CINXE.COM

Attachment 9002232 Details for Bug 1454764 – Format mozilla-central with rustfmt 1.0 RC. v1

<!doctype html> <html lang="en"> <head> <base href="https://bugzilla.mozilla.org/attachment.cgi?id=9002232&amp;action=edit"> <meta charset="UTF-8"> <meta property="og:type" content="website"> <meta property="og:title" content=" Attachment 9002232 Details for Bug 1454764 – Format mozilla-central with rustfmt 1.0 RC. v1"> <meta name="viewport" content="width=1024"> <meta name="color-scheme" content="dark light"> <meta name="generator" content="Bugzilla 20241126.1"> <meta name="bugzilla-global" content="dummy" id="bugzilla-global" data-bugzilla="{&quot;api_token&quot;:&quot;&quot;,&quot;config&quot;:{&quot;basepath&quot;:&quot;\/&quot;},&quot;constant&quot;:{&quot;COMMENT_COLS&quot;:80},&quot;param&quot;:{&quot;maxattachmentsize&quot;:&quot;10240&quot;,&quot;maxusermatches&quot;:&quot;50&quot;,&quot;splinter_base&quot;:&quot;\/page.cgi?id=splinter.html&amp;ignore=\/&quot;,&quot;use_markdown&quot;:&quot;1&quot;},&quot;string&quot;:{&quot;TextEditor&quot;:{&quot;command_bold&quot;:&quot;Bold&quot;,&quot;command_bulleted_list&quot;:&quot;Bulleted list&quot;,&quot;command_code&quot;:&quot;Code&quot;,&quot;command_heading&quot;:&quot;Heading&quot;,&quot;command_italic&quot;:&quot;Italic&quot;,&quot;command_link&quot;:&quot;Link&quot;,&quot;command_numbered_list&quot;:&quot;Numbered list&quot;,&quot;command_quote&quot;:&quot;Quote&quot;,&quot;comment_editor&quot;:&quot;Comment Editor&quot;,&quot;edit&quot;:&quot;Edit&quot;,&quot;etiquette_link&quot;:{&quot;href&quot;:&quot;page.cgi?id=etiquette.html&quot;,&quot;text&quot;:&quot;Etiquette&quot;},&quot;guidelines_link&quot;:{&quot;href&quot;:&quot;page.cgi?id=bug-writing.html&quot;,&quot;text&quot;:&quot;Bug Writing Guidelines&quot;},&quot;loading&quot;:&quot;Loading…&quot;,&quot;markdown_link&quot;:{&quot;href&quot;:&quot;https:\/\/guides.github.com\/features\/mastering-markdown\/&quot;,&quot;text&quot;:&quot;Markdown supported&quot;},&quot;preview&quot;:&quot;Preview&quot;,&quot;preview_error&quot;:&quot;Preview could not be loaded. Please try again later.&quot;,&quot;text_editor&quot;:&quot;Text Editor&quot;,&quot;toolbar_label&quot;:&quot;Markdown text-formatting toolbar&quot;},&quot;bug&quot;:&quot;bug&quot;,&quot;bug_type_required&quot;:&quot;You must select a Type for this bug&quot;,&quot;component_required&quot;:&quot;You must select a Component for this bug&quot;,&quot;description_required&quot;:&quot;You must enter a Description for this bug&quot;,&quot;short_desc_required&quot;:&quot;You must enter a Summary for this bug&quot;,&quot;version_required&quot;:&quot;You must select a Version for this bug&quot;},&quot;user&quot;:{&quot;is_new&quot;:true,&quot;login&quot;:&quot;&quot;}}"> <meta name="google-site-verification" content="JYXIuR9cAlV7fLmglSrc_4UaJS6Wzh5Mdxiorqu5AQc"> <title> Attachment 9002232 Details for Bug 1454764 – Format mozilla-central with rustfmt 1.0 RC. v1</title> <link href="/static/v20241126.1/skins/standard/global.css" rel="stylesheet" type="text/css"> <link href="/static/v20241126.1/skins/standard/attachment.css" rel="stylesheet" type="text/css"> <link href="/static/v20241126.1/js/jquery/ui/jquery-ui-min.css" rel="stylesheet" type="text/css"> <link href="/static/v20241126.1/js/jquery/ui/jquery-ui-structure-min.css" rel="stylesheet" type="text/css"> <link href="/static/v20241126.1/js/jquery/ui/jquery-ui-theme-min.css" rel="stylesheet" type="text/css"> <link href="/static/v20241126.1/skins/lib/prism.css" rel="stylesheet" type="text/css"> <link href="/static/v20241126.1/extensions/Needinfo/web/styles/needinfo.css" rel="stylesheet" type="text/css"> <link href="/static/v20241126.1/extensions/Review/web/styles/badge.css" rel="stylesheet" type="text/css"> <link href="/static/v20241126.1/extensions/Review/web/styles/review.css" rel="stylesheet" type="text/css"> <link href="/static/v20241126.1/skins/standard/text-editor.css" rel="stylesheet" type="text/css"> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/js/jquery/jquery-min.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/js/jquery/ui/jquery-ui-min.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/js/jquery/plugins/devbridgeAutocomplete/devbridgeAutocomplete-min.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/js/global.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/js/util.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/js/widgets.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH">BUGZILLA.value_descs = JSON.parse('{\"bug_status\":{},\"resolution\":{\"\":\"---\"}}'); review_suggestions = { _mentors: [ ], 'Lint and Formatting': [ ], _end: 1 }; static_component = 'Lint and Formatting'; </script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/js/text-editor.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/js/attachment.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/js/field.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/js/lib/prism.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/extensions/GoogleAnalytics/web/js/analytics.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/js/lib/md5.min.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/extensions/Review/web/js/badge.js"></script> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/extensions/Review/web/js/review.js"></script> <link href="/static/v20241126.1/skins/lib/fontawesome.min.css" rel="stylesheet" type="text/css"> <link href="/static/v20241126.1/skins/lib/fontawesome-brands.min.css" rel="stylesheet" type="text/css"> <link href="/static/v20241126.1/skins/lib/fontawesome-solid.min.css" rel="stylesheet" type="text/css"> <link rel="search" type="application/opensearchdescription+xml" title="Bugzilla@Mozilla" href="/search_plugin.cgi"> <link rel="shortcut icon" href="/extensions/BMO/web/images/favicon.ico"> <meta name="google-analytics" content="UA-36116321-3" data-location="https://bugzilla.mozilla.org/attachment/edit" data-title="Attachment 9002232 Details for Bug 1454764 &amp;ndash; Format mozilla-central with rustfmt 1.0 RC. v1"> <script async src="https://www.google-analytics.com/analytics.js"></script> <meta name="robots" content="noarchive"> <meta http-equiv="X-Translated-By" content="Google"> <meta http-equiv="X-Translated-To" content="iw"> <script type="text/javascript" src="https://www.gstatic.com/_/translate_http/_/js/k=translate_http.tr.en_GB.omlEigW4xY8.O/am=DgY/d=1/rs=AN8SPfpjsL9kUWY0h-sp7Ilu7hZWGwEmeg/m=corsproxy" data-sourceurl="https://bugzilla.mozilla.org/attachment.cgi?id=9002232&amp;action=edit"></script> <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" rel="stylesheet"> <script type="text/javascript" src="https://www.gstatic.com/_/translate_http/_/js/k=translate_http.tr.en_GB.omlEigW4xY8.O/am=DgY/d=1/exm=corsproxy/ed=1/rs=AN8SPfpjsL9kUWY0h-sp7Ilu7hZWGwEmeg/m=phishing_protection" data-phishing-protection-enabled="false" data-forms-warning-enabled="true" data-source-url="https://bugzilla.mozilla.org/attachment.cgi?id=9002232&amp;action=edit"></script> <meta name="robots" content="none"> </head> <body class="bugzilla-mozilla-org skin-standard no_javascript"> <script type="text/javascript" src="https://www.gstatic.com/_/translate_http/_/js/k=translate_http.tr.en_GB.omlEigW4xY8.O/am=DgY/d=1/exm=corsproxy,phishing_protection/ed=1/rs=AN8SPfpjsL9kUWY0h-sp7Ilu7hZWGwEmeg/m=navigationui" data-environment="prod" data-proxy-url="https://bugzilla-mozilla-org.translate.goog" data-proxy-full-url="https://bugzilla-mozilla-org.translate.goog/attachment.cgi?id=9002232&amp;action=edit&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB" data-source-url="https://bugzilla.mozilla.org/attachment.cgi?id=9002232&amp;action=edit" data-source-language="pl" data-target-language="iw" data-display-language="en-GB" data-detected-source-language="" data-is-source-untranslated="false" data-source-untranslated-url="https://translate.google.com/website?sl=pl&amp;tl=iw&amp;hl=en-GB&amp;u=https://bugzilla.mozilla.org/attachment.cgi?id%3D9002232%26action%3Dedit&amp;anno=2" data-client="tr"></script> <div id="wrapper"> <header id="header" role="banner" aria-label="Global Header"> <div class="inner" role="none"><button type="button" class="iconic ghost" id="open-menu-drawer" aria-label="Open Site Menu"> <span class="icon" aria-hidden="true" data-icon="menu"></span> </button> <div id="header-external-links" class="dropdown" role="none"><button type="button" id="header-external-menu-button" class="dropdown-button minor" aria-label="Show Mozilla Menu" aria-expanded="false" aria-haspopup="true" aria-controls="header-external-menu"> <img src="/static/v20241126.1/extensions/BMO/web/images/moz-fav-one-color-white-rgb.svg" width="32" height="32" alt=""> </button> <ul class="dropdown-content right" id="header-external-menu" role="menu" aria-label="Mozilla Menu" style="display:none;"> <li role="none"><a href="https://translate.google.com/website?sl=pl&amp;tl=iw&amp;hl=en-GB&amp;u=https://www.mozilla.org/" role="menuitem"> <span class="label" role="none">Mozilla Home</span> </a></li> <li role="separator"></li> <li role="none"><a href="https://translate.google.com/website?sl=pl&amp;tl=iw&amp;hl=en-GB&amp;u=https://www.mozilla.org/privacy/websites/" role="menuitem"> <span class="label" role="none">Privacy</span> </a></li> <li role="none"><a href="https://translate.google.com/website?sl=pl&amp;tl=iw&amp;hl=en-GB&amp;u=https://www.mozilla.org/privacy/websites/%23cookies" role="menuitem"> <span class="label" role="none">Cookies</span> </a></li> <li role="none"><a href="https://translate.google.com/website?sl=pl&amp;tl=iw&amp;hl=en-GB&amp;u=https://www.mozilla.org/about/legal/" role="menuitem"> <span class="label" role="none">Legal</span> </a></li> </ul> </div> <h1 id="header-title" class="title" role="none"><a class="header-button" href="https://bugzilla-mozilla-org.translate.goog/home?_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB" title="Go to home page"> <span aria-label="Go to Bugzilla Home Page">Bugzilla</span> </a></h1> <form id="header-search" class="quicksearch" action="/buglist.cgi" data-no-csrf role="search" aria-label="Search Bugs"><button type="button" class="iconic ghost" id="show-searchbox" aria-label="Search Bugs"> <span class="icon" aria-hidden="true" data-icon="search"></span> </button> <div class="searchbox-outer dropdown" role="combobox" aria-label="Quick Search" aria-haspopup="listbox" aria-owns="header-search-dropdown" aria-expanded="false"><span class="icon" aria-hidden="true" data-icon="search"></span> <input id="quicksearch_top" class="dropdown-button" name="quicksearch" autocomplete="off" value="" accesskey="s" placeholder="Search Bugs" title="Enter a bug number or some search terms" role="searchbox" aria-controls="header-search-dropdown" aria-label="Search Terms"> <div id="header-search-dropdown" class="dropdown-content dropdown-panel right" role="listbox" style="display: none;"> <div id="header-search-dropdown-wrapper" role="none"> <section id="header-search-dropdown-help" role="group" aria-label="Help"> <footer role="none"><a href="https://bugzilla-mozilla-org.translate.goog/page.cgi?id=quicksearch.html&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB">Quick Search Tips</a> <a href="https://bugzilla-mozilla-org.translate.goog/query.cgi?format=advanced&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB">Advanced Search</a> </footer> </section> </div> </div> </div> </form> <nav id="header-nav" role="menubar" aria-label="Site Links"> <ul class="links" role="none"> <li role="none"><a class="header-button" href="https://bugzilla-mozilla-org.translate.goog/describecomponents.cgi?_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB" title="Browse bugs by component" role="menuitem"> <span class="icon" aria-hidden="true" data-icon="category"></span> <span class="label" role="none">Browse</span> </a></li> <li role="none"><a class="header-button" href="https://bugzilla-mozilla-org.translate.goog/query.cgi?format=advanced&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB" title="Search bugs using various criteria" role="menuitem"> <span class="icon" aria-hidden="true" data-icon="pageview"></span> <span class="label" role="none">Advanced Search</span> </a></li> <li role="none"><a class="header-button" href="https://bugzilla-mozilla-org.translate.goog/enter_bug.cgi?_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB" title="File a new bug" role="menuitem"> <span class="icon" aria-hidden="true" data-icon="add_box"></span> <span class="label" role="none">New Bug</span> </a></li> </ul> <div class="dropdown" role="none"><button type="button" id="header-tools-menu-button" class="header-button dropdown-button minor" title="More tools…" role="menuitem" aria-label="Show More Tools Menu" aria-expanded="false" aria-haspopup="true" aria-controls="header-tools-menu"> <span class="icon" aria-hidden="true" data-icon="more_horiz"></span> </button> <ul class="dropdown-content left" id="header-tools-menu" role="menu" aria-label="More Tools Menu" style="display:none;"> <li role="none"><a href="https://bugzilla-mozilla-org.translate.goog/report.cgi?_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB" role="menuitem"> <span class="icon" aria-hidden="true" data-icon="analytics"></span> <span class="label" role="none">Reports</span> </a></li> <li role="separator"></li> <li role="none"><a href="https://translate.google.com/website?sl=pl&amp;tl=iw&amp;hl=en-GB&amp;u=https://bmo.readthedocs.io/en/latest/" target="_blank" role="menuitem"> <span class="icon" aria-hidden="true" data-icon="help"></span> <span class="label" role="none">Documentation</span> </a></li> </ul> </div> </nav> <ul id="header-login" class="links" role="none"> <li id="mini_login_container_top" role="none"><a id="login_link_top" href="https://bugzilla-mozilla-org.translate.goog/index.cgi?GoAheadAndLogIn=1&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB" class="show_mini_login_form header-button" data-qs-suffix="_top" role="button"> <span class="icon" aria-hidden="true" data-icon="login"></span> <span class="label" role="none">Log In</span> </a> <div id="mini_login_top" class="mini-popup mini_login bz_default_hidden"> <form method="post" action="/github.cgi"><input type="hidden" name="github_token" value="ExYOp1LwQkaSzG3LU5Y6M5SdHzE3GZ1ar1a1DYiGmithi2E2pMhPc2jVoV41865TDMWl6aoSXqfjW58ndgdqrf6nkDnpKCcXvCCiucseYBvu4x1XPjDYvP95S2YFwd0oCwvF7AZkHUQE8oCWtXbJTDgHqCy1SeitnvsvNGy4BQUDysnyNXrGXo9cZPsxpkRtQpiqWHPeBKO8tQarVc5ufsLjFFAtWHGByqe7L90hDROmXcYYHlRmf5aXxzxoA7m3"> <input type="hidden" name="target_uri" value="https://bugzilla.mozilla.org/attachment.cgi"> <button type="submit"> <i class="fab fa-github"></i> Log In with GitHub </button> </form> <div class="method-separator"> or </div> <form action="/attachment.cgi?id=9002232&amp;action=edit" method="POST" data-qs-suffix="_top"><input id="Bugzilla_login_top" class="bz_login" name="Bugzilla_login" title="Login" placeholder="Email" aria-label="Email" type="email" required> <input class="bz_password" id="Bugzilla_password_top" name="Bugzilla_password" type="password" title="Password" placeholder="Password" aria-label="Password" required> <input class="bz_password bz_default_hidden bz_mini_login_help" type="text" id="Bugzilla_password_dummy_top" value="password" title="Password"> <span class="remember-outer"> <input type="checkbox" id="Bugzilla_remember_top" name="Bugzilla_remember" value="on" class="bz_remember" checked> <label for="Bugzilla_remember_top">Remember me</label> </span> <input type="hidden" name="Bugzilla_login_token" value="1732794690-KBboSz8B6c8ifGe1tEZLbS24hTNsSM8tPVgWvaIk8TY"> <input type="submit" name="GoAheadAndLogIn" value="Log In" id="log_in_top" class="check_mini_login_fields" data-qs-suffix="_top"> <a href="https://bugzilla-mozilla-org.translate.goog/attachment.cgi?_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB#" id="hide_mini_login_top" aria-label="Close" class="close-button hide_mini_login_form" data-qs-suffix="_top"> <span class="icon" aria-hidden="true"></span> </a> </form> <div class="footer"><a href="https://bugzilla-mozilla-org.translate.goog/createaccount.cgi?_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB">Create an Account</a> · <a id="forgot_link_top" href="https://bugzilla-mozilla-org.translate.goog/index.cgi?GoAheadAndLogIn=1&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB#forgot" class="show_forgot_form" data-qs-suffix="_top">Forgot Password</a> </div> </div> <div id="forgot_form_top" class="mini-popup mini_forgot bz_default_hidden"> <form action="/token.cgi" method="post"><input type="email" name="loginname" size="20" placeholder="Email" aria-label="Email" required> <input id="forgot_button_top" value="Reset Password" type="submit"> <input type="hidden" name="a" value="reqpw"> <input type="hidden" id="token_top" name="token" value="1732794690-Z4fJ8KYk_yZdDbBCdCrPko40AzjAJBj29-65ZdIRQYM"> <a href="https://bugzilla-mozilla-org.translate.goog/attachment.cgi?_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB#" class="close-button hide_forgot_form" aria-label="Close" data-qs-suffix="_top"> <span class="icon" aria-hidden="true"></span> </a> </form> </div></li> </ul> </div><dialog id="menu-drawer" inert aria-label="Site Menu"> <div class="drawer-inner" role="none"> <div class="header" role="none"><button type="button" class="iconic ghost" id="close-menu-drawer" aria-label="Close Site Menu"> <span class="icon" aria-hidden="true" data-icon="close"></span> </button> </div> <ul role="menu" aria-label="Site Links"> <li role="none"><a class="header-button" href="https://bugzilla-mozilla-org.translate.goog/describecomponents.cgi?_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB" title="Browse bugs by component" role="menuitem"> <span class="icon" aria-hidden="true" data-icon="category"></span> <span class="label" role="none">Browse</span> </a></li> <li role="none"><a class="header-button" href="https://bugzilla-mozilla-org.translate.goog/query.cgi?format=advanced&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB" title="Search bugs using various criteria" role="menuitem"> <span class="icon" aria-hidden="true" data-icon="pageview"></span> <span class="label" role="none">Advanced Search</span> </a></li> <li role="none"><a class="header-button" href="https://bugzilla-mozilla-org.translate.goog/enter_bug.cgi?_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB" title="File a new bug" role="menuitem"> <span class="icon" aria-hidden="true" data-icon="add_box"></span> <span class="label" role="none">New Bug</span> </a></li> <li role="none"><a href="https://bugzilla-mozilla-org.translate.goog/report.cgi?_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB" role="menuitem"> <span class="icon" aria-hidden="true" data-icon="analytics"></span> <span class="label" role="none">Reports</span> </a></li> <li role="separator"></li> <li role="none"><a href="https://translate.google.com/website?sl=pl&amp;tl=iw&amp;hl=en-GB&amp;u=https://bmo.readthedocs.io/en/latest/" target="_blank" role="menuitem"> <span class="icon" aria-hidden="true" data-icon="help"></span> <span class="label" role="none">Documentation</span> </a></li> </ul> </div> </dialog> </header> <main id="bugzilla-body" tabindex="-1"> <aside id="message-container" role="complementary"> <noscript> <div class="noscript"> <div class="inner"> <p>Please enable JavaScript in your browser to use all the features on this site.</p> </div> </div> </noscript> </aside> <div id="main-inner"> <h2>Attachment 9002232 Details for <a class="bz_bug_link bz_status_REOPENED" title="REOPENED - [meta] rustfmt mozilla-central" href="https://bugzilla-mozilla-org.translate.goog/show_bug.cgi?id=1454764&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB">Bug 1454764</a></h2> <form method="post" action="/attachment.cgi" onsubmit="normalizeComments();"><input type="hidden" name="bugid" value="1454764"> <input type="hidden" name="id" value="9002232"> <input type="hidden" name="action" value="update"> <input type="hidden" name="contenttypemethod" value="manual"> <input type="hidden" name="delta_ts" value="2020-04-25 09:38:03"> <div id="attachment_info" class="attachment_info read"> <div id="attachment_attributes"> <div id="attachment_information_read_only" class=""> <div class="title"> [patch] <span class="bz_obsolete" title="obsolete">Format mozilla-central with rustfmt 1.0 RC. v1 </span> </div> <div class="details"> Bug-1454764---Format-mozilla-central-with-rustfmt-.patch (text/plain), 2.33 MB, created by <span class="vcard vcard_313730"><span class="fn">Bobby Holley (:bholley)</span> </span> </div> </div> <div id="attachment_information_edit"><span class="bz_hide"> (<a href="javascript:toggle_attachment_details_visibility();?_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB">hide</a>) </span> <div id="attachment_description"><label for="description">Description:</label>&nbsp;<textarea name="description" id="description" class="block bz_hidden_option" wrap="soft" rows="3" cols="25">Format mozilla-central with rustfmt 1.0 RC. v1</textarea> </div> <div id="attachment_filename"><label for="filename">Filename:</label> <input type="text" size="20" class="text block bz_hidden_option" id="filename" name="filename" value="Bug-1454764---Format-mozilla-central-with-rustfmt-.patch"> </div> <div id="attachment_mimetype"><label for="contenttypeentry">MIME Type:</label> <input type="text" size="20" class="text block bz_hidden_option" id="contenttypeentry" name="contenttypeentry" value="text/plain"> </div> <div id="attachment_creator"><span class="label">Creator:</span> <span class="vcard vcard_313730"><span class="fn">Bobby Holley (:bholley)</span> </span> </div> <div id="attachment_size"><span class="label">Size:</span> 2.33 MB </div> <div id="attachment_ispatch"><input type="checkbox" id="ispatch" name="ispatch" value="1" checked> <label for="ispatch">patch</label> </div> <div class="readonly"> <div class="checkboxes"> <div id="attachment_isobsolete"><input type="checkbox" id="isobsolete" name="isobsolete" value="1" checked> <label for="isobsolete">obsolete</label> </div> </div> </div> </div> <div id="attachment_view_window"> <div><input type="hidden" name="markdown_off" value="0"><textarea name="comment" id="editFrame" class="bz_default_hidden" wrap="soft" disabled rows="10" cols="80">&gt;# HG changeset patch &gt;# User Bobby Holley &lt;bobbyholley@gmail.com&gt; &gt; &gt;Bug 1454764 - Format mozilla-central with rustfmt 1.0 RC. v1 &gt; &gt;`cargo +nightly fmt --version` =&gt; rustfmt 0.99.2-nightly (5c9a2b6c 2018-08-07) &gt; &gt;Command: &gt; &gt;cargo +nightly fmt; pushd servo/components; for file in *; do pushd $file; cargo +nightly fmt; popd; done; popd; &gt; &gt;This currently excludes geckolib because of [1]. It also excludes webrender because that's effectively vendored code (we should format upstream at some point down the line). &gt; &gt;[1] https://github.com/rust-lang-nursery/rustfmt/issues/2936 &gt; &gt;MozReview-Commit-ID: CRdDMOGExMQ &gt; &gt;diff --git a/dom/media/gtest/hello.rs b/dom/media/gtest/hello.rs &gt;index cd111882ae87..af1308eee6c0 100644 &gt;--- a/dom/media/gtest/hello.rs &gt;+++ b/dom/media/gtest/hello.rs &gt;@@ -1,6 +1,6 @@ &gt; #[no_mangle] &gt;-pub extern fn test_rust() -&gt; *const u8 { &gt;+pub extern "C" fn test_rust() -&gt; *const u8 { &gt; // NB: rust &amp;str aren't null terminated. &gt; let greeting = "hello from rust.\0"; &gt; greeting.as_ptr() &gt; } &gt;diff --git a/intl/encoding_glue/src/lib.rs b/intl/encoding_glue/src/lib.rs &gt;index 66b627261cb9..4c35ec6ec4f2 100644 &gt;--- a/intl/encoding_glue/src/lib.rs &gt;+++ b/intl/encoding_glue/src/lib.rs &gt;@@ -26,93 +26,118 @@ const NS_CSTRING_OVERHEAD: usize = 9; &gt; &gt; /// Takes `Option&lt;usize&gt;`, the destination string and a value &gt; /// to return on failure and tries to set the length of the &gt; /// destination string to the `usize` wrapped in the first &gt; /// argument. &gt; macro_rules! try_dst_set_len { &gt; ($needed:expr, &gt; $dst:ident, &gt;- $ret:expr) =&gt; ( &gt;- let needed = match $needed { &gt;- Some(max) =&gt; { &gt;- // XPCOM strings use uint32_t for length. &gt;- if max &gt; ::std::u32::MAX as usize { &gt;+ $ret:expr) =&gt; { &gt;+ let needed = match $needed { &gt;+ Some(max) =&gt; { &gt;+ // XPCOM strings use uint32_t for length. &gt;+ if max &gt; ::std::u32::MAX as usize { &gt;+ return $ret; &gt;+ } &gt;+ max as u32 &gt;+ } &gt;+ None =&gt; { &gt;+ return $ret; &gt;+ } &gt;+ }; &gt;+ unsafe { &gt;+ if $dst.fallible_set_length(needed).is_err() { &gt; return $ret; &gt; } &gt;- max as u32 &gt;- } &gt;- None =&gt; { &gt;- return $ret; &gt; } &gt; }; &gt;- unsafe { &gt;- if $dst.fallible_set_length(needed).is_err() { &gt;- return $ret; &gt;- } &gt;- } &gt;- ) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring(encoding: *mut *const Encoding, &gt;- src: *const u8, &gt;- src_len: usize, &gt;- dst: *mut nsAString) &gt;- -&gt; nsresult { &gt;+pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring( &gt;+ encoding: *mut *const Encoding, &gt;+ src: *const u8, &gt;+ src_len: usize, &gt;+ dst: *mut nsAString, &gt;+) -&gt; nsresult { &gt; let (rv, enc) = decode_to_nsstring(&amp;**encoding, slice::from_raw_parts(src, src_len), &amp;mut *dst); &gt; *encoding = enc as *const Encoding; &gt; rv &gt; } &gt; &gt;-pub fn decode_to_nsstring(encoding: &amp;'static Encoding, &gt;- src: &amp;[u8], &gt;- dst: &amp;mut nsAString) &gt;- -&gt; (nsresult, &amp;'static Encoding) { &gt;+pub fn decode_to_nsstring( &gt;+ encoding: &amp;'static Encoding, &gt;+ src: &amp;[u8], &gt;+ dst: &amp;mut nsAString, &gt;+) -&gt; (nsresult, &amp;'static Encoding) { &gt; if let Some((enc, bom_length)) = Encoding::for_bom(src) { &gt;- return (decode_to_nsstring_without_bom_handling(enc, &amp;src[bom_length..], dst), enc); &gt;+ return ( &gt;+ decode_to_nsstring_without_bom_handling(enc, &amp;src[bom_length..], dst), &gt;+ enc, &gt;+ ); &gt; } &gt;- (decode_to_nsstring_without_bom_handling(encoding, src, dst), encoding) &gt;+ ( &gt;+ decode_to_nsstring_without_bom_handling(encoding, src, dst), &gt;+ encoding, &gt;+ ) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring_with_bom_removal(encoding: *const Encoding, src: *const u8, src_len: usize, dst: *mut nsAString) -&gt; nsresult{ &gt;+pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring_with_bom_removal( &gt;+ encoding: *const Encoding, &gt;+ src: *const u8, &gt;+ src_len: usize, &gt;+ dst: *mut nsAString, &gt;+) -&gt; nsresult { &gt; decode_to_nsstring_with_bom_removal(&amp;*encoding, slice::from_raw_parts(src, src_len), &amp;mut *dst) &gt; } &gt; &gt;-pub fn decode_to_nsstring_with_bom_removal(encoding: &amp;'static Encoding, &gt;- src: &amp;[u8], &gt;- dst: &amp;mut nsAString) &gt;- -&gt; nsresult { &gt;+pub fn decode_to_nsstring_with_bom_removal( &gt;+ encoding: &amp;'static Encoding, &gt;+ src: &amp;[u8], &gt;+ dst: &amp;mut nsAString, &gt;+) -&gt; nsresult { &gt; let without_bom = if encoding == UTF_8 &amp;&amp; src.starts_with(b"\xEF\xBB\xBF") { &gt; &amp;src[3..] &gt;- } else if (encoding == UTF_16LE &amp;&amp; src.starts_with(b"\xFF\xFE")) || &gt;- (encoding == UTF_16BE &amp;&amp; src.starts_with(b"\xFE\xFF")) { &gt;+ } else if (encoding == UTF_16LE &amp;&amp; src.starts_with(b"\xFF\xFE")) &gt;+ || (encoding == UTF_16BE &amp;&amp; src.starts_with(b"\xFE\xFF")) &gt;+ { &gt; &amp;src[2..] &gt; } else { &gt; src &gt; }; &gt; decode_to_nsstring_without_bom_handling(encoding, without_bom, dst) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring_without_bom_handling(encoding: *const Encoding, src: *const u8, src_len: usize, dst: *mut nsAString) -&gt; nsresult{ &gt;- decode_to_nsstring_without_bom_handling(&amp;*encoding, &gt;- slice::from_raw_parts(src, src_len), &gt;- &amp;mut *dst) &gt;+pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring_without_bom_handling( &gt;+ encoding: *const Encoding, &gt;+ src: *const u8, &gt;+ src_len: usize, &gt;+ dst: *mut nsAString, &gt;+) -&gt; nsresult { &gt;+ decode_to_nsstring_without_bom_handling( &gt;+ &amp;*encoding, &gt;+ slice::from_raw_parts(src, src_len), &gt;+ &amp;mut *dst, &gt;+ ) &gt; } &gt; &gt;-pub fn decode_to_nsstring_without_bom_handling(encoding: &amp;'static Encoding, &gt;- src: &amp;[u8], &gt;- dst: &amp;mut nsAString) &gt;- -&gt; nsresult { &gt;+pub fn decode_to_nsstring_without_bom_handling( &gt;+ encoding: &amp;'static Encoding, &gt;+ src: &amp;[u8], &gt;+ dst: &amp;mut nsAString, &gt;+) -&gt; nsresult { &gt; let mut decoder = encoding.new_decoder_without_bom_handling(); &gt;- try_dst_set_len!(decoder.max_utf16_buffer_length(src.len()), &gt;- dst, &gt;- NS_ERROR_OUT_OF_MEMORY); &gt;+ try_dst_set_len!( &gt;+ decoder.max_utf16_buffer_length(src.len()), &gt;+ dst, &gt;+ NS_ERROR_OUT_OF_MEMORY &gt;+ ); &gt; // to_mut() shouldn't fail right after setting length. &gt; let (result, read, written, had_errors) = decoder.decode_to_utf16(src, dst.to_mut(), true); &gt; debug_assert_eq!(result, CoderResult::InputEmpty); &gt; debug_assert_eq!(read, src.len()); &gt; debug_assert!(written &lt;= dst.len()); &gt; unsafe { &gt; if dst.fallible_set_length(written as u32).is_err() { &gt; return NS_ERROR_OUT_OF_MEMORY; &gt;@@ -120,36 +145,43 @@ pub fn decode_to_nsstring_without_bom_handling(encoding: &amp;'static Encoding, &gt; } &gt; if had_errors { &gt; return NS_OK_HAD_REPLACEMENTS; &gt; } &gt; NS_OK &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring_without_bom_handling_and_without_replacement &gt;- (encoding: *const Encoding, &gt;- src: *const u8, &gt;- src_len: usize, &gt;- dst: *mut nsAString) &gt;- -&gt; nsresult { &gt;- decode_to_nsstring_without_bom_handling_and_without_replacement(&amp;*encoding, &gt;- slice::from_raw_parts(src, &gt;- src_len), &gt;- &amp;mut *dst) &gt;+pub unsafe extern "C" fn mozilla_encoding_decode_to_nsstring_without_bom_handling_and_without_replacement( &gt;+ encoding: *const Encoding, &gt;+ src: *const u8, &gt;+ src_len: usize, &gt;+ dst: *mut nsAString, &gt;+) -&gt; nsresult { &gt;+ decode_to_nsstring_without_bom_handling_and_without_replacement( &gt;+ &amp;*encoding, &gt;+ slice::from_raw_parts(src, src_len), &gt;+ &amp;mut *dst, &gt;+ ) &gt; } &gt; &gt;-pub fn decode_to_nsstring_without_bom_handling_and_without_replacement(encoding: &amp;'static Encoding, src: &amp;[u8], dst: &amp;mut nsAString) -&gt; nsresult{ &gt;+pub fn decode_to_nsstring_without_bom_handling_and_without_replacement( &gt;+ encoding: &amp;'static Encoding, &gt;+ src: &amp;[u8], &gt;+ dst: &amp;mut nsAString, &gt;+) -&gt; nsresult { &gt; let mut decoder = encoding.new_decoder_without_bom_handling(); &gt;- try_dst_set_len!(decoder.max_utf16_buffer_length(src.len()), &gt;- dst, &gt;- NS_ERROR_OUT_OF_MEMORY); &gt;+ try_dst_set_len!( &gt;+ decoder.max_utf16_buffer_length(src.len()), &gt;+ dst, &gt;+ NS_ERROR_OUT_OF_MEMORY &gt;+ ); &gt; // to_mut() shouldn't fail right after setting length. &gt;- let (result, read, written) = decoder &gt;- .decode_to_utf16_without_replacement(src, dst.to_mut(), true); &gt;+ let (result, read, written) = &gt;+ decoder.decode_to_utf16_without_replacement(src, dst.to_mut(), true); &gt; match result { &gt; DecoderResult::InputEmpty =&gt; { &gt; debug_assert_eq!(read, src.len()); &gt; debug_assert!(written &lt;= dst.len()); &gt; unsafe { &gt; if dst.fallible_set_length(written as u32).is_err() { &gt; return NS_ERROR_OUT_OF_MEMORY; &gt; } &gt;@@ -160,44 +192,49 @@ pub fn decode_to_nsstring_without_bom_handling_and_without_replacement(encoding: &gt; dst.truncate(); &gt; NS_ERROR_UDEC_ILLEGALINPUT &gt; } &gt; DecoderResult::OutputFull =&gt; unreachable!(), &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn mozilla_encoding_encode_from_utf16(encoding: *mut *const Encoding, &gt;- src: *const u16, &gt;- src_len: usize, &gt;- dst: *mut nsACString) &gt;- -&gt; nsresult { &gt;+pub unsafe extern "C" fn mozilla_encoding_encode_from_utf16( &gt;+ encoding: *mut *const Encoding, &gt;+ src: *const u16, &gt;+ src_len: usize, &gt;+ dst: *mut nsACString, &gt;+) -&gt; nsresult { &gt; let (rv, enc) = encode_from_utf16(&amp;**encoding, slice::from_raw_parts(src, src_len), &amp;mut *dst); &gt; *encoding = enc as *const Encoding; &gt; rv &gt; } &gt; &gt;-pub fn encode_from_utf16(encoding: &amp;'static Encoding, &gt;- src: &amp;[u16], &gt;- dst: &amp;mut nsACString) &gt;- -&gt; (nsresult, &amp;'static Encoding) { &gt;+pub fn encode_from_utf16( &gt;+ encoding: &amp;'static Encoding, &gt;+ src: &amp;[u16], &gt;+ dst: &amp;mut nsACString, &gt;+) -&gt; (nsresult, &amp;'static Encoding) { &gt; let output_encoding = encoding.output_encoding(); &gt; let mut encoder = output_encoding.new_encoder(); &gt;- try_dst_set_len!(encoder.max_buffer_length_from_utf16_if_no_unmappables(src.len()), &gt;- dst, &gt;- (NS_ERROR_OUT_OF_MEMORY, output_encoding)); &gt;+ try_dst_set_len!( &gt;+ encoder.max_buffer_length_from_utf16_if_no_unmappables(src.len()), &gt;+ dst, &gt;+ (NS_ERROR_OUT_OF_MEMORY, output_encoding) &gt;+ ); &gt; &gt; let mut total_read = 0; &gt; let mut total_written = 0; &gt; let mut total_had_errors = false; &gt; loop { &gt;- let (result, read, written, had_errors) = encoder &gt;- .encode_from_utf16(&amp;src[total_read..], &gt;- &amp;mut (dst.to_mut())[total_written..], &gt;- true); &gt;+ let (result, read, written, had_errors) = encoder.encode_from_utf16( &gt;+ &amp;src[total_read..], &gt;+ &amp;mut (dst.to_mut())[total_written..], &gt;+ true, &gt;+ ); &gt; total_read += read; &gt; total_written += written; &gt; total_had_errors |= had_errors; &gt; match result { &gt; CoderResult::InputEmpty =&gt; { &gt; debug_assert_eq!(total_read, src.len()); &gt; debug_assert!(total_written &lt;= dst.len()); &gt; unsafe { &gt;@@ -206,20 +243,20 @@ pub fn encode_from_utf16(encoding: &amp;'static Encoding, &gt; } &gt; } &gt; if total_had_errors { &gt; return (NS_OK_HAD_REPLACEMENTS, output_encoding); &gt; } &gt; return (NS_OK, output_encoding); &gt; } &gt; CoderResult::OutputFull =&gt; { &gt;- if let Some(needed) = &gt;- checked_add(total_written, &gt;- encoder.max_buffer_length_from_utf16_if_no_unmappables(src.len() - &gt;- total_read)) { &gt;+ if let Some(needed) = checked_add( &gt;+ total_written, &gt;+ encoder.max_buffer_length_from_utf16_if_no_unmappables(src.len() - total_read), &gt;+ ) { &gt; // Let's round the allocation up in order to avoid repeated &gt; // allocations. Using power-of-two as the approximation of &gt; // available jemalloc buckets, since linking with &gt; // malloc_good_size is messy. &gt; if let Some(with_bookkeeping) = NS_CSTRING_OVERHEAD.checked_add(needed) { &gt; let rounded = with_bookkeeping.next_power_of_two(); &gt; let unclowned = rounded - NS_CSTRING_OVERHEAD; &gt; // XPCOM strings use uint32_t for length. &gt;@@ -234,71 +271,86 @@ pub fn encode_from_utf16(encoding: &amp;'static Encoding, &gt; } &gt; return (NS_ERROR_OUT_OF_MEMORY, output_encoding); &gt; } &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring(encoding: *mut *const Encoding, &gt;- src: *const nsACString, &gt;- dst: *mut nsACString) &gt;- -&gt; nsresult { &gt;+pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring( &gt;+ encoding: *mut *const Encoding, &gt;+ src: *const nsACString, &gt;+ dst: *mut nsACString, &gt;+) -&gt; nsresult { &gt; debug_assert_ne!(src as usize, dst as usize); &gt; let (rv, enc) = decode_to_nscstring(&amp;**encoding, &amp;*src, &amp;mut *dst); &gt; *encoding = enc as *const Encoding; &gt; rv &gt; } &gt; &gt;-pub fn decode_to_nscstring(encoding: &amp;'static Encoding, &gt;- src: &amp;nsACString, &gt;- dst: &amp;mut nsACString) &gt;- -&gt; (nsresult, &amp;'static Encoding) { &gt;+pub fn decode_to_nscstring( &gt;+ encoding: &amp;'static Encoding, &gt;+ src: &amp;nsACString, &gt;+ dst: &amp;mut nsACString, &gt;+) -&gt; (nsresult, &amp;'static Encoding) { &gt; if let Some((enc, bom_length)) = Encoding::for_bom(src) { &gt;- return (decode_from_slice_to_nscstring_without_bom_handling(enc, &gt;- &amp;src[bom_length..], &gt;- dst, &gt;- 0), &gt;- enc); &gt;+ return ( &gt;+ decode_from_slice_to_nscstring_without_bom_handling(enc, &amp;src[bom_length..], dst, 0), &gt;+ enc, &gt;+ ); &gt; } &gt;- (decode_to_nscstring_without_bom_handling(encoding, src, dst), encoding) &gt;+ ( &gt;+ decode_to_nscstring_without_bom_handling(encoding, src, dst), &gt;+ encoding, &gt;+ ) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring_with_bom_removal(encoding: *const Encoding, src: *const nsACString, dst: *mut nsACString) -&gt; nsresult{ &gt;+pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring_with_bom_removal( &gt;+ encoding: *const Encoding, &gt;+ src: *const nsACString, &gt;+ dst: *mut nsACString, &gt;+) -&gt; nsresult { &gt; debug_assert_ne!(src as usize, dst as usize); &gt; decode_to_nscstring_with_bom_removal(&amp;*encoding, &amp;*src, &amp;mut *dst) &gt; } &gt; &gt;-pub fn decode_to_nscstring_with_bom_removal(encoding: &amp;'static Encoding, &gt;- src: &amp;nsACString, &gt;- dst: &amp;mut nsACString) &gt;- -&gt; nsresult { &gt;+pub fn decode_to_nscstring_with_bom_removal( &gt;+ encoding: &amp;'static Encoding, &gt;+ src: &amp;nsACString, &gt;+ dst: &amp;mut nsACString, &gt;+) -&gt; nsresult { &gt; let without_bom = if encoding == UTF_8 &amp;&amp; src.starts_with(b"\xEF\xBB\xBF") { &gt; &amp;src[3..] &gt;- } else if (encoding == UTF_16LE &amp;&amp; src.starts_with(b"\xFF\xFE")) || &gt;- (encoding == UTF_16BE &amp;&amp; src.starts_with(b"\xFE\xFF")) { &gt;+ } else if (encoding == UTF_16LE &amp;&amp; src.starts_with(b"\xFF\xFE")) &gt;+ || (encoding == UTF_16BE &amp;&amp; src.starts_with(b"\xFE\xFF")) &gt;+ { &gt; &amp;src[2..] &gt; } else { &gt; return decode_to_nscstring_without_bom_handling(encoding, src, dst); &gt; }; &gt; decode_from_slice_to_nscstring_without_bom_handling(encoding, without_bom, dst, 0) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring_without_bom_handling(encoding: *const Encoding, src: *const nsACString, dst: *mut nsACString) -&gt; nsresult{ &gt;+pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring_without_bom_handling( &gt;+ encoding: *const Encoding, &gt;+ src: *const nsACString, &gt;+ dst: *mut nsACString, &gt;+) -&gt; nsresult { &gt; debug_assert_ne!(src as usize, dst as usize); &gt; decode_to_nscstring_without_bom_handling(&amp;*encoding, &amp;*src, &amp;mut *dst) &gt; } &gt; &gt;-pub fn decode_to_nscstring_without_bom_handling(encoding: &amp;'static Encoding, &gt;- src: &amp;nsACString, &gt;- dst: &amp;mut nsACString) &gt;- -&gt; nsresult { &gt;+pub fn decode_to_nscstring_without_bom_handling( &gt;+ encoding: &amp;'static Encoding, &gt;+ src: &amp;nsACString, &gt;+ dst: &amp;mut nsACString, &gt;+) -&gt; nsresult { &gt; let bytes = &amp;src[..]; &gt; let valid_up_to = if encoding == UTF_8 { &gt; Encoding::utf8_valid_up_to(bytes) &gt; } else if encoding.is_ascii_compatible() { &gt; Encoding::ascii_valid_up_to(bytes) &gt; } else if encoding == ISO_2022_JP { &gt; Encoding::iso_2022_jp_ascii_valid_up_to(bytes) &gt; } else { &gt;@@ -309,49 +361,67 @@ pub fn decode_to_nscstring_without_bom_handling(encoding: &amp;'static Encoding, &gt; return NS_ERROR_OUT_OF_MEMORY; &gt; } &gt; return NS_OK; &gt; } &gt; decode_from_slice_to_nscstring_without_bom_handling(encoding, src, dst, valid_up_to) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn mozilla_encoding_decode_from_slice_to_nscstring_without_bom_handling(encoding: *const Encoding, src: *const u8, src_len: usize, dst: *mut nsACString, already_validated: usize) -&gt; nsresult { &gt;- decode_from_slice_to_nscstring_without_bom_handling(&amp;*encoding, slice::from_raw_parts(src, src_len), &amp;mut *dst, already_validated) &gt;+pub unsafe extern "C" fn mozilla_encoding_decode_from_slice_to_nscstring_without_bom_handling( &gt;+ encoding: *const Encoding, &gt;+ src: *const u8, &gt;+ src_len: usize, &gt;+ dst: *mut nsACString, &gt;+ already_validated: usize, &gt;+) -&gt; nsresult { &gt;+ decode_from_slice_to_nscstring_without_bom_handling( &gt;+ &amp;*encoding, &gt;+ slice::from_raw_parts(src, src_len), &gt;+ &amp;mut *dst, &gt;+ already_validated, &gt;+ ) &gt; } &gt; &gt;-fn decode_from_slice_to_nscstring_without_bom_handling(encoding: &amp;'static Encoding, &gt;- src: &amp;[u8], &gt;- dst: &amp;mut nsACString, &gt;- already_validated: usize) &gt;- -&gt; nsresult { &gt;+fn decode_from_slice_to_nscstring_without_bom_handling( &gt;+ encoding: &amp;'static Encoding, &gt;+ src: &amp;[u8], &gt;+ dst: &amp;mut nsACString, &gt;+ already_validated: usize, &gt;+) -&gt; nsresult { &gt; let bytes = src; &gt; let mut decoder = encoding.new_decoder_without_bom_handling(); &gt;- let rounded_without_replacement = &gt;- checked_next_power_of_two(checked_add(already_validated, decoder.max_utf8_buffer_length_without_replacement(bytes.len() - already_validated))); &gt;- let with_replacement = checked_add(already_validated, &gt;- decoder.max_utf8_buffer_length(bytes.len() - &gt;- already_validated)); &gt;- try_dst_set_len!(checked_min(rounded_without_replacement, with_replacement), &gt;- dst, &gt;- NS_ERROR_OUT_OF_MEMORY); &gt;+ let rounded_without_replacement = checked_next_power_of_two(checked_add( &gt;+ already_validated, &gt;+ decoder.max_utf8_buffer_length_without_replacement(bytes.len() - already_validated), &gt;+ )); &gt;+ let with_replacement = checked_add( &gt;+ already_validated, &gt;+ decoder.max_utf8_buffer_length(bytes.len() - already_validated), &gt;+ ); &gt;+ try_dst_set_len!( &gt;+ checked_min(rounded_without_replacement, with_replacement), &gt;+ dst, &gt;+ NS_ERROR_OUT_OF_MEMORY &gt;+ ); &gt; &gt; if already_validated != 0 { &gt; // to_mut() shouldn't fail right after setting length. &gt; &amp;mut (dst.to_mut())[..already_validated].copy_from_slice(&amp;bytes[..already_validated]); &gt; } &gt; let mut total_read = already_validated; &gt; let mut total_written = already_validated; &gt; let mut total_had_errors = false; &gt; loop { &gt; // to_mut() shouldn't fail right after setting length. &gt;- let (result, read, written, had_errors) = &gt;- decoder.decode_to_utf8(&amp;bytes[total_read..], &gt;- &amp;mut (dst.to_mut())[total_written..], &gt;- true); &gt;+ let (result, read, written, had_errors) = decoder.decode_to_utf8( &gt;+ &amp;bytes[total_read..], &gt;+ &amp;mut (dst.to_mut())[total_written..], &gt;+ true, &gt;+ ); &gt; total_read += read; &gt; total_written += written; &gt; total_had_errors |= had_errors; &gt; match result { &gt; CoderResult::InputEmpty =&gt; { &gt; debug_assert_eq!(total_read, bytes.len()); &gt; unsafe { &gt; if dst.fallible_set_length(total_written as u32).is_err() { &gt;@@ -361,37 +431,44 @@ fn decode_from_slice_to_nscstring_without_bom_handling(encoding: &amp;'static Encodi &gt; if total_had_errors { &gt; return NS_OK_HAD_REPLACEMENTS; &gt; } &gt; return NS_OK; &gt; } &gt; CoderResult::OutputFull =&gt; { &gt; // Allocate for the worst case. That is, we should come &gt; // here at most once per invocation of this method. &gt;- try_dst_set_len!(checked_add(total_written, &gt;- decoder.max_utf8_buffer_length(bytes.len() - &gt;- total_read)), &gt;- dst, &gt;- NS_ERROR_OUT_OF_MEMORY); &gt;+ try_dst_set_len!( &gt;+ checked_add( &gt;+ total_written, &gt;+ decoder.max_utf8_buffer_length(bytes.len() - total_read) &gt;+ ), &gt;+ dst, &gt;+ NS_ERROR_OUT_OF_MEMORY &gt;+ ); &gt; continue; &gt; } &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring_without_bom_handling_and_without_replacement &gt;- (encoding: *const Encoding, &gt;- src: *const nsACString, &gt;- dst: *mut nsACString) &gt;- -&gt; nsresult { &gt;+pub unsafe extern "C" fn mozilla_encoding_decode_to_nscstring_without_bom_handling_and_without_replacement( &gt;+ encoding: *const Encoding, &gt;+ src: *const nsACString, &gt;+ dst: *mut nsACString, &gt;+) -&gt; nsresult { &gt; decode_to_nscstring_without_bom_handling_and_without_replacement(&amp;*encoding, &amp;*src, &amp;mut *dst) &gt; } &gt; &gt;-pub fn decode_to_nscstring_without_bom_handling_and_without_replacement(encoding: &amp;'static Encoding, src: &amp;nsACString, dst: &amp;mut nsACString) -&gt; nsresult{ &gt;+pub fn decode_to_nscstring_without_bom_handling_and_without_replacement( &gt;+ encoding: &amp;'static Encoding, &gt;+ src: &amp;nsACString, &gt;+ dst: &amp;mut nsACString, &gt;+) -&gt; nsresult { &gt; let bytes = &amp;src[..]; &gt; if encoding == UTF_8 { &gt; let valid_up_to = Encoding::utf8_valid_up_to(bytes); &gt; if valid_up_to == bytes.len() { &gt; if dst.fallible_assign(src).is_err() { &gt; return NS_ERROR_OUT_OF_MEMORY; &gt; } &gt; return NS_OK; &gt;@@ -407,62 +484,72 @@ pub fn decode_to_nscstring_without_bom_handling_and_without_replacement(encoding &gt; }; &gt; if valid_up_to == bytes.len() { &gt; if dst.fallible_assign(src).is_err() { &gt; return NS_ERROR_OUT_OF_MEMORY; &gt; } &gt; return NS_OK; &gt; } &gt; let mut decoder = encoding.new_decoder_without_bom_handling(); &gt;- try_dst_set_len!(checked_add(valid_up_to, &gt;- decoder.max_utf8_buffer_length_without_replacement(bytes.len() - &gt;- valid_up_to)), &gt;- dst, &gt;- NS_ERROR_OUT_OF_MEMORY); &gt;+ try_dst_set_len!( &gt;+ checked_add( &gt;+ valid_up_to, &gt;+ decoder.max_utf8_buffer_length_without_replacement(bytes.len() - valid_up_to) &gt;+ ), &gt;+ dst, &gt;+ NS_ERROR_OUT_OF_MEMORY &gt;+ ); &gt; // to_mut() shouldn't fail right after setting length. &gt; let (result, read, written) = { &gt; let dest = dst.to_mut(); &gt; dest[..valid_up_to].copy_from_slice(&amp;bytes[..valid_up_to]); &gt;- decoder &gt;- .decode_to_utf8_without_replacement(&amp;src[valid_up_to..], &amp;mut dest[valid_up_to..], true) &gt;+ decoder.decode_to_utf8_without_replacement( &gt;+ &amp;src[valid_up_to..], &gt;+ &amp;mut dest[valid_up_to..], &gt;+ true, &gt;+ ) &gt; }; &gt; match result { &gt; DecoderResult::InputEmpty =&gt; { &gt; debug_assert_eq!(valid_up_to + read, src.len()); &gt; debug_assert!(valid_up_to + written &lt;= dst.len()); &gt; unsafe { &gt;- if dst.fallible_set_length((valid_up_to + written) as u32) &gt;- .is_err() { &gt;+ if dst &gt;+ .fallible_set_length((valid_up_to + written) as u32) &gt;+ .is_err() &gt;+ { &gt; return NS_ERROR_OUT_OF_MEMORY; &gt; } &gt; } &gt; NS_OK &gt; } &gt; DecoderResult::Malformed(_, _) =&gt; { &gt; dst.truncate(); &gt; NS_ERROR_UDEC_ILLEGALINPUT &gt; } &gt; DecoderResult::OutputFull =&gt; unreachable!(), &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn mozilla_encoding_encode_from_nscstring(encoding: *mut *const Encoding, &gt;- src: *const nsACString, &gt;- dst: *mut nsACString) &gt;- -&gt; nsresult { &gt;+pub unsafe extern "C" fn mozilla_encoding_encode_from_nscstring( &gt;+ encoding: *mut *const Encoding, &gt;+ src: *const nsACString, &gt;+ dst: *mut nsACString, &gt;+) -&gt; nsresult { &gt; let (rv, enc) = encode_from_nscstring(&amp;**encoding, &amp;*src, &amp;mut *dst); &gt; *encoding = enc as *const Encoding; &gt; rv &gt; } &gt; &gt;-pub fn encode_from_nscstring(encoding: &amp;'static Encoding, &gt;- src: &amp;nsACString, &gt;- dst: &amp;mut nsACString) &gt;- -&gt; (nsresult, &amp;'static Encoding) { &gt;+pub fn encode_from_nscstring( &gt;+ encoding: &amp;'static Encoding, &gt;+ src: &amp;nsACString, &gt;+ dst: &amp;mut nsACString, &gt;+) -&gt; (nsresult, &amp;'static Encoding) { &gt; let output_encoding = encoding.output_encoding(); &gt; let bytes = &amp;src[..]; &gt; if output_encoding == UTF_8 { &gt; let valid_up_to = Encoding::utf8_valid_up_to(bytes); &gt; if valid_up_to == bytes.len() { &gt; if dst.fallible_assign(src).is_err() { &gt; return (NS_ERROR_OUT_OF_MEMORY, output_encoding); &gt; } &gt;@@ -487,35 +574,42 @@ pub fn encode_from_nscstring(encoding: &amp;'static Encoding, &gt; // to avoid unsafe blocks. &gt; let trail = if let Ok(trail) = ::std::str::from_utf8(&amp;bytes[valid_up_to..]) { &gt; trail &gt; } else { &gt; return (NS_ERROR_UDEC_ILLEGALINPUT, output_encoding); &gt; }; &gt; &gt; let mut encoder = output_encoding.new_encoder(); &gt;- try_dst_set_len!(checked_add(valid_up_to, &gt;- encoder.max_buffer_length_from_utf8_if_no_unmappables(trail.len())), dst, (NS_ERROR_OUT_OF_MEMORY, output_encoding)); &gt;+ try_dst_set_len!( &gt;+ checked_add( &gt;+ valid_up_to, &gt;+ encoder.max_buffer_length_from_utf8_if_no_unmappables(trail.len()) &gt;+ ), &gt;+ dst, &gt;+ (NS_ERROR_OUT_OF_MEMORY, output_encoding) &gt;+ ); &gt; &gt; if valid_up_to != 0 { &gt; // to_mut() shouldn't fail right after setting length. &gt; &amp;mut (dst.to_mut())[..valid_up_to].copy_from_slice(&amp;bytes[..valid_up_to]); &gt; } &gt; &gt; // `total_read` tracks `trail` only but `total_written` tracks the overall situation! &gt; // This asymmetry is here, because trail is materialized as `str` without resorting &gt; // to unsafe code here. &gt; let mut total_read = 0; &gt; let mut total_written = valid_up_to; &gt; let mut total_had_errors = false; &gt; loop { &gt;- let (result, read, written, had_errors) = encoder &gt;- .encode_from_utf8(&amp;trail[total_read..], &gt;- &amp;mut (dst.to_mut())[total_written..], &gt;- true); &gt;+ let (result, read, written, had_errors) = encoder.encode_from_utf8( &gt;+ &amp;trail[total_read..], &gt;+ &amp;mut (dst.to_mut())[total_written..], &gt;+ true, &gt;+ ); &gt; total_read += read; &gt; total_written += written; &gt; total_had_errors |= had_errors; &gt; match result { &gt; CoderResult::InputEmpty =&gt; { &gt; debug_assert_eq!(valid_up_to + total_read, src.len()); &gt; debug_assert!(total_written &lt;= dst.len()); &gt; unsafe { &gt;@@ -524,21 +618,20 @@ pub fn encode_from_nscstring(encoding: &amp;'static Encoding, &gt; } &gt; } &gt; if total_had_errors { &gt; return (NS_OK_HAD_REPLACEMENTS, output_encoding); &gt; } &gt; return (NS_OK, output_encoding); &gt; } &gt; CoderResult::OutputFull =&gt; { &gt;- if let Some(needed) = &gt;- checked_add(total_written, &gt;- encoder &gt;- .max_buffer_length_from_utf8_if_no_unmappables(trail.len() - &gt;- total_read)) { &gt;+ if let Some(needed) = checked_add( &gt;+ total_written, &gt;+ encoder.max_buffer_length_from_utf8_if_no_unmappables(trail.len() - total_read), &gt;+ ) { &gt; // Let's round the allocation up in order to avoid repeated &gt; // allocations. Using power-of-two as the approximation of &gt; // available jemalloc buckets, since linking with &gt; // malloc_good_size is messy. &gt; if let Some(with_bookkeeping) = NS_CSTRING_OVERHEAD.checked_add(needed) { &gt; let rounded = with_bookkeeping.next_power_of_two(); &gt; let unclowned = rounded - NS_CSTRING_OVERHEAD; &gt; // XPCOM strings use uint32_t for length. &gt;diff --git a/js/rust/build.rs b/js/rust/build.rs &gt;index 29e21dbfddef..631b1a57a975 100644 &gt;--- a/js/rust/build.rs &gt;+++ b/js/rust/build.rs &gt;@@ -23,31 +23,31 @@ fn build_jsglue_cpp() { &gt; &gt; println!("cargo:rustc-link-search=native={}/lib", dst.display()); &gt; println!("cargo:rustc-link-lib=static=jsglue"); &gt; println!("cargo:rerun-if-changed=src/jsglue.cpp"); &gt; } &gt; &gt; /// Find the public include directory within our mozjs-sys crate dependency. &gt; fn get_mozjs_include_dir() -&gt; path::PathBuf { &gt;- let out_dir = env::var("OUT_DIR") &gt;- .expect("cargo should invoke us with the OUT_DIR env var set"); &gt;+ let out_dir = env::var("OUT_DIR").expect("cargo should invoke us with the OUT_DIR env var set"); &gt; &gt; let mut target_build_dir = path::PathBuf::from(out_dir); &gt; target_build_dir.push("../../"); &gt; &gt; let mut include_dir_glob = target_build_dir.display().to_string(); &gt; include_dir_glob.push_str("mozjs_sys-*/out/dist/include"); &gt; &gt;- let entries = glob::glob(&amp;include_dir_glob) &gt;- .expect("Should find entries for mozjs-sys include dir"); &gt;+ let entries = &gt;+ glob::glob(&amp;include_dir_glob).expect("Should find entries for mozjs-sys include dir"); &gt; &gt; for entry in entries { &gt; if let Ok(path) = entry { &gt;- return path.canonicalize() &gt;+ return path &gt;+ .canonicalize() &gt; .expect("Should canonicalize include path"); &gt; } &gt; } &gt; &gt; panic!("Should have found either a mozjs_sys in target/debug or in target/release"); &gt; } &gt; &gt; /// Invoke bindgen on the JSAPI headers to produce raw FFI bindings for use from &gt;@@ -73,17 +73,18 @@ fn build_jsapi_bindings() { &gt; .clang_arg("-DJS_DEBUG"); &gt; } &gt; &gt; if cfg!(feature = "bigint") { &gt; builder = builder.clang_arg("-DENABLE_BIGINT"); &gt; } &gt; &gt; let include_dir = get_mozjs_include_dir(); &gt;- let include_dir = include_dir.to_str() &gt;+ let include_dir = include_dir &gt;+ .to_str() &gt; .expect("Path to mozjs include dir should be utf-8"); &gt; builder = builder.clang_arg("-I"); &gt; builder = builder.clang_arg(include_dir); &gt; &gt; for ty in UNSAFE_IMPL_SYNC_TYPES { &gt; builder = builder.raw_line(format!("unsafe impl Sync for {} {{}}", ty)); &gt; } &gt; &gt;@@ -110,26 +111,29 @@ fn build_jsapi_bindings() { &gt; for ty in OPAQUE_TYPES { &gt; builder = builder.opaque_type(ty); &gt; } &gt; &gt; for ty in BLACKLIST_TYPES { &gt; builder = builder.blacklist_type(ty); &gt; } &gt; &gt;- let bindings = builder.generate() &gt;+ let bindings = builder &gt;+ .generate() &gt; .expect("Should generate JSAPI bindings OK"); &gt; &gt; let out = path::PathBuf::from(env::var("OUT_DIR").unwrap()); &gt; &gt; if cfg!(feature = "debugmozjs") { &gt;- bindings.write_to_file(out.join("jsapi_debug.rs")) &gt;+ bindings &gt;+ .write_to_file(out.join("jsapi_debug.rs")) &gt; .expect("Should write bindings to file OK"); &gt; } else { &gt;- bindings.write_to_file(out.join("jsapi.rs")) &gt;+ bindings &gt;+ .write_to_file(out.join("jsapi.rs")) &gt; .expect("Should write bindings to file OK"); &gt; } &gt; &gt; println!("cargo:rerun-if-changed=etc/wrapper.hpp"); &gt; } &gt; &gt; /// JSAPI types for which we should implement `Sync`. &gt; const UNSAFE_IMPL_SYNC_TYPES: &amp;'static [&amp;'static str] = &amp;[ &gt;@@ -137,17 +141,18 @@ const UNSAFE_IMPL_SYNC_TYPES: &amp;'static [&amp;'static str] = &amp;[ &gt; "JSFunctionSpec", &gt; "JSNativeWrapper", &gt; "JSPropertySpec", &gt; "JSTypedMethodJitInfo", &gt; ]; &gt; &gt; /// Flags passed through bindgen directly to Clang. &gt; const EXTRA_CLANG_FLAGS: &amp;'static [&amp;'static str] = &amp;[ &gt;- "-x", "c++", &gt;+ "-x", &gt;+ "c++", &gt; "-std=gnu++14", &gt; "-fno-sized-deallocation", &gt; "-DRUST_BINDGEN", &gt; ]; &gt; &gt; /// Types which we want to generate bindings for (and every other type they &gt; /// transitively use). &gt; const WHITELIST_TYPES: &amp;'static [&amp;'static str] = &amp;[ &gt;@@ -472,17 +477,17 @@ const WHITELIST_FUNCTIONS: &amp;'static [&amp;'static str] = &amp;[ &gt; /// These are types which are too tricky for bindgen to handle, and/or use C++ &gt; /// features that don't have an equivalent in rust, such as partial template &gt; /// specialization. &gt; const OPAQUE_TYPES: &amp;'static [&amp;'static str] = &amp;[ &gt; "JS::ReadOnlyCompileOptions", &gt; "mozilla::BufferList", &gt; "mozilla::UniquePtr.*", &gt; "JS::Rooted&lt;JS::Auto.*Vector.*&gt;", &gt;- "JS::Auto.*Vector" &gt;+ "JS::Auto.*Vector", &gt; ]; &gt; &gt; /// Types for which we should NEVER generate bindings, even if it is used within &gt; /// a type or function signature that we are generating bindings for. &gt; const BLACKLIST_TYPES: &amp;'static [&amp;'static str] = &amp;[ &gt; // We provide our own definition because we need to express trait bounds in &gt; // the definition of the struct to make our Drop implementation correct. &gt; "JS::Heap", &gt;diff --git a/js/rust/src/ac.rs b/js/rust/src/ac.rs &gt;index cfd5e8b82e45..aca790d59a38 100644 &gt;--- a/js/rust/src/ac.rs &gt;+++ b/js/rust/src/ac.rs &gt;@@ -2,55 +2,43 @@ use jsapi::root::*; &gt; #[cfg(feature = "debugmozjs")] &gt; use std::ptr; &gt; &gt; #[derive(Debug)] &gt; pub struct AutoCompartment(JSAutoRealmAllowCCW); &gt; &gt; impl AutoCompartment { &gt; #[cfg(feature = "debugmozjs")] &gt;- pub unsafe fn with_obj(cx: *mut JSContext, &gt;- target: *mut JSObject) &gt;- -&gt; AutoCompartment &gt;- { &gt;+ pub unsafe fn with_obj(cx: *mut JSContext, target: *mut JSObject) -&gt; AutoCompartment { &gt; let mut notifier = mozilla::detail::GuardObjectNotifier { &gt; mStatementDone: ptr::null_mut(), &gt; }; &gt; &gt;- AutoCompartment( &gt;- JSAutoRealmAllowCCW::new( &gt;- cx, &gt;- target, &gt;- &amp;mut notifier as *mut _)) &gt;+ AutoCompartment(JSAutoRealmAllowCCW::new( &gt;+ cx, &gt;+ target, &gt;+ &amp;mut notifier as *mut _, &gt;+ )) &gt; } &gt; &gt; #[cfg(not(feature = "debugmozjs"))] &gt;- pub unsafe fn with_obj(cx: *mut JSContext, &gt;- target: *mut JSObject) &gt;- -&gt; AutoCompartment &gt;- { &gt;+ pub unsafe fn with_obj(cx: *mut JSContext, target: *mut JSObject) -&gt; AutoCompartment { &gt; AutoCompartment(JSAutoRealmAllowCCW::new(cx, target)) &gt; } &gt; &gt; #[cfg(feature = "debugmozjs")] &gt;- pub unsafe fn with_script(cx: *mut JSContext, &gt;- target: *mut JSScript) &gt;- -&gt; AutoCompartment &gt;- { &gt;+ pub unsafe fn with_script(cx: *mut JSContext, target: *mut JSScript) -&gt; AutoCompartment { &gt; let mut notifier = mozilla::detail::GuardObjectNotifier { &gt; mStatementDone: ptr::null_mut(), &gt; }; &gt; &gt;- AutoCompartment( &gt;- JSAutoRealmAllowCCW::new1( &gt;- cx, &gt;- target, &gt;- &amp;mut notifier as *mut _)) &gt;+ AutoCompartment(JSAutoRealmAllowCCW::new1( &gt;+ cx, &gt;+ target, &gt;+ &amp;mut notifier as *mut _, &gt;+ )) &gt; } &gt; &gt; #[cfg(not(feature = "debugmozjs"))] &gt;- pub unsafe fn with_script(cx: *mut JSContext, &gt;- target: *mut JSScript) &gt;- -&gt; AutoCompartment &gt;- { &gt;+ pub unsafe fn with_script(cx: *mut JSContext, target: *mut JSScript) -&gt; AutoCompartment { &gt; AutoCompartment(JSAutoRealmAllowCCW::new1(cx, target)) &gt; } &gt; } &gt;diff --git a/js/rust/src/conversions.rs b/js/rust/src/conversions.rs &gt;index 4405ef0945cb..9b38171c49b3 100644 &gt;--- a/js/rust/src/conversions.rs &gt;+++ b/js/rust/src/conversions.rs &gt;@@ -30,37 +30,37 @@ &gt; #[cfg(feature = "nonzero")] &gt; use core::nonzero::NonZero; &gt; &gt; use error::throw_type_error; &gt; use glue::RUST_JS_NumberValue; &gt; use heap::Heap; &gt; use jsapi::root::*; &gt; use jsval::{BooleanValue, Int32Value, NullValue, UInt32Value, UndefinedValue}; &gt;-use jsval::{ObjectValue, ObjectOrNullValue, StringValue}; &gt;-use rust::{ToBoolean, ToInt32, ToInt64, ToNumber, ToUint16, ToUint32, ToUint64}; &gt;-use rust::{ToString, maybe_wrap_object_or_null_value, maybe_wrap_value}; &gt;+use jsval::{ObjectOrNullValue, ObjectValue, StringValue}; &gt; use libc; &gt; use num_traits::{Bounded, Zero}; &gt;+use rust::{maybe_wrap_object_or_null_value, maybe_wrap_value, ToString}; &gt;+use rust::{ToBoolean, ToInt32, ToInt64, ToNumber, ToUint16, ToUint32, ToUint64}; &gt; use std::borrow::Cow; &gt; use std::rc::Rc; &gt; use std::{ptr, slice}; &gt; &gt; trait As&lt;O&gt;: Copy { &gt; fn cast(self) -&gt; O; &gt; } &gt; &gt; macro_rules! impl_as { &gt;- ($I:ty, $O:ty) =&gt; ( &gt;+ ($I:ty, $O:ty) =&gt; { &gt; impl As&lt;$O&gt; for $I { &gt; fn cast(self) -&gt; $O { &gt; self as $O &gt; } &gt; } &gt;- ) &gt;+ }; &gt; } &gt; &gt; impl_as!(f64, u8); &gt; impl_as!(f64, u16); &gt; impl_as!(f64, u32); &gt; impl_as!(f64, u64); &gt; impl_as!(f64, i8); &gt; impl_as!(f64, i16); &gt;@@ -100,17 +100,17 @@ pub enum ConversionResult&lt;T&gt; { &gt; /// Conversion failed, without a pending exception. &gt; Failure(Cow&lt;'static, str&gt;), &gt; } &gt; &gt; impl&lt;T&gt; ConversionResult&lt;T&gt; { &gt; /// Map a function over the `Success` value. &gt; pub fn map&lt;F, U&gt;(self, mut f: F) -&gt; ConversionResult&lt;U&gt; &gt; where &gt;- F: FnMut(T) -&gt; U &gt;+ F: FnMut(T) -&gt; U, &gt; { &gt; match self { &gt; ConversionResult::Success(t) =&gt; ConversionResult::Success(f(t)), &gt; ConversionResult::Failure(e) =&gt; ConversionResult::Failure(e), &gt; } &gt; } &gt; &gt; /// Returns Some(value) if it is `ConversionResult::Success`. &gt;@@ -126,20 +126,21 @@ impl&lt;T&gt; ConversionResult&lt;T&gt; { &gt; pub trait FromJSValConvertible: Sized { &gt; /// Optional configurable behaviour switch; use () for no configuration. &gt; type Config; &gt; /// Convert `val` to type `Self`. &gt; /// Optional configuration of type `T` can be passed as the `option` &gt; /// argument. &gt; /// If it returns `Err(())`, a JSAPI exception is pending. &gt; /// If it returns `Ok(Failure(reason))`, there is no pending JSAPI exception. &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- val: JS::HandleValue, &gt;- option: Self::Config) &gt;- -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt;; &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ option: Self::Config, &gt;+ ) -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt;; &gt; } &gt; &gt; /// Behavior for converting out-of-range integers. &gt; #[derive(PartialEq, Eq, Clone)] &gt; pub enum ConversionBehavior { &gt; /// Wrap into the integer's range. &gt; Default, &gt; /// Throw an exception. &gt;@@ -149,62 +150,70 @@ pub enum ConversionBehavior { &gt; } &gt; &gt; /// Use `T` with `ConversionBehavior::Default` but without requiring any &gt; /// `Config` associated type. &gt; pub struct Default&lt;T&gt;(pub T); &gt; &gt; impl&lt;T&gt; FromJSValConvertible for Default&lt;T&gt; &gt; where &gt;- T: FromJSValConvertible&lt;Config = ConversionBehavior&gt; &gt;+ T: FromJSValConvertible&lt;Config = ConversionBehavior&gt;, &gt; { &gt; type Config = (); &gt;- unsafe fn from_jsval(cx: *mut JSContext, val: JS::HandleValue, _: ()) &gt;- -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ _: (), &gt;+ ) -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt; { &gt; T::from_jsval(cx, val, ConversionBehavior::Default).map(|conv| conv.map(Default)) &gt; } &gt; } &gt; &gt; /// Use `T` with `ConversionBehavior::EnforceRange` but without requiring any &gt; /// `Config` associated type. &gt; pub struct EnforceRange&lt;T&gt;(pub T); &gt; &gt; impl&lt;T&gt; FromJSValConvertible for EnforceRange&lt;T&gt; &gt;- where &gt;- T: FromJSValConvertible&lt;Config = ConversionBehavior&gt; &gt;+where &gt;+ T: FromJSValConvertible&lt;Config = ConversionBehavior&gt;, &gt; { &gt; type Config = (); &gt;- unsafe fn from_jsval(cx: *mut JSContext, val: JS::HandleValue, _: ()) &gt;- -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt; { &gt;- T::from_jsval(cx, val, ConversionBehavior::EnforceRange) &gt;- .map(|conv| conv.map(EnforceRange)) &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ _: (), &gt;+ ) -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt; { &gt;+ T::from_jsval(cx, val, ConversionBehavior::EnforceRange).map(|conv| conv.map(EnforceRange)) &gt; } &gt; } &gt; &gt; /// Use `T` with `ConversionBehavior::Clamp` but without requiring any `Config` &gt; /// associated type. &gt; pub struct Clamp&lt;T&gt;(pub T); &gt; &gt; impl&lt;T&gt; FromJSValConvertible for Clamp&lt;T&gt; &gt;- where &gt;- T: FromJSValConvertible&lt;Config = ConversionBehavior&gt; &gt;+where &gt;+ T: FromJSValConvertible&lt;Config = ConversionBehavior&gt;, &gt; { &gt; type Config = (); &gt;- unsafe fn from_jsval(cx: *mut JSContext, val: JS::HandleValue, _: ()) &gt;- -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt; { &gt;- T::from_jsval(cx, val, ConversionBehavior::Clamp) &gt;- .map(|conv| conv.map(Clamp)) &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ _: (), &gt;+ ) -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt; { &gt;+ T::from_jsval(cx, val, ConversionBehavior::Clamp).map(|conv| conv.map(Clamp)) &gt; } &gt; } &gt; &gt; /// Try to cast the number to a smaller type, but &gt; /// if it doesn't fit, it will return an error. &gt; unsafe fn enforce_range&lt;D&gt;(cx: *mut JSContext, d: f64) -&gt; Result&lt;ConversionResult&lt;D&gt;, ()&gt; &gt;- where D: Bounded + As&lt;f64&gt;, &gt;- f64: As&lt;D&gt; &gt;+where &gt;+ D: Bounded + As&lt;f64&gt;, &gt;+ f64: As&lt;D&gt;, &gt; { &gt; if d.is_infinite() { &gt; throw_type_error(cx, "value out of range in an EnforceRange argument"); &gt; return Err(()); &gt; } &gt; &gt; let rounded = d.round(); &gt; if D::min_value().cast() &lt;= rounded &amp;&amp; rounded &lt;= D::max_value().cast() { &gt;@@ -214,18 +223,19 @@ unsafe fn enforce_range&lt;D&gt;(cx: *mut JSContext, d: f64) -&gt; Result&lt;ConversionResul &gt; Err(()) &gt; } &gt; } &gt; &gt; /// Try to cast the number to a smaller type, but if it doesn't fit, &gt; /// round it to the MAX or MIN of the source type before casting it to &gt; /// the destination type. &gt; fn clamp_to&lt;D&gt;(d: f64) -&gt; D &gt;- where D: Bounded + As&lt;f64&gt; + Zero, &gt;- f64: As&lt;D&gt; &gt;+where &gt;+ D: Bounded + As&lt;f64&gt; + Zero, &gt;+ f64: As&lt;D&gt;, &gt; { &gt; if d.is_nan() { &gt; D::zero() &gt; } else if d &gt; D::max_value().cast() { &gt; D::max_value() &gt; } else if d &lt; D::min_value().cast() { &gt; D::min_value() &gt; } else { &gt;@@ -239,44 +249,49 @@ impl ToJSValConvertible for () { &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(UndefinedValue()); &gt; } &gt; } &gt; &gt; impl FromJSValConvertible for JS::HandleValue { &gt; type Config = (); &gt; #[inline] &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- value: JS::HandleValue, &gt;- _option: ()) &gt;- -&gt; Result&lt;ConversionResult&lt;JS::HandleValue&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ value: JS::HandleValue, &gt;+ _option: (), &gt;+ ) -&gt; Result&lt;ConversionResult&lt;JS::HandleValue&gt;, ()&gt; { &gt; if value.is_object() { &gt; js::AssertSameCompartment(cx, value.to_object()); &gt; } &gt; Ok(ConversionResult::Success(value)) &gt; } &gt; } &gt; &gt; impl FromJSValConvertible for JS::Value { &gt; type Config = (); &gt;- unsafe fn from_jsval(_cx: *mut JSContext, &gt;- value: JS::HandleValue, &gt;- _option: ()) &gt;- -&gt; Result&lt;ConversionResult&lt;JS::Value&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ _cx: *mut JSContext, &gt;+ value: JS::HandleValue, &gt;+ _option: (), &gt;+ ) -&gt; Result&lt;ConversionResult&lt;JS::Value&gt;, ()&gt; { &gt; Ok(ConversionResult::Success(value.get())) &gt; } &gt; } &gt; &gt; impl FromJSValConvertible for Heap&lt;JS::Value&gt; { &gt; type Config = (); &gt;- unsafe fn from_jsval(_cx: *mut JSContext, &gt;- value: JS::HandleValue, &gt;- _option: ()) &gt;- -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt; { &gt;- Ok(ConversionResult::Success(Heap::&lt;JS::Value&gt;::new(value.get()))) &gt;+ unsafe fn from_jsval( &gt;+ _cx: *mut JSContext, &gt;+ value: JS::HandleValue, &gt;+ _option: (), &gt;+ ) -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt; { &gt;+ Ok(ConversionResult::Success(Heap::&lt;JS::Value&gt;::new( &gt;+ value.get(), &gt;+ ))) &gt; } &gt; } &gt; &gt; impl ToJSValConvertible for JS::Value { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(*self); &gt; maybe_wrap_value(cx, rval); &gt;@@ -295,228 +310,255 @@ impl ToJSValConvertible for Heap&lt;JS::Value&gt; { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(self.get()); &gt; maybe_wrap_value(cx, rval); &gt; } &gt; } &gt; &gt; #[inline] &gt;-unsafe fn convert_int_from_jsval&lt;T, M&gt;(cx: *mut JSContext, value: JS::HandleValue, &gt;- option: ConversionBehavior, &gt;- convert_fn: unsafe fn(*mut JSContext, JS::HandleValue) -&gt; Result&lt;M, ()&gt;) &gt;- -&gt; Result&lt;ConversionResult&lt;T&gt;, ()&gt; &gt;- where T: Bounded + Zero + As&lt;f64&gt;, &gt;- M: Zero + As&lt;T&gt;, &gt;- f64: As&lt;T&gt; &gt;+unsafe fn convert_int_from_jsval&lt;T, M&gt;( &gt;+ cx: *mut JSContext, &gt;+ value: JS::HandleValue, &gt;+ option: ConversionBehavior, &gt;+ convert_fn: unsafe fn(*mut JSContext, JS::HandleValue) -&gt; Result&lt;M, ()&gt;, &gt;+) -&gt; Result&lt;ConversionResult&lt;T&gt;, ()&gt; &gt;+where &gt;+ T: Bounded + Zero + As&lt;f64&gt;, &gt;+ M: Zero + As&lt;T&gt;, &gt;+ f64: As&lt;T&gt;, &gt; { &gt; match option { &gt;- ConversionBehavior::Default =&gt; Ok(ConversionResult::Success(try!(convert_fn(cx, value)).cast())), &gt;+ ConversionBehavior::Default =&gt; Ok(ConversionResult::Success( &gt;+ try!(convert_fn(cx, value)).cast(), &gt;+ )), &gt; ConversionBehavior::EnforceRange =&gt; enforce_range(cx, try!(ToNumber(cx, value))), &gt;- ConversionBehavior::Clamp =&gt; Ok(ConversionResult::Success(clamp_to(try!(ToNumber(cx, value))))), &gt;+ ConversionBehavior::Clamp =&gt; Ok(ConversionResult::Success(clamp_to(try!(ToNumber( &gt;+ cx, value &gt;+ ))))), &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-boolean &gt; impl ToJSValConvertible for bool { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(BooleanValue(*self)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-boolean &gt; impl FromJSValConvertible for bool { &gt; type Config = (); &gt;- unsafe fn from_jsval(_cx: *mut JSContext, val: JS::HandleValue, _option: ()) -&gt; Result&lt;ConversionResult&lt;bool&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ _cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ _option: (), &gt;+ ) -&gt; Result&lt;ConversionResult&lt;bool&gt;, ()&gt; { &gt; Ok(ToBoolean(val)).map(ConversionResult::Success) &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-byte &gt; impl ToJSValConvertible for i8 { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(Int32Value(*self as i32)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-byte &gt; impl FromJSValConvertible for i8 { &gt; type Config = ConversionBehavior; &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- val: JS::HandleValue, &gt;- option: ConversionBehavior) &gt;- -&gt; Result&lt;ConversionResult&lt;i8&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ option: ConversionBehavior, &gt;+ ) -&gt; Result&lt;ConversionResult&lt;i8&gt;, ()&gt; { &gt; convert_int_from_jsval(cx, val, option, ToInt32) &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-octet &gt; impl ToJSValConvertible for u8 { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(Int32Value(*self as i32)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-octet &gt; impl FromJSValConvertible for u8 { &gt; type Config = ConversionBehavior; &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- val: JS::HandleValue, &gt;- option: ConversionBehavior) &gt;- -&gt; Result&lt;ConversionResult&lt;u8&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ option: ConversionBehavior, &gt;+ ) -&gt; Result&lt;ConversionResult&lt;u8&gt;, ()&gt; { &gt; convert_int_from_jsval(cx, val, option, ToInt32) &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-short &gt; impl ToJSValConvertible for i16 { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(Int32Value(*self as i32)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-short &gt; impl FromJSValConvertible for i16 { &gt; type Config = ConversionBehavior; &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- val: JS::HandleValue, &gt;- option: ConversionBehavior) &gt;- -&gt; Result&lt;ConversionResult&lt;i16&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ option: ConversionBehavior, &gt;+ ) -&gt; Result&lt;ConversionResult&lt;i16&gt;, ()&gt; { &gt; convert_int_from_jsval(cx, val, option, ToInt32) &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-unsigned-short &gt; impl ToJSValConvertible for u16 { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(Int32Value(*self as i32)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-unsigned-short &gt; impl FromJSValConvertible for u16 { &gt; type Config = ConversionBehavior; &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- val: JS::HandleValue, &gt;- option: ConversionBehavior) &gt;- -&gt; Result&lt;ConversionResult&lt;u16&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ option: ConversionBehavior, &gt;+ ) -&gt; Result&lt;ConversionResult&lt;u16&gt;, ()&gt; { &gt; convert_int_from_jsval(cx, val, option, ToUint16) &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-long &gt; impl ToJSValConvertible for i32 { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(Int32Value(*self)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-long &gt; impl FromJSValConvertible for i32 { &gt; type Config = ConversionBehavior; &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- val: JS::HandleValue, &gt;- option: ConversionBehavior) &gt;- -&gt; Result&lt;ConversionResult&lt;i32&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ option: ConversionBehavior, &gt;+ ) -&gt; Result&lt;ConversionResult&lt;i32&gt;, ()&gt; { &gt; convert_int_from_jsval(cx, val, option, ToInt32) &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-unsigned-long &gt; impl ToJSValConvertible for u32 { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(UInt32Value(*self)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-unsigned-long &gt; impl FromJSValConvertible for u32 { &gt; type Config = ConversionBehavior; &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- val: JS::HandleValue, &gt;- option: ConversionBehavior) &gt;- -&gt; Result&lt;ConversionResult&lt;u32&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ option: ConversionBehavior, &gt;+ ) -&gt; Result&lt;ConversionResult&lt;u32&gt;, ()&gt; { &gt; convert_int_from_jsval(cx, val, option, ToUint32) &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-long-long &gt; impl ToJSValConvertible for i64 { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(RUST_JS_NumberValue(*self as f64)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-long-long &gt; impl FromJSValConvertible for i64 { &gt; type Config = ConversionBehavior; &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- val: JS::HandleValue, &gt;- option: ConversionBehavior) &gt;- -&gt; Result&lt;ConversionResult&lt;i64&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ option: ConversionBehavior, &gt;+ ) -&gt; Result&lt;ConversionResult&lt;i64&gt;, ()&gt; { &gt; convert_int_from_jsval(cx, val, option, ToInt64) &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-unsigned-long-long &gt; impl ToJSValConvertible for u64 { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(RUST_JS_NumberValue(*self as f64)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-unsigned-long-long &gt; impl FromJSValConvertible for u64 { &gt; type Config = ConversionBehavior; &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- val: JS::HandleValue, &gt;- option: ConversionBehavior) &gt;- -&gt; Result&lt;ConversionResult&lt;u64&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ option: ConversionBehavior, &gt;+ ) -&gt; Result&lt;ConversionResult&lt;u64&gt;, ()&gt; { &gt; convert_int_from_jsval(cx, val, option, ToUint64) &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-float &gt; impl ToJSValConvertible for f32 { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(RUST_JS_NumberValue(*self as f64)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-float &gt; impl FromJSValConvertible for f32 { &gt; type Config = (); &gt;- unsafe fn from_jsval(cx: *mut JSContext, val: JS::HandleValue, _option: ()) -&gt; Result&lt;ConversionResult&lt;f32&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ _option: (), &gt;+ ) -&gt; Result&lt;ConversionResult&lt;f32&gt;, ()&gt; { &gt; let result = ToNumber(cx, val); &gt; result.map(|f| f as f32).map(ConversionResult::Success) &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-double &gt; impl ToJSValConvertible for f64 { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, _cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; rval.set(RUST_JS_NumberValue(*self)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-double &gt; impl FromJSValConvertible for f64 { &gt; type Config = (); &gt;- unsafe fn from_jsval(cx: *mut JSContext, val: JS::HandleValue, _option: ()) -&gt; Result&lt;ConversionResult&lt;f64&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ _option: (), &gt;+ ) -&gt; Result&lt;ConversionResult&lt;f64&gt;, ()&gt; { &gt; ToNumber(cx, val).map(ConversionResult::Success) &gt; } &gt; } &gt; &gt; /// Converts a `JSString`, encoded in "Latin1" (i.e. U+0000-U+00FF encoded as 0x00-0xFF) into a &gt; /// `String`. &gt; pub unsafe fn latin1_to_string(cx: *mut JSContext, s: *mut JSString) -&gt; String { &gt; assert!(JS_StringHasLatin1Chars(s)); &gt;@@ -532,19 +574,21 @@ pub unsafe fn latin1_to_string(cx: *mut JSContext, s: *mut JSString) -&gt; String { &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-USVString &gt; impl ToJSValConvertible for str { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; let mut string_utf16: Vec&lt;u16&gt; = Vec::with_capacity(self.len()); &gt; string_utf16.extend(self.encode_utf16()); &gt;- let jsstr = JS_NewUCStringCopyN(cx, &gt;- string_utf16.as_ptr(), &gt;- string_utf16.len() as libc::size_t); &gt;+ let jsstr = JS_NewUCStringCopyN( &gt;+ cx, &gt;+ string_utf16.as_ptr(), &gt;+ string_utf16.len() as libc::size_t, &gt;+ ); &gt; if jsstr.is_null() { &gt; panic!("JS_NewUCStringCopyN failed"); &gt; } &gt; rval.set(StringValue(&amp;*jsstr)); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-USVString &gt;@@ -553,17 +597,21 @@ impl ToJSValConvertible for String { &gt; unsafe fn to_jsval(&amp;self, cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; (**self).to_jsval(cx, rval); &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-USVString &gt; impl FromJSValConvertible for String { &gt; type Config = (); &gt;- unsafe fn from_jsval(cx: *mut JSContext, value: JS::HandleValue, _: ()) -&gt; Result&lt;ConversionResult&lt;String&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ value: JS::HandleValue, &gt;+ _: (), &gt;+ ) -&gt; Result&lt;ConversionResult&lt;String&gt;, ()&gt; { &gt; let jsstr = ToString(cx, value); &gt; if jsstr.is_null() { &gt; debug!("ToString failed"); &gt; return Err(()); &gt; } &gt; if JS_StringHasLatin1Chars(jsstr) { &gt; return Ok(latin1_to_string(cx, jsstr)).map(ConversionResult::Success); &gt; } &gt;@@ -590,27 +638,30 @@ impl&lt;T: ToJSValConvertible&gt; ToJSValConvertible for Rc&lt;T&gt; { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; (**self).to_jsval(cx, rval) &gt; } &gt; } &gt; &gt; impl&lt;T: FromJSValConvertible&gt; FromJSValConvertible for Option&lt;T&gt; { &gt; type Config = T::Config; &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- value: JS::HandleValue, &gt;- option: T::Config) &gt;- -&gt; Result&lt;ConversionResult&lt;Option&lt;T&gt;&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ value: JS::HandleValue, &gt;+ option: T::Config, &gt;+ ) -&gt; Result&lt;ConversionResult&lt;Option&lt;T&gt;&gt;, ()&gt; { &gt; if value.get().is_null_or_undefined() { &gt; Ok(ConversionResult::Success(None)) &gt; } else { &gt;- Ok(match try!(FromJSValConvertible::from_jsval(cx, value, option)) { &gt;- ConversionResult::Success(v) =&gt; ConversionResult::Success(Some(v)), &gt;- ConversionResult::Failure(v) =&gt; ConversionResult::Failure(v), &gt;- }) &gt;+ Ok( &gt;+ match try!(FromJSValConvertible::from_jsval(cx, value, option)) { &gt;+ ConversionResult::Success(v) =&gt; ConversionResult::Success(Some(v)), &gt;+ ConversionResult::Failure(v) =&gt; ConversionResult::Failure(v), &gt;+ }, &gt;+ ) &gt; } &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-sequence &gt; impl&lt;T: ToJSValConvertible&gt; ToJSValConvertible for Vec&lt;T&gt; { &gt; #[inline] &gt; unsafe fn to_jsval(&amp;self, cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt;@@ -634,81 +685,85 @@ impl&lt;T: ToJSValConvertible&gt; ToJSValConvertible for Vec&lt;T&gt; { &gt; } &gt; } &gt; &gt; /// Rooting guard for the iterator and nextMethod fields of ForOfIterator. &gt; /// Behaves like RootedGuard (roots on creation, unroots on drop), &gt; /// but borrows and allows access to the whole ForOfIterator, so &gt; /// that methods on ForOfIterator can still be used through it. &gt; struct ForOfIteratorGuard&lt;'a&gt; { &gt;- root: &amp;'a mut JS::ForOfIterator &gt;+ root: &amp;'a mut JS::ForOfIterator, &gt; } &gt; &gt; impl&lt;'a&gt; ForOfIteratorGuard&lt;'a&gt; { &gt; fn new(cx: *mut JSContext, root: &amp;'a mut JS::ForOfIterator) -&gt; Self { &gt; unsafe { &gt; root.iterator.register_with_root_lists(cx); &gt; root.nextMethod.register_with_root_lists(cx); &gt; } &gt;- ForOfIteratorGuard { &gt;- root: root &gt;- } &gt;+ ForOfIteratorGuard { root: root } &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; Drop for ForOfIteratorGuard&lt;'a&gt; { &gt; fn drop(&amp;mut self) { &gt; unsafe { &gt; self.root.nextMethod.remove_from_root_stack(); &gt; self.root.iterator.remove_from_root_stack(); &gt; } &gt; } &gt; } &gt; &gt;-impl&lt;C: Clone, T: FromJSValConvertible&lt;Config=C&gt;&gt; FromJSValConvertible for Vec&lt;T&gt; { &gt;+impl&lt;C: Clone, T: FromJSValConvertible&lt;Config = C&gt;&gt; FromJSValConvertible for Vec&lt;T&gt; { &gt; type Config = C; &gt; &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- value: JS::HandleValue, &gt;- option: C) &gt;- -&gt; Result&lt;ConversionResult&lt;Vec&lt;T&gt;&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ value: JS::HandleValue, &gt;+ option: C, &gt;+ ) -&gt; Result&lt;ConversionResult&lt;Vec&lt;T&gt;&gt;, ()&gt; { &gt; let mut iterator = JS::ForOfIterator { &gt; cx_: cx, &gt; iterator: JS::RootedObject::new_unrooted(), &gt; nextMethod: JS::RootedValue::new_unrooted(), &gt; index: ::std::u32::MAX, // NOT_ARRAY &gt; }; &gt; let iterator = ForOfIteratorGuard::new(cx, &amp;mut iterator); &gt; let iterator = &amp;mut *iterator.root; &gt; &gt;- if !iterator.init(value, JS::ForOfIterator_NonIterableBehavior::AllowNonIterable) { &gt;- return Err(()) &gt;+ if !iterator.init( &gt;+ value, &gt;+ JS::ForOfIterator_NonIterableBehavior::AllowNonIterable, &gt;+ ) { &gt;+ return Err(()); &gt; } &gt; &gt; if iterator.iterator.ptr.is_null() { &gt; return Ok(ConversionResult::Failure("Value is not iterable".into())); &gt; } &gt; &gt; let mut ret = vec![]; &gt; &gt; loop { &gt; let mut done = false; &gt; rooted!(in(cx) let mut val = UndefinedValue()); &gt; if !iterator.next(val.handle_mut(), &amp;mut done) { &gt;- return Err(()) &gt;+ return Err(()); &gt; } &gt; &gt; if done { &gt; break; &gt; } &gt; &gt;- ret.push(match try!(T::from_jsval(cx, val.handle(), option.clone())) { &gt;- ConversionResult::Success(v) =&gt; v, &gt;- ConversionResult::Failure(e) =&gt; return Ok(ConversionResult::Failure(e)), &gt;- }); &gt;+ ret.push( &gt;+ match try!(T::from_jsval(cx, val.handle(), option.clone())) { &gt;+ ConversionResult::Success(v) =&gt; v, &gt;+ ConversionResult::Failure(e) =&gt; return Ok(ConversionResult::Failure(e)), &gt;+ }, &gt;+ ); &gt; } &gt; &gt; Ok(ret).map(ConversionResult::Success) &gt; } &gt; } &gt; &gt; // https://heycam.github.io/webidl/#es-object &gt; impl ToJSValConvertible for *mut JSObject { &gt;@@ -773,20 +828,21 @@ impl ToJSValConvertible for JS::Handle&lt;*mut JSFunction&gt; { &gt; rval.set(ObjectOrNullValue(self.get() as *mut JSObject)); &gt; maybe_wrap_object_or_null_value(cx, rval); &gt; } &gt; } &gt; &gt; impl FromJSValConvertible for *mut JSFunction { &gt; type Config = (); &gt; &gt;- unsafe fn from_jsval(cx: *mut JSContext, &gt;- val: JS::HandleValue, &gt;- _: ()) &gt;- -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt; { &gt;+ unsafe fn from_jsval( &gt;+ cx: *mut JSContext, &gt;+ val: JS::HandleValue, &gt;+ _: (), &gt;+ ) -&gt; Result&lt;ConversionResult&lt;Self&gt;, ()&gt; { &gt; let func = JS_ValueToFunction(cx, val); &gt; if func.is_null() { &gt; Ok(ConversionResult::Failure("value is not a function".into())) &gt; } else { &gt; Ok(ConversionResult::Success(func)) &gt; } &gt; } &gt; } &gt;diff --git a/js/rust/src/error.rs b/js/rust/src/error.rs &gt;index 1216e8b02b32..34a5fa828ab6 100644 &gt;--- a/js/rust/src/error.rs &gt;+++ b/js/rust/src/error.rs &gt;@@ -32,39 +32,44 @@ static mut RANGE_ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString &gt; name: b"RUSTMSG_RANGE_ERROR\0" as *const _ as *const libc::c_char, &gt; format: &amp;ERROR_FORMAT_STRING_STRING as *const libc::c_char, &gt; argCount: 1, &gt; exnType: JSExnType::JSEXN_RANGEERR as i16, &gt; }; &gt; &gt; /// Callback used to throw javascript errors. &gt; /// See throw_js_error for info about error_number. &gt;-unsafe extern "C" fn get_error_message(_user_ref: *mut os::raw::c_void, &gt;- error_number: libc::c_uint) &gt;- -&gt; *const JSErrorFormatString { &gt;+unsafe extern "C" fn get_error_message( &gt;+ _user_ref: *mut os::raw::c_void, &gt;+ error_number: libc::c_uint, &gt;+) -&gt; *const JSErrorFormatString { &gt; let num: JSExnType = mem::transmute(error_number); &gt; match num { &gt; JSExnType::JSEXN_TYPEERR =&gt; &amp;TYPE_ERROR_FORMAT_STRING as *const JSErrorFormatString, &gt; JSExnType::JSEXN_RANGEERR =&gt; &amp;RANGE_ERROR_FORMAT_STRING as *const JSErrorFormatString, &gt;- _ =&gt; panic!("Bad js error number given to get_error_message: {}", &gt;- error_number), &gt;+ _ =&gt; panic!( &gt;+ "Bad js error number given to get_error_message: {}", &gt;+ error_number &gt;+ ), &gt; } &gt; } &gt; &gt; /// Helper fn to throw a javascript error with the given message and number. &gt; /// Reuse the jsapi error codes to distinguish the error_number &gt; /// passed back to the get_error_message callback. &gt; /// c_uint is u32, so this cast is safe, as is casting to/from i32 from there. &gt; unsafe fn throw_js_error(cx: *mut JSContext, error: &amp;str, error_number: u32) { &gt; let error = CString::new(error).unwrap(); &gt;- JS_ReportErrorNumberUTF8(cx, &gt;- Some(get_error_message), &gt;- ptr::null_mut(), &gt;- error_number, &gt;- error.as_ptr()); &gt;+ JS_ReportErrorNumberUTF8( &gt;+ cx, &gt;+ Some(get_error_message), &gt;+ ptr::null_mut(), &gt;+ error_number, &gt;+ error.as_ptr(), &gt;+ ); &gt; } &gt; &gt; /// Throw a `TypeError` with the given message. &gt; pub unsafe fn throw_type_error(cx: *mut JSContext, error: &amp;str) { &gt; throw_js_error(cx, error, JSExnType::JSEXN_TYPEERR as u32); &gt; } &gt; &gt; /// Throw a `RangeError` with the given message. &gt;diff --git a/js/rust/src/glue.rs b/js/rust/src/glue.rs &gt;index 362c08d69cb0..5d46730865e8 100644 &gt;--- a/js/rust/src/glue.rs &gt;+++ b/js/rust/src/glue.rs &gt;@@ -1,145 +1,198 @@ &gt;-use jsapi::root::*; &gt; use heap::Heap; &gt;+use jsapi::root::*; &gt; use std::os::raw::c_void; &gt; &gt;- &gt;-pub enum Action { } &gt;+pub enum Action {} &gt; unsafe impl Sync for ProxyTraps {} &gt; &gt; #[repr(C)] &gt; #[derive(Copy, Clone)] &gt; pub struct ProxyTraps { &gt;- pub enter: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- id: JS::HandleId, &gt;- action: Action, &gt;- bp: *mut bool) &gt;- -&gt; bool&gt;, &gt;- pub getOwnPropertyDescriptor: &gt;- ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- id: JS::HandleId, &gt;- desc: JS::MutableHandle&lt;JS::PropertyDescriptor&gt;) &gt;- -&gt; bool&gt;, &gt;- pub defineProperty: &gt;- ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- id: JS::HandleId, &gt;- desc: JS::Handle&lt;JS::PropertyDescriptor&gt;, &gt;- result: *mut JS::ObjectOpResult) &gt;- -&gt; bool&gt;, &gt;- pub ownPropertyKeys: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- props: *mut JS::AutoIdVector) &gt;- -&gt; bool&gt;, &gt;- pub delete_: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- id: JS::HandleId, &gt;- result: *mut JS::ObjectOpResult) &gt;- -&gt; bool&gt;, &gt;- pub enumerate: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- objp: JS::MutableHandleObject) &gt;- -&gt; bool&gt;, &gt;- pub getPrototypeIfOrdinary: &gt;- ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- isOrdinary: *mut bool, &gt;- protop: JS::MutableHandleObject) &gt;- -&gt; bool&gt;, &gt;- pub preventExtensions: &gt;- ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- result: *mut JS::ObjectOpResult) &gt;- -&gt; bool&gt;, &gt;- pub isExtensible: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- succeeded: *mut bool) &gt;- -&gt; bool&gt;, &gt;- pub has: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- id: JS::HandleId, &gt;- bp: *mut bool) &gt;- -&gt; bool&gt;, &gt;- pub get: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- receiver: JS::HandleValue, &gt;- id: JS::HandleId, &gt;- vp: JS::MutableHandleValue) &gt;- -&gt; bool&gt;, &gt;- pub set: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- id: JS::HandleId, &gt;- v: JS::HandleValue, &gt;- receiver: JS::HandleValue, &gt;- result: *mut JS::ObjectOpResult) &gt;- -&gt; bool&gt;, &gt;- pub call: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- args: *const JS::CallArgs) &gt;- -&gt; bool&gt;, &gt;- pub construct: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- args: *const JS::CallArgs) &gt;- -&gt; bool&gt;, &gt;- pub getPropertyDescriptor: &gt;- ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- id: JS::HandleId, &gt;- desc: JS::MutableHandle&lt;JS::PropertyDescriptor&gt;) &gt;- -&gt; bool&gt;, &gt;- pub hasOwn: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- id: JS::HandleId, &gt;- bp: *mut bool) &gt;- -&gt; bool&gt;, &gt;- pub getOwnEnumerablePropertyKeys: &gt;- ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- props: *mut JS::AutoIdVector) &gt;- -&gt; bool&gt;, &gt;- pub nativeCall: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- test: JS::IsAcceptableThis, &gt;- _impl: JS::NativeImpl, &gt;- args: JS::CallArgs) &gt;- -&gt; bool&gt;, &gt;- pub hasInstance: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- v: JS::MutableHandleValue, &gt;- bp: *mut bool) &gt;- -&gt; bool&gt;, &gt;- pub objectClassIs: ::std::option::Option&lt;unsafe extern "C" fn(obj: JS::HandleObject, &gt;- classValue: js::ESClass, &gt;- cx: *mut JSContext) &gt;- -&gt; bool&gt;, &gt;- pub className: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject) &gt;- -&gt; *const i8&gt;, &gt;- pub fun_toString: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- indent: u32) &gt;- -&gt; *mut JSString&gt;, &gt;- pub boxedValue_unbox: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- vp: JS::MutableHandleValue) &gt;- -&gt; bool&gt;, &gt;- pub defaultValue: ::std::option::Option&lt;unsafe extern "C" fn(cx: *mut JSContext, &gt;- obj: JS::HandleObject, &gt;- hint: JSType, &gt;- vp: JS::MutableHandleValue) &gt;- -&gt; bool&gt;, &gt;+ pub enter: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ id: JS::HandleId, &gt;+ action: Action, &gt;+ bp: *mut bool, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub getOwnPropertyDescriptor: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ id: JS::HandleId, &gt;+ desc: JS::MutableHandle&lt;JS::PropertyDescriptor&gt;, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub defineProperty: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ id: JS::HandleId, &gt;+ desc: JS::Handle&lt;JS::PropertyDescriptor&gt;, &gt;+ result: *mut JS::ObjectOpResult, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub ownPropertyKeys: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ props: *mut JS::AutoIdVector, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub delete_: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ id: JS::HandleId, &gt;+ result: *mut JS::ObjectOpResult, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub enumerate: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ objp: JS::MutableHandleObject, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub getPrototypeIfOrdinary: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ isOrdinary: *mut bool, &gt;+ protop: JS::MutableHandleObject, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub preventExtensions: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ result: *mut JS::ObjectOpResult, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub isExtensible: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn(cx: *mut JSContext, proxy: JS::HandleObject, succeeded: *mut bool) &gt;+ -&gt; bool, &gt;+ &gt;, &gt;+ pub has: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ id: JS::HandleId, &gt;+ bp: *mut bool, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub get: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ receiver: JS::HandleValue, &gt;+ id: JS::HandleId, &gt;+ vp: JS::MutableHandleValue, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub set: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ id: JS::HandleId, &gt;+ v: JS::HandleValue, &gt;+ receiver: JS::HandleValue, &gt;+ result: *mut JS::ObjectOpResult, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub call: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ args: *const JS::CallArgs, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub construct: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ args: *const JS::CallArgs, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub getPropertyDescriptor: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ id: JS::HandleId, &gt;+ desc: JS::MutableHandle&lt;JS::PropertyDescriptor&gt;, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub hasOwn: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ id: JS::HandleId, &gt;+ bp: *mut bool, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub getOwnEnumerablePropertyKeys: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ props: *mut JS::AutoIdVector, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub nativeCall: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ test: JS::IsAcceptableThis, &gt;+ _impl: JS::NativeImpl, &gt;+ args: JS::CallArgs, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub hasInstance: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ v: JS::MutableHandleValue, &gt;+ bp: *mut bool, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub objectClassIs: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn(obj: JS::HandleObject, classValue: js::ESClass, cx: *mut JSContext) &gt;+ -&gt; bool, &gt;+ &gt;, &gt;+ pub className: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn(cx: *mut JSContext, proxy: JS::HandleObject) -&gt; *const i8, &gt;+ &gt;, &gt;+ pub fun_toString: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn(cx: *mut JSContext, proxy: JS::HandleObject, indent: u32) &gt;+ -&gt; *mut JSString, &gt;+ &gt;, &gt;+ pub boxedValue_unbox: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ vp: JS::MutableHandleValue, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt;+ pub defaultValue: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ cx: *mut JSContext, &gt;+ obj: JS::HandleObject, &gt;+ hint: JSType, &gt;+ vp: JS::MutableHandleValue, &gt;+ ) -&gt; bool, &gt;+ &gt;, &gt; pub trace: &gt; ::std::option::Option&lt;unsafe extern "C" fn(trc: *mut JSTracer, proxy: *mut JSObject)&gt;, &gt; pub finalize: &gt; ::std::option::Option&lt;unsafe extern "C" fn(fop: *mut JSFreeOp, proxy: *mut JSObject)&gt;, &gt;- pub objectMoved: &gt;- ::std::option::Option&lt;unsafe extern "C" fn(proxy: *mut JSObject, &gt;- old: *mut JSObject) -&gt; usize&gt;, &gt;+ pub objectMoved: ::std::option::Option&lt; &gt;+ unsafe extern "C" fn(proxy: *mut JSObject, old: *mut JSObject) -&gt; usize, &gt;+ &gt;, &gt; pub isCallable: ::std::option::Option&lt;unsafe extern "C" fn(obj: *mut JSObject) -&gt; bool&gt;, &gt; pub isConstructor: ::std::option::Option&lt;unsafe extern "C" fn(obj: *mut JSObject) -&gt; bool&gt;, &gt; } &gt; impl ::std::default::Default for ProxyTraps { &gt; fn default() -&gt; ProxyTraps { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt;@@ -161,189 +214,231 @@ pub struct ForwardingProxyHandler { &gt; } &gt; impl ::std::default::Default for ForwardingProxyHandler { &gt; fn default() -&gt; ForwardingProxyHandler { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt; extern "C" { &gt;- pub fn InvokeGetOwnPropertyDescriptor(handler: *const ::libc::c_void, &gt;- cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- id: JS::HandleId, &gt;- desc: JS::MutableHandle&lt;JS::PropertyDescriptor&gt;) &gt;- -&gt; bool; &gt;- pub fn InvokeHasOwn(handler: *const ::libc::c_void, &gt;- cx: *mut JSContext, &gt;- proxy: JS::HandleObject, &gt;- id: JS::HandleId, &gt;- bp: *mut bool) &gt;- -&gt; bool; &gt;+ pub fn InvokeGetOwnPropertyDescriptor( &gt;+ handler: *const ::libc::c_void, &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ id: JS::HandleId, &gt;+ desc: JS::MutableHandle&lt;JS::PropertyDescriptor&gt;, &gt;+ ) -&gt; bool; &gt;+ pub fn InvokeHasOwn( &gt;+ handler: *const ::libc::c_void, &gt;+ cx: *mut JSContext, &gt;+ proxy: JS::HandleObject, &gt;+ id: JS::HandleId, &gt;+ bp: *mut bool, &gt;+ ) -&gt; bool; &gt; pub fn RUST_JS_NumberValue(d: f64) -&gt; JS::Value; &gt; pub fn RUST_FUNCTION_VALUE_TO_JITINFO(v: JS::Value) -&gt; *const JSJitInfo; &gt; pub fn CreateCallArgsFromVp(argc: u32, v: *mut JS::Value) -&gt; JS::CallArgs; &gt;- pub fn CallJitGetterOp(info: *const JSJitInfo, &gt;- cx: *mut JSContext, &gt;- thisObj: JS::HandleObject, &gt;- specializedThis: *mut ::libc::c_void, &gt;- argc: u32, &gt;- vp: *mut JS::Value) &gt;- -&gt; bool; &gt;- pub fn CallJitSetterOp(info: *const JSJitInfo, &gt;- cx: *mut JSContext, &gt;- thisObj: JS::HandleObject, &gt;- specializedThis: *mut ::libc::c_void, &gt;- argc: u32, &gt;- vp: *mut JS::Value) &gt;- -&gt; bool; &gt;- pub fn CallJitMethodOp(info: *const JSJitInfo, &gt;- cx: *mut JSContext, &gt;- thisObj: JS::HandleObject, &gt;- specializedThis: *mut ::libc::c_void, &gt;- argc: u32, &gt;- vp: *mut JS::Value) &gt;- -&gt; bool; &gt;- pub fn CreateProxyHandler(aTraps: *const ProxyTraps, &gt;- aExtra: *const ::libc::c_void) &gt;- -&gt; *const ::libc::c_void; &gt;+ pub fn CallJitGetterOp( &gt;+ info: *const JSJitInfo, &gt;+ cx: *mut JSContext, &gt;+ thisObj: JS::HandleObject, &gt;+ specializedThis: *mut ::libc::c_void, &gt;+ argc: u32, &gt;+ vp: *mut JS::Value, &gt;+ ) -&gt; bool; &gt;+ pub fn CallJitSetterOp( &gt;+ info: *const JSJitInfo, &gt;+ cx: *mut JSContext, &gt;+ thisObj: JS::HandleObject, &gt;+ specializedThis: *mut ::libc::c_void, &gt;+ argc: u32, &gt;+ vp: *mut JS::Value, &gt;+ ) -&gt; bool; &gt;+ pub fn CallJitMethodOp( &gt;+ info: *const JSJitInfo, &gt;+ cx: *mut JSContext, &gt;+ thisObj: JS::HandleObject, &gt;+ specializedThis: *mut ::libc::c_void, &gt;+ argc: u32, &gt;+ vp: *mut JS::Value, &gt;+ ) -&gt; bool; &gt;+ pub fn CreateProxyHandler( &gt;+ aTraps: *const ProxyTraps, &gt;+ aExtra: *const ::libc::c_void, &gt;+ ) -&gt; *const ::libc::c_void; &gt; pub fn CreateWrapperProxyHandler(aTraps: *const ProxyTraps) -&gt; *const ::libc::c_void; &gt;- pub fn CreateRustJSPrincipal(origin: *const ::libc::c_void, &gt;- destroy: Option&lt;unsafe extern "C" fn &gt;- (principal: *mut JSPrincipals)&gt;, &gt;- write: Option&lt;unsafe extern "C" fn &gt;- (cx: *mut JSContext, &gt;- writer: *mut JSStructuredCloneWriter) &gt;- -&gt; bool&gt;) &gt;--&gt; *mut JSPrincipals; &gt;+ pub fn CreateRustJSPrincipal( &gt;+ origin: *const ::libc::c_void, &gt;+ destroy: Option&lt;unsafe extern "C" fn(principal: *mut JSPrincipals)&gt;, &gt;+ write: Option&lt; &gt;+ unsafe extern "C" fn(cx: *mut JSContext, writer: *mut JSStructuredCloneWriter) -&gt; bool, &gt;+ &gt;, &gt;+ ) -&gt; *mut JSPrincipals; &gt; pub fn GetPrincipalOrigin(principal: *const JSPrincipals) -&gt; *const ::libc::c_void; &gt; pub fn GetCrossCompartmentWrapper() -&gt; *const ::libc::c_void; &gt; pub fn GetSecurityWrapper() -&gt; *const ::libc::c_void; &gt;- pub fn NewCompileOptions(aCx: *mut JSContext, &gt;- aFile: *const ::libc::c_char, &gt;- aLine: u32) &gt;- -&gt; *mut JS::ReadOnlyCompileOptions; &gt;+ pub fn NewCompileOptions( &gt;+ aCx: *mut JSContext, &gt;+ aFile: *const ::libc::c_char, &gt;+ aLine: u32, &gt;+ ) -&gt; *mut JS::ReadOnlyCompileOptions; &gt; pub fn DeleteCompileOptions(aOpts: *mut JS::ReadOnlyCompileOptions); &gt;- pub fn NewProxyObject(aCx: *mut JSContext, &gt;- aHandler: *const ::libc::c_void, &gt;- aPriv: JS::HandleValue, &gt;- proto: *mut JSObject, &gt;- parent: *mut JSObject, &gt;- call: *mut JSObject, &gt;- construct: *mut JSObject) &gt;- -&gt; *mut JSObject; &gt;- pub fn WrapperNew(aCx: *mut JSContext, &gt;- aObj: JS::HandleObject, &gt;- aHandler: *const ::libc::c_void, &gt;- aClass: *const JSClass, &gt;- aSingleton: bool) &gt;- -&gt; *mut JSObject; &gt;- pub fn NewWindowProxy(aCx: *mut JSContext, &gt;- aObj: JS::HandleObject, &gt;- aHandler: *const ::libc::c_void) &gt;- -&gt; *mut JSObject; &gt;+ pub fn NewProxyObject( &gt;+ aCx: *mut JSContext, &gt;+ aHandler: *const ::libc::c_void, &gt;+ aPriv: JS::HandleValue, &gt;+ proto: *mut JSObject, &gt;+ parent: *mut JSObject, &gt;+ call: *mut JSObject, &gt;+ construct: *mut JSObject, &gt;+ ) -&gt; *mut JSObject; &gt;+ pub fn WrapperNew( &gt;+ aCx: *mut JSContext, &gt;+ aObj: JS::HandleObject, &gt;+ aHandler: *const ::libc::c_void, &gt;+ aClass: *const JSClass, &gt;+ aSingleton: bool, &gt;+ ) -&gt; *mut JSObject; &gt;+ pub fn NewWindowProxy( &gt;+ aCx: *mut JSContext, &gt;+ aObj: JS::HandleObject, &gt;+ aHandler: *const ::libc::c_void, &gt;+ ) -&gt; *mut JSObject; &gt; pub fn GetWindowProxyClass() -&gt; *const js::Class; &gt; pub fn GetProxyPrivate(obj: *mut JSObject) -&gt; JS::Value; &gt; pub fn SetProxyPrivate(obj: *mut JSObject, private: *const JS::Value); &gt; pub fn GetProxyReservedSlot(obj: *mut JSObject, slot: u32) -&gt; JS::Value; &gt; pub fn SetProxyReservedSlot(obj: *mut JSObject, slot: u32, val: *const JS::Value); &gt; pub fn RUST_JSID_IS_INT(id: JS::HandleId) -&gt; bool; &gt; pub fn RUST_JSID_TO_INT(id: JS::HandleId) -&gt; i32; &gt; pub fn int_to_jsid(i: i32) -&gt; jsid; &gt; pub fn RUST_JSID_IS_STRING(id: JS::HandleId) -&gt; bool; &gt; pub fn RUST_JSID_TO_STRING(id: JS::HandleId) -&gt; *mut JSString; &gt; pub fn RUST_SYMBOL_TO_JSID(sym: *mut JS::Symbol) -&gt; jsid; &gt; pub fn RUST_SET_JITINFO(func: *mut JSFunction, info: *const JSJitInfo); &gt; pub fn RUST_INTERNED_STRING_TO_JSID(cx: *mut JSContext, str: *mut JSString) -&gt; jsid; &gt;- pub fn RUST_js_GetErrorMessage(userRef: *mut ::libc::c_void, &gt;- errorNumber: u32) &gt;- -&gt; *const JSErrorFormatString; &gt;+ pub fn RUST_js_GetErrorMessage( &gt;+ userRef: *mut ::libc::c_void, &gt;+ errorNumber: u32, &gt;+ ) -&gt; *const JSErrorFormatString; &gt; pub fn IsProxyHandlerFamily(obj: *mut JSObject) -&gt; u8; &gt; pub fn GetProxyHandlerExtra(obj: *mut JSObject) -&gt; *const ::libc::c_void; &gt; pub fn GetProxyHandler(obj: *mut JSObject) -&gt; *const ::libc::c_void; &gt; pub fn ReportError(aCx: *mut JSContext, aError: *const i8); &gt; pub fn IsWrapper(obj: *mut JSObject) -&gt; bool; &gt; pub fn UnwrapObject(obj: *mut JSObject, stopAtOuter: u8) -&gt; *mut JSObject; &gt; pub fn UncheckedUnwrapObject(obj: *mut JSObject, stopAtOuter: u8) -&gt; *mut JSObject; &gt; pub fn CreateAutoIdVector(cx: *mut JSContext) -&gt; *mut JS::AutoIdVector; &gt; pub fn AppendToAutoIdVector(v: *mut JS::AutoIdVector, id: jsid) -&gt; bool; &gt; pub fn SliceAutoIdVector(v: *const JS::AutoIdVector, length: *mut usize) -&gt; *const jsid; &gt; pub fn DestroyAutoIdVector(v: *mut JS::AutoIdVector); &gt; pub fn CreateAutoObjectVector(aCx: *mut JSContext) -&gt; *mut JS::AutoObjectVector; &gt; pub fn AppendToAutoObjectVector(v: *mut JS::AutoObjectVector, obj: *mut JSObject) -&gt; bool; &gt; pub fn DeleteAutoObjectVector(v: *mut JS::AutoObjectVector); &gt; pub fn CollectServoSizes(rt: *mut JSRuntime, sizes: *mut JS::ServoSizes) -&gt; bool; &gt; pub fn CallIdTracer(trc: *mut JSTracer, idp: *mut Heap&lt;jsid&gt;, name: *const ::libc::c_char); &gt;- pub fn CallValueTracer(trc: *mut JSTracer, &gt;- valuep: *mut Heap&lt;JS::Value&gt;, &gt;- name: *const ::libc::c_char); &gt;- pub fn CallObjectTracer(trc: *mut JSTracer, &gt;- objp: *mut Heap&lt;*mut JSObject&gt;, &gt;- name: *const ::libc::c_char); &gt;- pub fn CallStringTracer(trc: *mut JSTracer, &gt;- strp: *mut Heap&lt;*mut JSString&gt;, &gt;- name: *const ::libc::c_char); &gt;- pub fn CallScriptTracer(trc: *mut JSTracer, &gt;- scriptp: *mut Heap&lt;*mut JSScript&gt;, &gt;- name: *const ::libc::c_char); &gt;- pub fn CallFunctionTracer(trc: *mut JSTracer, &gt;- funp: *mut Heap&lt;*mut JSFunction&gt;, &gt;- name: *const ::libc::c_char); &gt;- pub fn CallUnbarrieredObjectTracer(trc: *mut JSTracer, &gt;- objp: *mut *mut JSObject, &gt;- name: *const ::libc::c_char); &gt;+ pub fn CallValueTracer( &gt;+ trc: *mut JSTracer, &gt;+ valuep: *mut Heap&lt;JS::Value&gt;, &gt;+ name: *const ::libc::c_char, &gt;+ ); &gt;+ pub fn CallObjectTracer( &gt;+ trc: *mut JSTracer, &gt;+ objp: *mut Heap&lt;*mut JSObject&gt;, &gt;+ name: *const ::libc::c_char, &gt;+ ); &gt;+ pub fn CallStringTracer( &gt;+ trc: *mut JSTracer, &gt;+ strp: *mut Heap&lt;*mut JSString&gt;, &gt;+ name: *const ::libc::c_char, &gt;+ ); &gt;+ pub fn CallScriptTracer( &gt;+ trc: *mut JSTracer, &gt;+ scriptp: *mut Heap&lt;*mut JSScript&gt;, &gt;+ name: *const ::libc::c_char, &gt;+ ); &gt;+ pub fn CallFunctionTracer( &gt;+ trc: *mut JSTracer, &gt;+ funp: *mut Heap&lt;*mut JSFunction&gt;, &gt;+ name: *const ::libc::c_char, &gt;+ ); &gt;+ pub fn CallUnbarrieredObjectTracer( &gt;+ trc: *mut JSTracer, &gt;+ objp: *mut *mut JSObject, &gt;+ name: *const ::libc::c_char, &gt;+ ); &gt; pub fn GetProxyHandlerFamily() -&gt; *const c_void; &gt; &gt;- pub fn GetInt8ArrayLengthAndData(obj: *mut JSObject, &gt;- length: *mut u32, &gt;- isSharedMemory: *mut bool, &gt;- data: *mut *mut i8); &gt;- pub fn GetUint8ArrayLengthAndData(obj: *mut JSObject, &gt;- length: *mut u32, &gt;- isSharedMemory: *mut bool, &gt;- data: *mut *mut u8); &gt;- pub fn GetUint8ClampedArrayLengthAndData(obj: *mut JSObject, &gt;- length: *mut u32, &gt;- isSharedMemory: *mut bool, &gt;- data: *mut *mut u8); &gt;- pub fn GetInt16ArrayLengthAndData(obj: *mut JSObject, &gt;- length: *mut u32, &gt;- isSharedMemory: *mut bool, &gt;- data: *mut *mut i16); &gt;- pub fn GetUint16ArrayLengthAndData(obj: *mut JSObject, &gt;- length: *mut u32, &gt;- isSharedMemory: *mut bool, &gt;- data: *mut *mut u16); &gt;- pub fn GetInt32ArrayLengthAndData(obj: *mut JSObject, &gt;- length: *mut u32, &gt;- isSharedMemory: *mut bool, &gt;- data: *mut *mut i32); &gt;- pub fn GetUint32ArrayLengthAndData(obj: *mut JSObject, &gt;- length: *mut u32, &gt;- isSharedMemory: *mut bool, &gt;- data: *mut *mut u32); &gt;- pub fn GetFloat32ArrayLengthAndData(obj: *mut JSObject, &gt;- length: *mut u32, &gt;- isSharedMemory: *mut bool, &gt;- data: *mut *mut f32); &gt;- pub fn GetFloat64ArrayLengthAndData(obj: *mut JSObject, &gt;- length: *mut u32, &gt;- isSharedMemory: *mut bool, &gt;- data: *mut *mut f64); &gt;+ pub fn GetInt8ArrayLengthAndData( &gt;+ obj: *mut JSObject, &gt;+ length: *mut u32, &gt;+ isSharedMemory: *mut bool, &gt;+ data: *mut *mut i8, &gt;+ ); &gt;+ pub fn GetUint8ArrayLengthAndData( &gt;+ obj: *mut JSObject, &gt;+ length: *mut u32, &gt;+ isSharedMemory: *mut bool, &gt;+ data: *mut *mut u8, &gt;+ ); &gt;+ pub fn GetUint8ClampedArrayLengthAndData( &gt;+ obj: *mut JSObject, &gt;+ length: *mut u32, &gt;+ isSharedMemory: *mut bool, &gt;+ data: *mut *mut u8, &gt;+ ); &gt;+ pub fn GetInt16ArrayLengthAndData( &gt;+ obj: *mut JSObject, &gt;+ length: *mut u32, &gt;+ isSharedMemory: *mut bool, &gt;+ data: *mut *mut i16, &gt;+ ); &gt;+ pub fn GetUint16ArrayLengthAndData( &gt;+ obj: *mut JSObject, &gt;+ length: *mut u32, &gt;+ isSharedMemory: *mut bool, &gt;+ data: *mut *mut u16, &gt;+ ); &gt;+ pub fn GetInt32ArrayLengthAndData( &gt;+ obj: *mut JSObject, &gt;+ length: *mut u32, &gt;+ isSharedMemory: *mut bool, &gt;+ data: *mut *mut i32, &gt;+ ); &gt;+ pub fn GetUint32ArrayLengthAndData( &gt;+ obj: *mut JSObject, &gt;+ length: *mut u32, &gt;+ isSharedMemory: *mut bool, &gt;+ data: *mut *mut u32, &gt;+ ); &gt;+ pub fn GetFloat32ArrayLengthAndData( &gt;+ obj: *mut JSObject, &gt;+ length: *mut u32, &gt;+ isSharedMemory: *mut bool, &gt;+ data: *mut *mut f32, &gt;+ ); &gt;+ pub fn GetFloat64ArrayLengthAndData( &gt;+ obj: *mut JSObject, &gt;+ length: *mut u32, &gt;+ isSharedMemory: *mut bool, &gt;+ data: *mut *mut f64, &gt;+ ); &gt; &gt;- pub fn NewJSAutoStructuredCloneBuffer(scope: JS::StructuredCloneScope, &gt;- callbacks: *const JSStructuredCloneCallbacks) &gt;- -&gt; *mut JSAutoStructuredCloneBuffer; &gt;+ pub fn NewJSAutoStructuredCloneBuffer( &gt;+ scope: JS::StructuredCloneScope, &gt;+ callbacks: *const JSStructuredCloneCallbacks, &gt;+ ) -&gt; *mut JSAutoStructuredCloneBuffer; &gt; pub fn DeleteJSAutoStructuredCloneBuffer(buf: *mut JSAutoStructuredCloneBuffer); &gt; pub fn GetLengthOfJSStructuredCloneData(data: *mut JSStructuredCloneData) -&gt; usize; &gt; pub fn CopyJSStructuredCloneData(src: *mut JSStructuredCloneData, dest: *mut u8); &gt;- pub fn WriteBytesToJSStructuredCloneData(src: *const u8, &gt;- len: usize, &gt;- dest: *mut JSStructuredCloneData) &gt;- -&gt; bool; &gt;+ pub fn WriteBytesToJSStructuredCloneData( &gt;+ src: *const u8, &gt;+ len: usize, &gt;+ dest: *mut JSStructuredCloneData, &gt;+ ) -&gt; bool; &gt; &gt; pub fn IsDebugBuild() -&gt; bool; &gt; } &gt; &gt; #[test] &gt; fn jsglue_cpp_configured_correctly() { &gt; assert_eq!(cfg!(feature = "debugmozjs"), unsafe { IsDebugBuild() }); &gt; } &gt;diff --git a/js/rust/src/heap.rs b/js/rust/src/heap.rs &gt;index 2c2fdd35025c..fc3f43d13a9c 100644 &gt;--- a/js/rust/src/heap.rs &gt;+++ b/js/rust/src/heap.rs &gt;@@ -34,83 +34,80 @@ pub unsafe trait Trace { &gt; #[repr(C)] &gt; #[derive(Debug)] &gt; pub struct Heap&lt;T: GCMethods + Copy&gt; { &gt; ptr: UnsafeCell&lt;T&gt;, &gt; } &gt; &gt; impl&lt;T: GCMethods + Copy&gt; Heap&lt;T&gt; { &gt; pub fn new(v: T) -&gt; Heap&lt;T&gt; &gt;- where Heap&lt;T&gt;: Default &gt;+ where &gt;+ Heap&lt;T&gt;: Default, &gt; { &gt; let ptr = Heap::default(); &gt; ptr.set(v); &gt; ptr &gt; } &gt; &gt; pub fn set(&amp;self, v: T) { &gt; unsafe { &gt; let ptr = self.ptr.get(); &gt; let prev = *ptr; &gt; *ptr = v; &gt; T::post_barrier(ptr, prev, v); &gt; } &gt; } &gt; &gt; pub fn get(&amp;self) -&gt; T { &gt;- unsafe { &gt;- *self.ptr.get() &gt;- } &gt;+ unsafe { *self.ptr.get() } &gt; } &gt; &gt; pub unsafe fn get_unsafe(&amp;self) -&gt; *mut T { &gt; self.ptr.get() &gt; } &gt; &gt; pub fn handle(&amp;self) -&gt; JS::Handle&lt;T&gt; { &gt;- unsafe { &gt;- JS::Handle::from_marked_location(self.ptr.get() as *const _) &gt;- } &gt;+ unsafe { JS::Handle::from_marked_location(self.ptr.get() as *const _) } &gt; } &gt; &gt; pub fn handle_mut(&amp;self) -&gt; JS::MutableHandle&lt;T&gt; { &gt;- unsafe { &gt;- JS::MutableHandle::from_marked_location(self.ptr.get()) &gt;- } &gt;+ unsafe { JS::MutableHandle::from_marked_location(self.ptr.get()) } &gt; } &gt; } &gt; &gt; impl&lt;T: GCMethods + Copy&gt; Clone for Heap&lt;T&gt; &gt;- where Heap&lt;T&gt;: Default &gt;+where &gt;+ Heap&lt;T&gt;: Default, &gt; { &gt; fn clone(&amp;self) -&gt; Self { &gt; Heap::new(self.get()) &gt; } &gt; } &gt; &gt; impl&lt;T: GCMethods + Copy + PartialEq&gt; PartialEq for Heap&lt;T&gt; { &gt; fn eq(&amp;self, other: &amp;Self) -&gt; bool { &gt; self.get() == other.get() &gt; } &gt; } &gt; &gt; impl&lt;T&gt; Default for Heap&lt;*mut T&gt; &gt;- where *mut T: GCMethods + Copy &gt;+where &gt;+ *mut T: GCMethods + Copy, &gt; { &gt; fn default() -&gt; Heap&lt;*mut T&gt; { &gt; Heap { &gt;- ptr: UnsafeCell::new(ptr::null_mut()) &gt;+ ptr: UnsafeCell::new(ptr::null_mut()), &gt; } &gt; } &gt; } &gt; &gt; impl Default for Heap&lt;JS::Value&gt; { &gt; fn default() -&gt; Heap&lt;JS::Value&gt; { &gt; Heap { &gt;- ptr: UnsafeCell::new(JS::Value::default()) &gt;+ ptr: UnsafeCell::new(JS::Value::default()), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;T: GCMethods + Copy&gt; Drop for Heap&lt;T&gt; { &gt; fn drop(&amp;mut self) { &gt; unsafe { &gt; let prev = self.ptr.get(); &gt;@@ -118,17 +115,17 @@ impl&lt;T: GCMethods + Copy&gt; Drop for Heap&lt;T&gt; { &gt; } &gt; } &gt; } &gt; &gt; // Creates a C string literal `$str`. &gt; macro_rules! c_str { &gt; ($str:expr) =&gt; { &gt; concat!($str, "\0").as_ptr() as *const ::std::os::raw::c_char &gt;- } &gt;+ }; &gt; } &gt; &gt; unsafe impl Trace for Heap&lt;*mut JSFunction&gt; { &gt; unsafe fn trace(&amp;self, trc: *mut JSTracer) { &gt; glue::CallFunctionTracer(trc, self as *const _ as *mut Self, c_str!("function")); &gt; } &gt; } &gt; &gt;diff --git a/js/rust/src/jsval.rs b/js/rust/src/jsval.rs &gt;index ac9e42647494..f3a388605a03 100644 &gt;--- a/js/rust/src/jsval.rs &gt;+++ b/js/rust/src/jsval.rs &gt;@@ -1,13 +1,12 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this file, &gt; * You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt;- &gt; use jsapi::root::*; &gt; use libc::c_void; &gt; use std::mem; &gt; &gt; #[cfg(target_pointer_width = "64")] &gt; const JSVAL_TAG_SHIFT: usize = 47; &gt; &gt; #[cfg(target_pointer_width = "64")] &gt;@@ -16,73 +15,70 @@ const JSVAL_TAG_MAX_DOUBLE: u32 = 0x1FFF0u32; &gt; #[cfg(target_pointer_width = "32")] &gt; const JSVAL_TAG_CLEAR: u32 = 0xFFFFFF80; &gt; &gt; #[cfg(target_pointer_width = "64")] &gt; #[repr(u32)] &gt; #[allow(dead_code)] &gt; #[derive(Clone, Copy, Debug)] &gt; enum ValueTag { &gt;- INT32 = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_INT32 as u32), &gt;+ INT32 = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_INT32 as u32), &gt; UNDEFINED = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_UNDEFINED as u32), &gt;- STRING = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_STRING as u32), &gt;- SYMBOL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_SYMBOL as u32), &gt;+ STRING = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_STRING as u32), &gt;+ SYMBOL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_SYMBOL as u32), &gt; #[cfg(feature = "bigint")] &gt;- BIGINT = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BIGINT as u32), &gt;- BOOLEAN = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BOOLEAN as u32), &gt;- MAGIC = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_MAGIC as u32), &gt;- NULL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_NULL as u32), &gt;- OBJECT = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_OBJECT as u32), &gt;+ BIGINT = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BIGINT as u32), &gt;+ BOOLEAN = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_BOOLEAN as u32), &gt;+ MAGIC = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_MAGIC as u32), &gt;+ NULL = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_NULL as u32), &gt;+ OBJECT = JSVAL_TAG_MAX_DOUBLE | (JSValueType::JSVAL_TYPE_OBJECT as u32), &gt; } &gt; &gt; #[cfg(target_pointer_width = "32")] &gt; #[repr(u32)] &gt; #[allow(dead_code)] &gt; #[derive(Clone, Copy, Debug)] &gt; enum ValueTag { &gt;- PRIVATE = 0, &gt;- INT32 = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_INT32 as u32), &gt;+ PRIVATE = 0, &gt;+ INT32 = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_INT32 as u32), &gt; UNDEFINED = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_UNDEFINED as u32), &gt;- STRING = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_STRING as u32), &gt;- SYMBOL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_SYMBOL as u32), &gt;+ STRING = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_STRING as u32), &gt;+ SYMBOL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_SYMBOL as u32), &gt; #[cfg(feature = "bigint")] &gt;- BIGINT = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BIGINT as u32), &gt;- BOOLEAN = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BOOLEAN as u32), &gt;- MAGIC = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_MAGIC as u32), &gt;- NULL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_NULL as u32), &gt;- OBJECT = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_OBJECT as u32), &gt;+ BIGINT = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BIGINT as u32), &gt;+ BOOLEAN = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_BOOLEAN as u32), &gt;+ MAGIC = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_MAGIC as u32), &gt;+ NULL = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_NULL as u32), &gt;+ OBJECT = JSVAL_TAG_CLEAR as u32 | (JSValueType::JSVAL_TYPE_OBJECT as u32), &gt; } &gt; &gt; #[cfg(target_pointer_width = "64")] &gt; #[repr(u64)] &gt; #[allow(dead_code)] &gt; #[derive(Clone, Copy, Debug)] &gt; enum ValueShiftedTag { &gt; MAX_DOUBLE = (((JSVAL_TAG_MAX_DOUBLE as u64) &lt;&lt; JSVAL_TAG_SHIFT) | 0xFFFFFFFFu64), &gt;- INT32 = ((ValueTag::INT32 as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;- UNDEFINED = ((ValueTag::UNDEFINED as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;- STRING = ((ValueTag::STRING as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;- SYMBOL = ((ValueTag::SYMBOL as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;+ INT32 = ((ValueTag::INT32 as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;+ UNDEFINED = ((ValueTag::UNDEFINED as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;+ STRING = ((ValueTag::STRING as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;+ SYMBOL = ((ValueTag::SYMBOL as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt; #[cfg(feature = "bigint")] &gt;- BIGINT = ((ValueTag::BIGINT as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;- BOOLEAN = ((ValueTag::BOOLEAN as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;- MAGIC = ((ValueTag::MAGIC as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;- NULL = ((ValueTag::NULL as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;- OBJECT = ((ValueTag::OBJECT as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;+ BIGINT = ((ValueTag::BIGINT as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;+ BOOLEAN = ((ValueTag::BOOLEAN as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;+ MAGIC = ((ValueTag::MAGIC as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;+ NULL = ((ValueTag::NULL as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt;+ OBJECT = ((ValueTag::OBJECT as u64) &lt;&lt; JSVAL_TAG_SHIFT), &gt; } &gt; &gt;- &gt; #[cfg(target_pointer_width = "64")] &gt; const JSVAL_PAYLOAD_MASK: u64 = 0x00007FFFFFFFFFFF; &gt; &gt; #[inline(always)] &gt; fn AsJSVal(val: u64) -&gt; JS::Value { &gt;- JS::Value { &gt;- asBits_: val, &gt;- } &gt;+ JS::Value { asBits_: val } &gt; } &gt; &gt; #[cfg(target_pointer_width = "64")] &gt; #[inline(always)] &gt; fn BuildJSVal(tag: ValueTag, payload: u64) -&gt; JS::Value { &gt; AsJSVal(((tag as u32 as u64) &lt;&lt; JSVAL_TAG_SHIFT) | payload) &gt; } &gt; &gt;@@ -214,225 +210,177 @@ impl JS::Value { &gt; #[inline(always)] &gt; unsafe fn asBits(&amp;self) -&gt; u64 { &gt; self.asBits_ &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_undefined(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- self.asBits() == ValueShiftedTag::UNDEFINED as u64 &gt;- } &gt;+ unsafe { self.asBits() == ValueShiftedTag::UNDEFINED as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_undefined(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) == ValueTag::UNDEFINED as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) == ValueTag::UNDEFINED as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_null(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- self.asBits() == ValueShiftedTag::NULL as u64 &gt;- } &gt;+ unsafe { self.asBits() == ValueShiftedTag::NULL as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_null(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) == ValueTag::NULL as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) == ValueTag::NULL as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; pub fn is_null_or_undefined(&amp;self) -&gt; bool { &gt; self.is_null() || self.is_undefined() &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_boolean(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; JSVAL_TAG_SHIFT) == ValueTag::BOOLEAN as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; JSVAL_TAG_SHIFT) == ValueTag::BOOLEAN as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_boolean(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) == ValueTag::BOOLEAN as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) == ValueTag::BOOLEAN as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_int32(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; JSVAL_TAG_SHIFT) == ValueTag::INT32 as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; JSVAL_TAG_SHIFT) == ValueTag::INT32 as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_int32(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) == ValueTag::INT32 as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) == ValueTag::INT32 as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_double(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- self.asBits() &lt;= ValueShiftedTag::MAX_DOUBLE as u64 &gt;- } &gt;+ unsafe { self.asBits() &lt;= ValueShiftedTag::MAX_DOUBLE as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_double(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) &lt;= JSVAL_TAG_CLEAR as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) &lt;= JSVAL_TAG_CLEAR as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_number(&amp;self) -&gt; bool { &gt; const JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET: u64 = ValueShiftedTag::UNDEFINED as u64; &gt;- unsafe { &gt;- self.asBits() &lt; JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET &gt;- } &gt;+ unsafe { self.asBits() &lt; JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_number(&amp;self) -&gt; bool { &gt; const JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET: u64 = ValueTag::INT32 as u64; &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) &lt;= JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) &lt;= JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_primitive(&amp;self) -&gt; bool { &gt; const JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET: u64 = ValueShiftedTag::OBJECT as u64; &gt;- unsafe { &gt;- self.asBits() &lt; JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET &gt;- } &gt;+ unsafe { self.asBits() &lt; JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_primitive(&amp;self) -&gt; bool { &gt; const JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET: u64 = ValueTag::OBJECT as u64; &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) &lt; JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) &lt; JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_string(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; JSVAL_TAG_SHIFT) == ValueTag::STRING as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; JSVAL_TAG_SHIFT) == ValueTag::STRING as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_string(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) == ValueTag::STRING as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) == ValueTag::STRING as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_object(&amp;self) -&gt; bool { &gt; unsafe { &gt; assert!((self.asBits() &gt;&gt; JSVAL_TAG_SHIFT) &lt;= ValueTag::OBJECT as u64); &gt; self.asBits() &gt;= ValueShiftedTag::OBJECT as u64 &gt; } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_object(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) == ValueTag::OBJECT as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) == ValueTag::OBJECT as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_symbol(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; JSVAL_TAG_SHIFT) == ValueTag::SYMBOL as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; JSVAL_TAG_SHIFT) == ValueTag::SYMBOL as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_symbol(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) == ValueTag::SYMBOL as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) == ValueTag::SYMBOL as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(feature = "bigint")] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_bigint(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; JSVAL_TAG_SHIFT) == ValueTag::BIGINT as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; JSVAL_TAG_SHIFT) == ValueTag::BIGINT as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(feature = "bigint")] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_bigint(&amp;self) -&gt; bool { &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) == ValueTag::BIGINT as u64 &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) == ValueTag::BIGINT as u64 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn to_boolean(&amp;self) -&gt; bool { &gt; assert!(self.is_boolean()); &gt;- unsafe { &gt;- (self.asBits() &amp; JSVAL_PAYLOAD_MASK) != 0 &gt;- } &gt;+ unsafe { (self.asBits() &amp; JSVAL_PAYLOAD_MASK) != 0 } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn to_boolean(&amp;self) -&gt; bool { &gt; assert!(self.is_boolean()); &gt;- unsafe { &gt;- (self.asBits() &amp; 0x00000000FFFFFFFF) != 0 &gt;- } &gt;+ unsafe { (self.asBits() &amp; 0x00000000FFFFFFFF) != 0 } &gt; } &gt; &gt; #[inline(always)] &gt; pub fn to_int32(&amp;self) -&gt; i32 { &gt; assert!(self.is_int32()); &gt;- unsafe { &gt;- (self.asBits() &amp; 0x00000000FFFFFFFF) as i32 &gt;- } &gt;+ unsafe { (self.asBits() &amp; 0x00000000FFFFFFFF) as i32 } &gt; } &gt; &gt; #[inline(always)] &gt; pub fn to_double(&amp;self) -&gt; f64 { &gt; assert!(self.is_double()); &gt; unsafe { mem::transmute(self.asBits()) } &gt; } &gt; &gt;@@ -531,28 +479,24 @@ impl JS::Value { &gt; ptrBits as *const c_void &gt; } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn is_gcthing(&amp;self) -&gt; bool { &gt; const JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET: u64 = ValueShiftedTag::STRING as u64; &gt;- unsafe { &gt;- self.asBits() &gt;= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET &gt;- } &gt;+ unsafe { self.asBits() &gt;= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "32")] &gt; pub fn is_gcthing(&amp;self) -&gt; bool { &gt; const JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET: u64 = ValueTag::STRING as u64; &gt;- unsafe { &gt;- (self.asBits() &gt;&gt; 32) &gt;= JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET &gt;- } &gt;+ unsafe { (self.asBits() &gt;&gt; 32) &gt;= JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET } &gt; } &gt; &gt; #[inline(always)] &gt; #[cfg(target_pointer_width = "64")] &gt; pub fn to_gcthing(&amp;self) -&gt; *mut c_void { &gt; assert!(self.is_gcthing()); &gt; unsafe { &gt; let ptrBits = self.asBits() &amp; JSVAL_PAYLOAD_MASK; &gt;diff --git a/js/rust/src/lib.rs b/js/rust/src/lib.rs &gt;index f8df9ea31d60..453078647c97 100644 &gt;--- a/js/rust/src/lib.rs &gt;+++ b/js/rust/src/lib.rs &gt;@@ -1,18 +1,21 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this file, &gt; * You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; #![crate_name = "js"] &gt; #![crate_type = "rlib"] &gt;- &gt; #![cfg_attr(feature = "nonzero", feature(nonzero))] &gt;- &gt;-#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes)] &gt;+#![allow( &gt;+ non_upper_case_globals, &gt;+ non_camel_case_types, &gt;+ non_snake_case, &gt;+ improper_ctypes &gt;+)] &gt; &gt; #[cfg(feature = "nonzero")] &gt; extern crate core; &gt; #[macro_use] &gt; extern crate lazy_static; &gt; extern crate libc; &gt; #[macro_use] &gt; extern crate log; &gt;diff --git a/js/rust/src/panic.rs b/js/rust/src/panic.rs &gt;index 351e24f77350..496ed9b33d4d 100644 &gt;--- a/js/rust/src/panic.rs &gt;+++ b/js/rust/src/panic.rs &gt;@@ -1,28 +1,29 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; use std::any::Any; &gt; use std::cell::RefCell; &gt;-use std::panic::{UnwindSafe, catch_unwind, resume_unwind}; &gt;+use std::panic::{catch_unwind, resume_unwind, UnwindSafe}; &gt; &gt; thread_local!(static PANIC_RESULT: RefCell&lt;Option&lt;Box&lt;Any + Send&gt;&gt;&gt; = RefCell::new(None)); &gt; &gt; /// If there is a pending panic, resume unwinding. &gt; pub fn maybe_resume_unwind() { &gt; if let Some(error) = PANIC_RESULT.with(|result| result.borrow_mut().take()) { &gt; resume_unwind(error); &gt; } &gt; } &gt; &gt; /// Generic wrapper for JS engine callbacks panic-catching &gt; pub fn wrap_panic&lt;F, R&gt;(function: F, generic_return_type: R) -&gt; R &gt;- where F: FnOnce() -&gt; R + UnwindSafe &gt;+where &gt;+ F: FnOnce() -&gt; R + UnwindSafe, &gt; { &gt; let result = catch_unwind(function); &gt; match result { &gt; Ok(result) =&gt; result, &gt; Err(error) =&gt; { &gt; PANIC_RESULT.with(|result| { &gt; assert!(result.borrow().is_none()); &gt; *result.borrow_mut() = Some(error); &gt;diff --git a/js/rust/src/rust.rs b/js/rust/src/rust.rs &gt;index 69993caac787..1bb530550731 100644 &gt;--- a/js/rust/src/rust.rs &gt;+++ b/js/rust/src/rust.rs &gt;@@ -1,36 +1,39 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this file, &gt; * You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Rust wrappers around the raw JS apis &gt; &gt; use ac::AutoCompartment; &gt;+use glue::{ &gt;+ AppendToAutoObjectVector, CreateAutoObjectVector, CreateCallArgsFromVp, DeleteAutoObjectVector, &gt;+ IsDebugBuild, &gt;+}; &gt;+use glue::{CreateAutoIdVector, DestroyAutoIdVector, SliceAutoIdVector}; &gt;+use glue::{DeleteCompileOptions, NewCompileOptions}; &gt;+use jsapi::root::*; &gt;+use jsval::{self, UndefinedValue}; &gt; use libc::c_uint; &gt;+use panic; &gt; use std::cell::{Cell, UnsafeCell}; &gt; use std::char; &gt;-use std::ffi; &gt;-use std::ptr; &gt;-use std::slice; &gt;-use std::mem; &gt;-use std::u32; &gt; use std::default::Default; &gt;+use std::ffi; &gt; use std::marker; &gt;+use std::mem; &gt; use std::ops::{Deref, DerefMut}; &gt;-use std::sync::{Once, ONCE_INIT, Arc, Mutex}; &gt;+use std::ptr; &gt;+use std::slice; &gt; use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicUsize, Ordering}; &gt;-use std::sync::mpsc::{SyncSender, sync_channel}; &gt;+use std::sync::mpsc::{sync_channel, SyncSender}; &gt;+use std::sync::{Arc, Mutex, Once, ONCE_INIT}; &gt; use std::thread; &gt;-use jsapi::root::*; &gt;-use jsval::{self, UndefinedValue}; &gt;-use glue::{CreateAutoObjectVector, CreateCallArgsFromVp, AppendToAutoObjectVector, DeleteAutoObjectVector, IsDebugBuild}; &gt;-use glue::{CreateAutoIdVector, SliceAutoIdVector, DestroyAutoIdVector}; &gt;-use glue::{NewCompileOptions, DeleteCompileOptions}; &gt;-use panic; &gt;+use std::u32; &gt; &gt; const DEFAULT_HEAPSIZE: u32 = 32_u32 * 1024_u32 * 1024_u32; &gt; &gt; // From Gecko: &gt; // Our "default" stack is what we use in configurations where we don't have a compelling reason to &gt; // do things differently. This is effectively 1MB on 64-bit platforms. &gt; const STACK_QUOTA: usize = 128 * 8 * 1024; &gt; &gt;@@ -72,19 +75,17 @@ lazy_static! { &gt; /// A wrapper for the `JSContext` structure in SpiderMonkey. &gt; pub struct Runtime { &gt; cx: *mut JSContext, &gt; } &gt; &gt; impl Runtime { &gt; /// Get the `JSContext` for this thread. &gt; pub fn get() -&gt; *mut JSContext { &gt;- let cx = CONTEXT.with(|context| { &gt;- context.get() &gt;- }); &gt;+ let cx = CONTEXT.with(|context| context.get()); &gt; assert!(!cx.is_null()); &gt; cx &gt; } &gt; &gt; /// Creates a new `JSContext`. &gt; /// &gt; /// * `use_internal_job_queue`: If `true`, then SpiderMonkey's internal &gt; /// micro-task job queue is used. If `false`, then it is up to you to &gt;@@ -107,19 +108,17 @@ impl Runtime { &gt; assert_eq!(self.get(), val); &gt; } &gt; &gt; fn get(&amp;self) -&gt; *mut JSContext { &gt; self.as_atomic().load(Ordering::SeqCst) &gt; } &gt; &gt; fn as_atomic(&amp;self) -&gt; &amp;AtomicPtr&lt;JSContext&gt; { &gt;- unsafe { &gt;- mem::transmute(&amp;self.0) &gt;- } &gt;+ unsafe { mem::transmute(&amp;self.0) } &gt; } &gt; } &gt; &gt; lazy_static! { &gt; static ref PARENT: Parent = Parent(UnsafeCell::new(0 as *mut _)); &gt; } &gt; static ONCE: Once = ONCE_INIT; &gt; &gt;@@ -127,22 +126,24 @@ impl Runtime { &gt; // There is a 1:1 relationship between threads and JSContexts, &gt; // so we must spawn a new thread for the parent context. &gt; let (tx, rx) = sync_channel(0); &gt; *SHUT_DOWN_SIGNAL.lock().unwrap() = Some(tx); &gt; let _ = thread::spawn(move || { &gt; let is_debug_mozjs = cfg!(feature = "debugmozjs"); &gt; let diagnostic = JS::detail::InitWithFailureDiagnostic(is_debug_mozjs); &gt; if !diagnostic.is_null() { &gt;- panic!("JS::detail::InitWithFailureDiagnostic failed: {}", &gt;- ffi::CStr::from_ptr(diagnostic).to_string_lossy()); &gt;+ panic!( &gt;+ "JS::detail::InitWithFailureDiagnostic failed: {}", &gt;+ ffi::CStr::from_ptr(diagnostic).to_string_lossy() &gt;+ ); &gt; } &gt; &gt;- let context = JS_NewContext( &gt;- DEFAULT_HEAPSIZE, ChunkSize as u32, ptr::null_mut()); &gt;+ let context = &gt;+ JS_NewContext(DEFAULT_HEAPSIZE, ChunkSize as u32, ptr::null_mut()); &gt; assert!(!context.is_null()); &gt; JS::InitSelfHostedCode(context); &gt; PARENT.set(context); &gt; &gt; // The last JSRuntime child died, resume the execution by destroying the parent. &gt; rx.recv().unwrap(); &gt; let cx = PARENT.get(); &gt; JS_DestroyContext(cx); &gt;@@ -154,34 +155,36 @@ impl Runtime { &gt; &gt; while PARENT.get().is_null() { &gt; thread::yield_now(); &gt; } &gt; }); &gt; &gt; assert_eq!(IsDebugBuild(), cfg!(feature = "debugmozjs")); &gt; &gt;- let js_context = JS_NewContext(DEFAULT_HEAPSIZE, &gt;- ChunkSize as u32, &gt;- JS_GetParentRuntime(PARENT.get())); &gt;+ let js_context = JS_NewContext( &gt;+ DEFAULT_HEAPSIZE, &gt;+ ChunkSize as u32, &gt;+ JS_GetParentRuntime(PARENT.get()), &gt;+ ); &gt; assert!(!js_context.is_null()); &gt; &gt; // Unconstrain the runtime's threshold on nominal heap size, to avoid &gt; // triggering GC too often if operating continuously near an arbitrary &gt; // finite threshold. This leaves the maximum-JS_malloc-bytes threshold &gt; // still in effect to cause periodical, and we hope hygienic, &gt; // last-ditch GCs from within the GC's allocator. &gt;- JS_SetGCParameter( &gt;- js_context, JSGCParamKey::JSGC_MAX_BYTES, u32::MAX); &gt;+ JS_SetGCParameter(js_context, JSGCParamKey::JSGC_MAX_BYTES, u32::MAX); &gt; &gt; JS_SetNativeStackQuota( &gt; js_context, &gt; STACK_QUOTA, &gt; STACK_QUOTA - SYSTEM_CODE_BUFFER, &gt;- STACK_QUOTA - SYSTEM_CODE_BUFFER - TRUSTED_SCRIPT_BUFFER); &gt;+ STACK_QUOTA - SYSTEM_CODE_BUFFER - TRUSTED_SCRIPT_BUFFER, &gt;+ ); &gt; &gt; let opts = JS::ContextOptionsRef(js_context); &gt; (*opts).set_baseline_(true); &gt; (*opts).set_ion_(true); &gt; (*opts).set_nativeRegExp_(true); &gt; &gt; CONTEXT.with(|context| { &gt; assert!(context.get().is_null()); &gt;@@ -193,56 +196,60 @@ impl Runtime { &gt; } &gt; &gt; JS::InitSelfHostedCode(js_context); &gt; &gt; JS::SetWarningReporter(js_context, Some(report_warning)); &gt; &gt; JS_BeginRequest(js_context); &gt; &gt;- Ok(Runtime { &gt;- cx: js_context, &gt;- }) &gt;+ Ok(Runtime { cx: js_context }) &gt; } &gt; } &gt; &gt; /// Returns the underlying `JSContext` object. &gt; pub fn cx(&amp;self) -&gt; *mut JSContext { &gt; self.cx &gt; } &gt; &gt; /// Returns the underlying `JSContext`'s `JSRuntime`. &gt; pub fn rt(&amp;self) -&gt; *mut JSRuntime { &gt;- unsafe { &gt;- JS_GetRuntime(self.cx) &gt;- } &gt;+ unsafe { JS_GetRuntime(self.cx) } &gt; } &gt; &gt;- pub fn evaluate_script(&amp;self, glob: JS::HandleObject, script: &amp;str, filename: &amp;str, &gt;- line_num: u32, rval: JS::MutableHandleValue) &gt;- -&gt; Result&lt;(),()&gt; { &gt;+ pub fn evaluate_script( &gt;+ &amp;self, &gt;+ glob: JS::HandleObject, &gt;+ script: &amp;str, &gt;+ filename: &amp;str, &gt;+ line_num: u32, &gt;+ rval: JS::MutableHandleValue, &gt;+ ) -&gt; Result&lt;(), ()&gt; { &gt; let script_utf16: Vec&lt;u16&gt; = script.encode_utf16().collect(); &gt; let filename_cstr = ffi::CString::new(filename.as_bytes()).unwrap(); &gt;- debug!("Evaluating script from {} with content {}", filename, script); &gt;+ debug!( &gt;+ "Evaluating script from {} with content {}", &gt;+ filename, script &gt;+ ); &gt; // SpiderMonkey does not approve of null pointers. &gt; let (ptr, len) = if script_utf16.len() == 0 { &gt; static empty: &amp;'static [u16] = &amp;[]; &gt; (empty.as_ptr(), 0) &gt; } else { &gt; (script_utf16.as_ptr(), script_utf16.len() as c_uint) &gt; }; &gt; assert!(!ptr.is_null()); &gt; unsafe { &gt; let _ac = AutoCompartment::with_obj(self.cx(), glob.get()); &gt; let options = CompileOptionsWrapper::new(self.cx(), filename_cstr.as_ptr(), line_num); &gt; &gt; let mut srcBuf = JS::SourceBufferHolder { &gt; data_: ptr, &gt; length_: len as _, &gt;- ownsChars_: false &gt;+ ownsChars_: false, &gt; }; &gt; if !JS::Evaluate(self.cx(), options.ptr, &amp;mut srcBuf, rval) { &gt; debug!("...err!"); &gt; panic::maybe_resume_unwind(); &gt; Err(()) &gt; } else { &gt; // we could return the script result but then we'd have &gt; // to root it and so forth and, really, who cares? &gt;@@ -283,87 +290,109 @@ impl Drop for Runtime { &gt; &gt; pub trait RootKind { &gt; #[inline(always)] &gt; fn rootKind() -&gt; JS::RootKind; &gt; } &gt; &gt; impl RootKind for *mut JSObject { &gt; #[inline(always)] &gt;- fn rootKind() -&gt; JS::RootKind { JS::RootKind::Object } &gt;+ fn rootKind() -&gt; JS::RootKind { &gt;+ JS::RootKind::Object &gt;+ } &gt; } &gt; &gt; impl RootKind for *mut JSFlatString { &gt; #[inline(always)] &gt;- fn rootKind() -&gt; JS::RootKind { JS::RootKind::String } &gt;+ fn rootKind() -&gt; JS::RootKind { &gt;+ JS::RootKind::String &gt;+ } &gt; } &gt; &gt; impl RootKind for *mut JSFunction { &gt; #[inline(always)] &gt;- fn rootKind() -&gt; JS::RootKind { JS::RootKind::Object } &gt;+ fn rootKind() -&gt; JS::RootKind { &gt;+ JS::RootKind::Object &gt;+ } &gt; } &gt; &gt; impl RootKind for *mut JSString { &gt; #[inline(always)] &gt;- fn rootKind() -&gt; JS::RootKind { JS::RootKind::String } &gt;+ fn rootKind() -&gt; JS::RootKind { &gt;+ JS::RootKind::String &gt;+ } &gt; } &gt; &gt; impl RootKind for *mut JS::Symbol { &gt; #[inline(always)] &gt;- fn rootKind() -&gt; JS::RootKind { JS::RootKind::Symbol } &gt;+ fn rootKind() -&gt; JS::RootKind { &gt;+ JS::RootKind::Symbol &gt;+ } &gt; } &gt; &gt; #[cfg(feature = "bigint")] &gt; impl RootKind for *mut JS::BigInt { &gt; #[inline(always)] &gt;- fn rootKind() -&gt; JS::RootKind { JS::RootKind::BigInt } &gt;+ fn rootKind() -&gt; JS::RootKind { &gt;+ JS::RootKind::BigInt &gt;+ } &gt; } &gt; &gt; impl RootKind for *mut JSScript { &gt; #[inline(always)] &gt;- fn rootKind() -&gt; JS::RootKind { JS::RootKind::Script } &gt;+ fn rootKind() -&gt; JS::RootKind { &gt;+ JS::RootKind::Script &gt;+ } &gt; } &gt; &gt; impl RootKind for jsid { &gt; #[inline(always)] &gt;- fn rootKind() -&gt; JS::RootKind { JS::RootKind::Id } &gt;+ fn rootKind() -&gt; JS::RootKind { &gt;+ JS::RootKind::Id &gt;+ } &gt; } &gt; &gt; impl RootKind for JS::Value { &gt; #[inline(always)] &gt;- fn rootKind() -&gt; JS::RootKind { JS::RootKind::Value } &gt;+ fn rootKind() -&gt; JS::RootKind { &gt;+ JS::RootKind::Value &gt;+ } &gt; } &gt; &gt; impl&lt;T&gt; JS::Rooted&lt;T&gt; { &gt; pub fn new_unrooted() -&gt; JS::Rooted&lt;T&gt; &gt;- where T: GCMethods, &gt;+ where &gt;+ T: GCMethods, &gt; { &gt; JS::Rooted { &gt; stack: ptr::null_mut(), &gt; prev: ptr::null_mut(), &gt; ptr: unsafe { T::initial() }, &gt; _phantom_0: marker::PhantomData, &gt; } &gt; } &gt; &gt; unsafe fn get_rooting_context(cx: *mut JSContext) -&gt; *mut JS::RootingContext { &gt; mem::transmute(cx) &gt; } &gt; &gt;- unsafe fn get_root_stack(cx: *mut JSContext) &gt;- -&gt; *mut *mut JS::Rooted&lt;*mut ::std::os::raw::c_void&gt; &gt;- where T: RootKind &gt;+ unsafe fn get_root_stack( &gt;+ cx: *mut JSContext, &gt;+ ) -&gt; *mut *mut JS::Rooted&lt;*mut ::std::os::raw::c_void&gt; &gt;+ where &gt;+ T: RootKind, &gt; { &gt; let kind = T::rootKind() as usize; &gt; let rooting_cx = Self::get_rooting_context(cx); &gt; &amp;mut rooting_cx.as_mut().unwrap().stackRoots_[kind] as *mut _ as *mut _ &gt; } &gt; &gt; pub unsafe fn register_with_root_lists(&amp;mut self, cx: *mut JSContext) &gt;- where T: RootKind &gt;+ where &gt;+ T: RootKind, &gt; { &gt; self.stack = Self::get_root_stack(cx); &gt; let stack = self.stack.as_mut().unwrap(); &gt; self.prev = *stack as *mut _; &gt; &gt; *stack = self as *mut _ as usize as _; &gt; } &gt; &gt;@@ -372,43 +401,40 @@ impl&lt;T&gt; JS::Rooted&lt;T&gt; { &gt; *self.stack = self.prev; &gt; } &gt; } &gt; &gt; /// Rust API for keeping a JS::Rooted value in the context's root stack. &gt; /// Example usage: `rooted!(in(cx) let x = UndefinedValue());`. &gt; /// `RootedGuard::new` also works, but the macro is preferred. &gt; pub struct RootedGuard&lt;'a, T: 'a + RootKind + GCMethods&gt; { &gt;- root: &amp;'a mut JS::Rooted&lt;T&gt; &gt;+ root: &amp;'a mut JS::Rooted&lt;T&gt;, &gt; } &gt; &gt; impl&lt;'a, T: 'a + RootKind + GCMethods&gt; RootedGuard&lt;'a, T&gt; { &gt; pub fn new(cx: *mut JSContext, root: &amp;'a mut JS::Rooted&lt;T&gt;, initial: T) -&gt; Self { &gt; root.ptr = initial; &gt; unsafe { &gt; root.register_with_root_lists(cx); &gt; } &gt;- RootedGuard { &gt;- root: root &gt;- } &gt;+ RootedGuard { root: root } &gt; } &gt; &gt; pub fn handle(&amp;self) -&gt; JS::Handle&lt;T&gt; { &gt;- unsafe { &gt;- JS::Handle::from_marked_location(&amp;self.root.ptr) &gt;- } &gt;+ unsafe { JS::Handle::from_marked_location(&amp;self.root.ptr) } &gt; } &gt; &gt; pub fn handle_mut(&amp;mut self) -&gt; JS::MutableHandle&lt;T&gt; { &gt;- unsafe { &gt;- JS::MutableHandle::from_marked_location(&amp;mut self.root.ptr) &gt;- } &gt;+ unsafe { JS::MutableHandle::from_marked_location(&amp;mut self.root.ptr) } &gt; } &gt; &gt;- pub fn get(&amp;self) -&gt; T where T: Copy { &gt;+ pub fn get(&amp;self) -&gt; T &gt;+ where &gt;+ T: Copy, &gt;+ { &gt; self.root.ptr &gt; } &gt; &gt; pub fn set(&amp;mut self, v: T) { &gt; self.root.ptr = v; &gt; } &gt; } &gt; &gt;@@ -438,22 +464,23 @@ impl&lt;'a, T: 'a + RootKind + GCMethods&gt; Drop for RootedGuard&lt;'a, T&gt; { &gt; macro_rules! rooted { &gt; (in($cx:expr) let $name:ident = $init:expr) =&gt; { &gt; let mut __root = $crate::jsapi::JS::Rooted::new_unrooted(); &gt; let $name = $crate::rust::RootedGuard::new($cx, &amp;mut __root, $init); &gt; }; &gt; (in($cx:expr) let mut $name:ident = $init:expr) =&gt; { &gt; let mut __root = $crate::jsapi::JS::Rooted::new_unrooted(); &gt; let mut $name = $crate::rust::RootedGuard::new($cx, &amp;mut __root, $init); &gt;- } &gt;+ }; &gt; } &gt; &gt; impl&lt;T&gt; JS::Handle&lt;T&gt; { &gt; pub fn get(&amp;self) -&gt; T &gt;- where T: Copy &gt;+ where &gt;+ T: Copy, &gt; { &gt; unsafe { *self.ptr } &gt; } &gt; &gt; pub unsafe fn from_marked_location(ptr: *const T) -&gt; JS::Handle&lt;T&gt; { &gt; JS::Handle { &gt; ptr: mem::transmute(ptr), &gt; _phantom_0: marker::PhantomData, &gt;@@ -473,29 +500,29 @@ impl&lt;T&gt; JS::MutableHandle&lt;T&gt; { &gt; pub unsafe fn from_marked_location(ptr: *mut T) -&gt; JS::MutableHandle&lt;T&gt; { &gt; JS::MutableHandle { &gt; ptr: ptr, &gt; _phantom_0: marker::PhantomData, &gt; } &gt; } &gt; &gt; pub fn handle(&amp;self) -&gt; JS::Handle&lt;T&gt; { &gt;- unsafe { &gt;- JS::Handle::from_marked_location(self.ptr as *const _) &gt;- } &gt;+ unsafe { JS::Handle::from_marked_location(self.ptr as *const _) } &gt; } &gt; &gt; pub fn get(&amp;self) -&gt; T &gt;- where T: Copy &gt;+ where &gt;+ T: Copy, &gt; { &gt; unsafe { *self.ptr } &gt; } &gt; &gt; pub fn set(&amp;self, v: T) &gt;- where T: Copy &gt;+ where &gt;+ T: Copy, &gt; { &gt; unsafe { *self.ptr = v } &gt; } &gt; } &gt; &gt; impl&lt;T&gt; Deref for JS::MutableHandle&lt;T&gt; { &gt; type Target = T; &gt; &gt;@@ -507,127 +534,139 @@ impl&lt;T&gt; Deref for JS::MutableHandle&lt;T&gt; { &gt; impl&lt;T&gt; DerefMut for JS::MutableHandle&lt;T&gt; { &gt; fn deref_mut&lt;'a&gt;(&amp;'a mut self) -&gt; &amp;'a mut T { &gt; unsafe { &amp;mut *self.ptr } &gt; } &gt; } &gt; &gt; impl JS::HandleValue { &gt; pub fn null() -&gt; JS::HandleValue { &gt;- unsafe { &gt;- JS::NullHandleValue &gt;- } &gt;+ unsafe { JS::NullHandleValue } &gt; } &gt; &gt; pub fn undefined() -&gt; JS::HandleValue { &gt;- unsafe { &gt;- JS::UndefinedHandleValue &gt;- } &gt;+ unsafe { JS::UndefinedHandleValue } &gt; } &gt; } &gt; &gt; impl JS::HandleValueArray { &gt; pub fn new() -&gt; JS::HandleValueArray { &gt; JS::HandleValueArray { &gt; length_: 0, &gt; elements_: ptr::null(), &gt; } &gt; } &gt; &gt; pub unsafe fn from_rooted_slice(values: &amp;[JS::Value]) -&gt; JS::HandleValueArray { &gt; JS::HandleValueArray { &gt; length_: values.len(), &gt;- elements_: values.as_ptr() &gt;+ elements_: values.as_ptr(), &gt; } &gt; } &gt; } &gt; &gt; const ConstNullValue: *mut JSObject = 0 as *mut JSObject; &gt; &gt; impl JS::HandleObject { &gt; pub fn null() -&gt; JS::HandleObject { &gt;- unsafe { &gt;- JS::HandleObject::from_marked_location(&amp;ConstNullValue) &gt;- } &gt;+ unsafe { JS::HandleObject::from_marked_location(&amp;ConstNullValue) } &gt; } &gt; } &gt; &gt; impl Default for jsid { &gt; fn default() -&gt; jsid { &gt; jsid { &gt; asBits: JSID_TYPE_VOID as usize, &gt; } &gt; } &gt; } &gt; &gt; impl Default for JS::Value { &gt;- fn default() -&gt; JS::Value { jsval::UndefinedValue() } &gt;+ fn default() -&gt; JS::Value { &gt;+ jsval::UndefinedValue() &gt;+ } &gt; } &gt; &gt; impl Default for JS::RealmOptions { &gt;- fn default() -&gt; Self { unsafe { ::std::mem::zeroed() } } &gt;+ fn default() -&gt; Self { &gt;+ unsafe { ::std::mem::zeroed() } &gt;+ } &gt; } &gt; &gt; const ChunkShift: usize = 20; &gt; const ChunkSize: usize = 1 &lt;&lt; ChunkShift; &gt; &gt; #[cfg(target_pointer_width = "32")] &gt; const ChunkLocationOffset: usize = ChunkSize - 2 * 4 - 8; &gt; &gt; pub trait GCMethods { &gt; unsafe fn initial() -&gt; Self; &gt; unsafe fn post_barrier(v: *mut Self, prev: Self, next: Self); &gt; } &gt; &gt; impl GCMethods for jsid { &gt;- unsafe fn initial() -&gt; jsid { Default::default() } &gt;+ unsafe fn initial() -&gt; jsid { &gt;+ Default::default() &gt;+ } &gt; unsafe fn post_barrier(_: *mut jsid, _: jsid, _: jsid) {} &gt; } &gt; &gt; impl GCMethods for *mut JSObject { &gt;- unsafe fn initial() -&gt; *mut JSObject { ptr::null_mut() } &gt;- unsafe fn post_barrier(v: *mut *mut JSObject, &gt;- prev: *mut JSObject, next: *mut JSObject) { &gt;+ unsafe fn initial() -&gt; *mut JSObject { &gt;+ ptr::null_mut() &gt;+ } &gt;+ unsafe fn post_barrier(v: *mut *mut JSObject, prev: *mut JSObject, next: *mut JSObject) { &gt; JS::HeapObjectPostBarrier(v, prev, next); &gt; } &gt; } &gt; &gt; impl GCMethods for *mut JSString { &gt;- unsafe fn initial() -&gt; *mut JSString { ptr::null_mut() } &gt;+ unsafe fn initial() -&gt; *mut JSString { &gt;+ ptr::null_mut() &gt;+ } &gt; unsafe fn post_barrier(_: *mut *mut JSString, _: *mut JSString, _: *mut JSString) {} &gt; } &gt; &gt; impl GCMethods for *mut JSScript { &gt;- unsafe fn initial() -&gt; *mut JSScript { ptr::null_mut() } &gt;- unsafe fn post_barrier(_: *mut *mut JSScript, _: *mut JSScript, _: *mut JSScript) { } &gt;+ unsafe fn initial() -&gt; *mut JSScript { &gt;+ ptr::null_mut() &gt;+ } &gt;+ unsafe fn post_barrier(_: *mut *mut JSScript, _: *mut JSScript, _: *mut JSScript) {} &gt; } &gt; &gt; impl GCMethods for *mut JSFunction { &gt;- unsafe fn initial() -&gt; *mut JSFunction { ptr::null_mut() } &gt;- unsafe fn post_barrier(v: *mut *mut JSFunction, &gt;- prev: *mut JSFunction, next: *mut JSFunction) { &gt;- JS::HeapObjectPostBarrier(mem::transmute(v), &gt;- mem::transmute(prev), &gt;- mem::transmute(next)); &gt;+ unsafe fn initial() -&gt; *mut JSFunction { &gt;+ ptr::null_mut() &gt;+ } &gt;+ unsafe fn post_barrier(v: *mut *mut JSFunction, prev: *mut JSFunction, next: *mut JSFunction) { &gt;+ JS::HeapObjectPostBarrier( &gt;+ mem::transmute(v), &gt;+ mem::transmute(prev), &gt;+ mem::transmute(next), &gt;+ ); &gt; } &gt; } &gt; &gt; impl GCMethods for JS::Value { &gt;- unsafe fn initial() -&gt; JS::Value { UndefinedValue() } &gt;+ unsafe fn initial() -&gt; JS::Value { &gt;+ UndefinedValue() &gt;+ } &gt; unsafe fn post_barrier(v: *mut JS::Value, prev: JS::Value, next: JS::Value) { &gt; JS::HeapValuePostBarrier(v, &amp;prev, &amp;next); &gt; } &gt; } &gt; &gt; // ___________________________________________________________________________ &gt; // Implementations for various things in jsapi.rs &gt; &gt; impl Drop for JSAutoRealmAllowCCW { &gt; fn drop(&amp;mut self) { &gt;- unsafe { JS::LeaveRealm(self.cx_, self.oldRealm_); } &gt;+ unsafe { &gt;+ JS::LeaveRealm(self.cx_, self.oldRealm_); &gt;+ } &gt; } &gt; } &gt; &gt; impl JSJitMethodCallArgs { &gt; #[inline] &gt; pub fn get(&amp;self, i: u32) -&gt; JS::HandleValue { &gt; unsafe { &gt; if i &lt; self._base.argc_ { &gt;@@ -636,104 +675,89 @@ impl JSJitMethodCallArgs { &gt; JS::UndefinedHandleValue &gt; } &gt; } &gt; } &gt; &gt; #[inline] &gt; pub fn index(&amp;self, i: u32) -&gt; JS::HandleValue { &gt; assert!(i &lt; self._base.argc_); &gt;- unsafe { &gt;- JS::HandleValue::from_marked_location(self._base.argv_.offset(i as isize)) &gt;- } &gt;+ unsafe { JS::HandleValue::from_marked_location(self._base.argv_.offset(i as isize)) } &gt; } &gt; &gt; #[inline] &gt; pub fn index_mut(&amp;self, i: u32) -&gt; JS::MutableHandleValue { &gt; assert!(i &lt; self._base.argc_); &gt;- unsafe { &gt;- JS::MutableHandleValue::from_marked_location(self._base.argv_.offset(i as isize)) &gt;- } &gt;+ unsafe { JS::MutableHandleValue::from_marked_location(self._base.argv_.offset(i as isize)) } &gt; } &gt; &gt; #[inline] &gt; pub fn rval(&amp;self) -&gt; JS::MutableHandleValue { &gt;- unsafe { &gt;- JS::MutableHandleValue::from_marked_location(self._base.argv_.offset(-2)) &gt;- } &gt;+ unsafe { JS::MutableHandleValue::from_marked_location(self._base.argv_.offset(-2)) } &gt; } &gt; } &gt; &gt; // XXX need to hack up bindgen to convert this better so we don't have &gt; // to duplicate so much code here &gt; impl JS::CallArgs { &gt; #[inline] &gt; pub unsafe fn from_vp(vp: *mut JS::Value, argc: u32) -&gt; JS::CallArgs { &gt; CreateCallArgsFromVp(argc, vp) &gt; } &gt; &gt; #[inline] &gt; pub fn index(&amp;self, i: u32) -&gt; JS::HandleValue { &gt; assert!(i &lt; self._base.argc_); &gt;- unsafe { &gt;- JS::HandleValue::from_marked_location(self._base.argv_.offset(i as isize)) &gt;- } &gt;+ unsafe { JS::HandleValue::from_marked_location(self._base.argv_.offset(i as isize)) } &gt; } &gt; &gt; #[inline] &gt; pub fn index_mut(&amp;self, i: u32) -&gt; JS::MutableHandleValue { &gt; assert!(i &lt; self._base.argc_); &gt;- unsafe { &gt;- JS::MutableHandleValue::from_marked_location(self._base.argv_.offset(i as isize)) &gt;- } &gt;+ unsafe { JS::MutableHandleValue::from_marked_location(self._base.argv_.offset(i as isize)) } &gt; } &gt; &gt; #[inline] &gt; pub fn get(&amp;self, i: u32) -&gt; JS::HandleValue { &gt; unsafe { &gt; if i &lt; self._base.argc_ { &gt; JS::HandleValue::from_marked_location(self._base.argv_.offset(i as isize)) &gt; } else { &gt; JS::UndefinedHandleValue &gt; } &gt; } &gt; } &gt; &gt; #[inline] &gt; pub fn rval(&amp;self) -&gt; JS::MutableHandleValue { &gt;- unsafe { &gt;- JS::MutableHandleValue::from_marked_location(self._base.argv_.offset(-2)) &gt;- } &gt;+ unsafe { JS::MutableHandleValue::from_marked_location(self._base.argv_.offset(-2)) } &gt; } &gt; &gt; #[inline] &gt; pub fn thisv(&amp;self) -&gt; JS::HandleValue { &gt;- unsafe { &gt;- JS::HandleValue::from_marked_location(self._base.argv_.offset(-1)) &gt;- } &gt;+ unsafe { JS::HandleValue::from_marked_location(self._base.argv_.offset(-1)) } &gt; } &gt; &gt; #[inline] &gt; pub fn calleev(&amp;self) -&gt; JS::HandleValue { &gt;- unsafe { &gt;- JS::HandleValue::from_marked_location(self._base.argv_.offset(-2)) &gt;- } &gt;+ unsafe { JS::HandleValue::from_marked_location(self._base.argv_.offset(-2)) } &gt; } &gt; &gt; #[inline] &gt; pub fn callee(&amp;self) -&gt; *mut JSObject { &gt; self.calleev().to_object() &gt; } &gt; &gt; #[inline] &gt; pub fn new_target(&amp;self) -&gt; JS::MutableHandleValue { &gt; assert!(self._base.constructing_()); &gt; unsafe { &gt; JS::MutableHandleValue::from_marked_location( &gt;- self._base.argv_.offset(self._base.argc_ as isize)) &gt;+ self._base.argv_.offset(self._base.argc_ as isize), &gt;+ ) &gt; } &gt; } &gt; } &gt; &gt; impl JSJitGetterCallArgs { &gt; #[inline] &gt; pub fn rval(&amp;self) -&gt; JS::MutableHandleValue { &gt; self._base &gt;@@ -747,49 +771,49 @@ impl JSJitSetterCallArgs { &gt; self._base.handle() &gt; } &gt; } &gt; &gt; // ___________________________________________________________________________ &gt; // Wrappers around things in jsglue.cpp &gt; &gt; pub struct AutoObjectVectorWrapper { &gt;- pub ptr: *mut JS::AutoObjectVector &gt;+ pub ptr: *mut JS::AutoObjectVector, &gt; } &gt; &gt; impl AutoObjectVectorWrapper { &gt; pub fn new(cx: *mut JSContext) -&gt; AutoObjectVectorWrapper { &gt; AutoObjectVectorWrapper { &gt;- ptr: unsafe { &gt;- CreateAutoObjectVector(cx) &gt;- } &gt;+ ptr: unsafe { CreateAutoObjectVector(cx) }, &gt; } &gt; } &gt; &gt; pub fn append(&amp;self, obj: *mut JSObject) -&gt; bool { &gt;- unsafe { &gt;- AppendToAutoObjectVector(self.ptr, obj) &gt;- } &gt;+ unsafe { AppendToAutoObjectVector(self.ptr, obj) } &gt; } &gt; } &gt; &gt; impl Drop for AutoObjectVectorWrapper { &gt; fn drop(&amp;mut self) { &gt; unsafe { DeleteAutoObjectVector(self.ptr) } &gt; } &gt; } &gt; &gt; pub struct CompileOptionsWrapper { &gt;- pub ptr: *mut JS::ReadOnlyCompileOptions &gt;+ pub ptr: *mut JS::ReadOnlyCompileOptions, &gt; } &gt; &gt; impl CompileOptionsWrapper { &gt;- pub fn new(cx: *mut JSContext, file: *const ::libc::c_char, line: c_uint) -&gt; CompileOptionsWrapper { &gt;+ pub fn new( &gt;+ cx: *mut JSContext, &gt;+ file: *const ::libc::c_char, &gt;+ line: c_uint, &gt;+ ) -&gt; CompileOptionsWrapper { &gt; CompileOptionsWrapper { &gt;- ptr: unsafe { NewCompileOptions(cx, file, line) } &gt;+ ptr: unsafe { NewCompileOptions(cx, file, line) }, &gt; } &gt; } &gt; } &gt; &gt; impl Drop for CompileOptionsWrapper { &gt; fn drop(&amp;mut self) { &gt; unsafe { DeleteCompileOptions(self.ptr) } &gt; } &gt;@@ -840,19 +864,18 @@ pub unsafe fn ToNumber(cx: *mut JSContext, v: JS::HandleValue) -&gt; Result&lt;f64, () &gt; Err(()) &gt; } &gt; } &gt; &gt; #[inline] &gt; unsafe fn convert_from_int32&lt;T: Default + Copy&gt;( &gt; cx: *mut JSContext, &gt; v: JS::HandleValue, &gt;- conv_fn: unsafe extern "C" fn(*mut JSContext, JS::HandleValue, *mut T) -&gt; bool) &gt;- -&gt; Result&lt;T, ()&gt; { &gt;- &gt;+ conv_fn: unsafe extern "C" fn(*mut JSContext, JS::HandleValue, *mut T) -&gt; bool, &gt;+) -&gt; Result&lt;T, ()&gt; { &gt; let val = *v.ptr; &gt; if val.is_int32() { &gt; let intval: i64 = val.to_int32() as i64; &gt; // TODO: do something better here that works on big endian &gt; let intval = *(&amp;intval as *const i64 as *const T); &gt; return Ok(intval); &gt; } &gt; &gt;@@ -894,34 +917,39 @@ pub unsafe fn ToString(cx: *mut JSContext, v: JS::HandleValue) -&gt; *mut JSString &gt; let val = *v.ptr; &gt; if val.is_string() { &gt; return val.to_string(); &gt; } &gt; &gt; js::ToStringSlow(cx, v) &gt; } &gt; &gt;-pub unsafe extern fn report_warning(_cx: *mut JSContext, report: *mut JSErrorReport) { &gt;+pub unsafe extern "C" fn report_warning(_cx: *mut JSContext, report: *mut JSErrorReport) { &gt; fn latin1_to_string(bytes: &amp;[u8]) -&gt; String { &gt;- bytes.iter().map(|c| char::from_u32(*c as u32).unwrap()).collect() &gt;+ bytes &gt;+ .iter() &gt;+ .map(|c| char::from_u32(*c as u32).unwrap()) &gt;+ .collect() &gt; } &gt; &gt; let fnptr = (*report)._base.filename; &gt; let fname = if !fnptr.is_null() { &gt; let c_str = ffi::CStr::from_ptr(fnptr); &gt; latin1_to_string(c_str.to_bytes()) &gt; } else { &gt; "none".to_string() &gt; }; &gt; &gt; let lineno = (*report)._base.lineno; &gt; let column = (*report)._base.column; &gt; &gt; let msg_ptr = (*report)._base.message_.data_ as *const u16; &gt;- let msg_len = (0usize..).find(|&amp;i| *msg_ptr.offset(i as isize) == 0).unwrap(); &gt;+ let msg_len = (0usize..) &gt;+ .find(|&amp;i| *msg_ptr.offset(i as isize) == 0) &gt;+ .unwrap(); &gt; let msg_slice = slice::from_raw_parts(msg_ptr, msg_len); &gt; let msg = String::from_utf16_lossy(msg_slice); &gt; &gt; warn!("Warning at {}:{}:{}: {}\n", fname, lineno, column, msg); &gt; } &gt; &gt; impl JSNativeWrapper { &gt; fn is_zeroed(&amp;self) -&gt; bool { &gt;@@ -941,19 +969,17 @@ impl IdVector { &gt; &gt; pub fn get(&amp;self) -&gt; *mut JS::AutoIdVector { &gt; self.0 &gt; } &gt; } &gt; &gt; impl Drop for IdVector { &gt; fn drop(&amp;mut self) { &gt;- unsafe { &gt;- DestroyAutoIdVector(self.0) &gt;- } &gt;+ unsafe { DestroyAutoIdVector(self.0) } &gt; } &gt; } &gt; &gt; impl Deref for IdVector { &gt; type Target = [jsid]; &gt; &gt; fn deref(&amp;self) -&gt; &amp;[jsid] { &gt; unsafe { &gt;@@ -974,25 +1000,36 @@ impl Deref for IdVector { &gt; /// # Panics &gt; /// &gt; /// Panics if the last entry of `methods` does not contain zeroed memory. &gt; /// &gt; /// # Safety &gt; /// &gt; /// - `cx` must be valid. &gt; /// - This function calls into unaudited C++ code. &gt;-pub unsafe fn define_methods(cx: *mut JSContext, obj: JS::HandleObject, &gt;- methods: &amp;'static [JSFunctionSpec]) &gt;- -&gt; Result&lt;(), ()&gt; { &gt;+pub unsafe fn define_methods( &gt;+ cx: *mut JSContext, &gt;+ obj: JS::HandleObject, &gt;+ methods: &amp;'static [JSFunctionSpec], &gt;+) -&gt; Result&lt;(), ()&gt; { &gt; assert!({ &gt; match methods.last() { &gt;- Some(&amp;JSFunctionSpec { name, call, nargs, flags, selfHostedName }) =&gt; { &gt;- name.is_null() &amp;&amp; call.is_zeroed() &amp;&amp; nargs == 0 &amp;&amp; flags == 0 &amp;&amp; &gt;- selfHostedName.is_null() &gt;- }, &gt;+ Some(&amp;JSFunctionSpec { &gt;+ name, &gt;+ call, &gt;+ nargs, &gt;+ flags, &gt;+ selfHostedName, &gt;+ }) =&gt; { &gt;+ name.is_null() &gt;+ &amp;&amp; call.is_zeroed() &gt;+ &amp;&amp; nargs == 0 &gt;+ &amp;&amp; flags == 0 &gt;+ &amp;&amp; selfHostedName.is_null() &gt;+ } &gt; None =&gt; false, &gt; } &gt; }); &gt; &gt; JS_DefineFunctions(cx, obj, methods.as_ptr()).to_result() &gt; } &gt; &gt; /// Defines attributes on `obj`. The last entry of `properties` must contain &gt;@@ -1005,24 +1042,28 @@ pub unsafe fn define_methods(cx: *mut JSContext, obj: JS::HandleObject, &gt; /// # Panics &gt; /// &gt; /// Panics if the last entry of `properties` does not contain zeroed memory. &gt; /// &gt; /// # Safety &gt; /// &gt; /// - `cx` must be valid. &gt; /// - This function calls into unaudited C++ code. &gt;-pub unsafe fn define_properties(cx: *mut JSContext, obj: JS::HandleObject, &gt;- properties: &amp;'static [JSPropertySpec]) &gt;- -&gt; Result&lt;(), ()&gt; { &gt;+pub unsafe fn define_properties( &gt;+ cx: *mut JSContext, &gt;+ obj: JS::HandleObject, &gt;+ properties: &amp;'static [JSPropertySpec], &gt;+) -&gt; Result&lt;(), ()&gt; { &gt; assert!(!properties.is_empty()); &gt; assert!({ &gt; let spec = properties.last().unwrap(); &gt;- let slice = slice::from_raw_parts(spec as *const _ as *const u8, &gt;- mem::size_of::&lt;JSPropertySpec&gt;()); &gt;+ let slice = slice::from_raw_parts( &gt;+ spec as *const _ as *const u8, &gt;+ mem::size_of::&lt;JSPropertySpec&gt;(), &gt;+ ); &gt; slice.iter().all(|byte| *byte == 0) &gt; }); &gt; &gt; JS_DefineProperties(cx, obj, properties.as_ptr()).to_result() &gt; } &gt; &gt; static SIMPLE_GLOBAL_CLASS_OPS: JSClassOps = JSClassOps { &gt; addProperty: None, &gt;@@ -1036,19 +1077,21 @@ static SIMPLE_GLOBAL_CLASS_OPS: JSClassOps = JSClassOps { &gt; hasInstance: None, &gt; construct: None, &gt; trace: Some(JS_GlobalObjectTraceHook), &gt; }; &gt; &gt; /// This is a simple `JSClass` for global objects, primarily intended for tests. &gt; pub static SIMPLE_GLOBAL_CLASS: JSClass = JSClass { &gt; name: b"Global\0" as *const u8 as *const _, &gt;- flags: (JSCLASS_IS_GLOBAL | ((JSCLASS_GLOBAL_SLOT_COUNT &amp; JSCLASS_RESERVED_SLOTS_MASK) &lt;&lt; JSCLASS_RESERVED_SLOTS_SHIFT)) as u32, &gt;+ flags: (JSCLASS_IS_GLOBAL &gt;+ | ((JSCLASS_GLOBAL_SLOT_COUNT &amp; JSCLASS_RESERVED_SLOTS_MASK) &gt;+ &lt;&lt; JSCLASS_RESERVED_SLOTS_SHIFT)) as u32, &gt; cOps: &amp;SIMPLE_GLOBAL_CLASS_OPS as *const JSClassOps, &gt;- reserved: [0 as *mut _; 3] &gt;+ reserved: [0 as *mut _; 3], &gt; }; &gt; &gt; #[inline] &gt; unsafe fn get_object_group(obj: *mut JSObject) -&gt; *mut js::shadow::ObjectGroup { &gt; assert!(!obj.is_null()); &gt; let obj = obj as *mut js::shadow::Object; &gt; (*obj).group &gt; } &gt;@@ -1102,19 +1145,17 @@ pub unsafe fn maybe_wrap_object_value(cx: *mut JSContext, rval: JS::MutableHandl &gt; // not here, but JSAPI no longer exposes a way to get a JSContext's &gt; // compartment, and additionally JSContext is under a bunch of churn in &gt; // JSAPI in general right now. &gt; &gt; assert!(JS_WrapValue(cx, rval)); &gt; } &gt; &gt; #[inline] &gt;-pub unsafe fn maybe_wrap_object_or_null_value( &gt;- cx: *mut JSContext, &gt;- rval: JS::MutableHandleValue) { &gt;+pub unsafe fn maybe_wrap_object_or_null_value(cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt; assert!(rval.is_object_or_null()); &gt; if !rval.is_null() { &gt; maybe_wrap_object_value(cx, rval); &gt; } &gt; } &gt; &gt; #[inline] &gt; pub unsafe fn maybe_wrap_value(cx: *mut JSContext, rval: JS::MutableHandleValue) { &gt;@@ -1122,36 +1163,40 @@ pub unsafe fn maybe_wrap_value(cx: *mut JSContext, rval: JS::MutableHandleValue) &gt; assert!(JS_WrapValue(cx, rval)); &gt; } else if rval.is_object() { &gt; maybe_wrap_object_value(cx, rval); &gt; } &gt; } &gt; &gt; /// Equivalents of the JS_FN* macros. &gt; impl JSFunctionSpec { &gt;- pub fn js_fs(name: *const ::std::os::raw::c_char, &gt;- func: JSNative, &gt;- nargs: u16, &gt;- flags: u16) -&gt; JSFunctionSpec { &gt;+ pub fn js_fs( &gt;+ name: *const ::std::os::raw::c_char, &gt;+ func: JSNative, &gt;+ nargs: u16, &gt;+ flags: u16, &gt;+ ) -&gt; JSFunctionSpec { &gt; JSFunctionSpec { &gt; name: name, &gt; call: JSNativeWrapper { &gt; op: func, &gt; info: ptr::null(), &gt; }, &gt; nargs: nargs, &gt; flags: flags, &gt; selfHostedName: 0 as *const _, &gt; } &gt; } &gt; &gt;- pub fn js_fn(name: *const ::std::os::raw::c_char, &gt;- func: JSNative, &gt;- nargs: u16, &gt;- flags: u16) -&gt; JSFunctionSpec { &gt;+ pub fn js_fn( &gt;+ name: *const ::std::os::raw::c_char, &gt;+ func: JSNative, &gt;+ nargs: u16, &gt;+ flags: u16, &gt;+ ) -&gt; JSFunctionSpec { &gt; JSFunctionSpec { &gt; name: name, &gt; call: JSNativeWrapper { &gt; op: func, &gt; info: ptr::null(), &gt; }, &gt; nargs: nargs, &gt; flags: flags, &gt;@@ -1168,18 +1213,21 @@ impl JSFunctionSpec { &gt; nargs: 0, &gt; flags: 0, &gt; selfHostedName: 0 as *const _, &gt; }; &gt; } &gt; &gt; /// Equivalents of the JS_PS* macros. &gt; impl JSPropertySpec { &gt;- pub fn getter(name: *const ::std::os::raw::c_char, flags: u8, func: JSNative) &gt;- -&gt; JSPropertySpec { &gt;+ pub fn getter( &gt;+ name: *const ::std::os::raw::c_char, &gt;+ flags: u8, &gt;+ func: JSNative, &gt;+ ) -&gt; JSPropertySpec { &gt; debug_assert_eq!(flags &amp; !(JSPROP_ENUMERATE | JSPROP_PERMANENT), 0); &gt; JSPropertySpec { &gt; name: name, &gt; flags: flags, &gt; __bindgen_anon_1: JSPropertySpec__bindgen_ty_1 { &gt; accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 { &gt; getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 { &gt; native: JSNativeWrapper { &gt;@@ -1187,27 +1235,28 @@ impl JSPropertySpec { &gt; info: ptr::null(), &gt; }, &gt; }, &gt; setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 { &gt; native: JSNativeWrapper { &gt; op: None, &gt; info: ptr::null(), &gt; }, &gt;- } &gt;- } &gt;- } &gt;+ }, &gt;+ }, &gt;+ }, &gt; } &gt; } &gt; &gt;- pub fn getter_setter(name: *const ::std::os::raw::c_char, &gt;- flags: u8, &gt;- g_f: JSNative, &gt;- s_f: JSNative) &gt;- -&gt; JSPropertySpec { &gt;+ pub fn getter_setter( &gt;+ name: *const ::std::os::raw::c_char, &gt;+ flags: u8, &gt;+ g_f: JSNative, &gt;+ s_f: JSNative, &gt;+ ) -&gt; JSPropertySpec { &gt; debug_assert_eq!(flags &amp; !(JSPROP_ENUMERATE | JSPROP_PERMANENT), 0); &gt; JSPropertySpec { &gt; name: name, &gt; flags: flags, &gt; __bindgen_anon_1: JSPropertySpec__bindgen_ty_1 { &gt; accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 { &gt; getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 { &gt; native: JSNativeWrapper { &gt;@@ -1215,35 +1264,35 @@ impl JSPropertySpec { &gt; info: ptr::null(), &gt; }, &gt; }, &gt; setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 { &gt; native: JSNativeWrapper { &gt; op: s_f, &gt; info: ptr::null(), &gt; }, &gt;- } &gt;- } &gt;- } &gt;+ }, &gt;+ }, &gt;+ }, &gt; } &gt; } &gt; &gt; pub const NULL: JSPropertySpec = JSPropertySpec { &gt; name: 0 as *const _, &gt; flags: 0, &gt;- __bindgen_anon_1: JSPropertySpec__bindgen_ty_1{ &gt;+ __bindgen_anon_1: JSPropertySpec__bindgen_ty_1 { &gt; accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 { &gt; getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 { &gt; native: JSNativeWrapper { &gt; op: None, &gt; info: 0 as *const _, &gt; }, &gt; }, &gt; setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 { &gt; native: JSNativeWrapper { &gt; op: None, &gt; info: 0 as *const _, &gt; }, &gt;- } &gt;- } &gt;- } &gt;+ }, &gt;+ }, &gt;+ }, &gt; }; &gt; } &gt;diff --git a/js/rust/src/sc.rs b/js/rust/src/sc.rs &gt;index a304a510e4c5..a847702f1f0d 100644 &gt;--- a/js/rust/src/sc.rs &gt;+++ b/js/rust/src/sc.rs &gt;@@ -15,82 +15,71 @@ pub struct StructuredCloneBuffer { &gt; } &gt; &gt; impl StructuredCloneBuffer { &gt; /// Construct a new `StructuredCloneBuffer`. &gt; /// &gt; /// # Panics &gt; /// &gt; /// Panics if the underlying JSAPI calls fail. &gt;- pub fn new(scope: jsapi::JS::StructuredCloneScope, &gt;- callbacks: &amp;jsapi::JSStructuredCloneCallbacks) &gt;- -&gt; StructuredCloneBuffer { &gt;- let raw = unsafe { &gt;- glue::NewJSAutoStructuredCloneBuffer(scope, callbacks) &gt;- }; &gt;+ pub fn new( &gt;+ scope: jsapi::JS::StructuredCloneScope, &gt;+ callbacks: &amp;jsapi::JSStructuredCloneCallbacks, &gt;+ ) -&gt; StructuredCloneBuffer { &gt;+ let raw = unsafe { glue::NewJSAutoStructuredCloneBuffer(scope, callbacks) }; &gt; assert!(!raw.is_null()); &gt;- StructuredCloneBuffer { &gt;- raw: raw, &gt;- } &gt;+ StructuredCloneBuffer { raw: raw } &gt; } &gt; &gt; /// Get the raw `*mut JSStructuredCloneData` owned by this buffer. &gt; pub fn data(&amp;self) -&gt; *mut jsapi::JSStructuredCloneData { &gt;- unsafe { &gt;- &amp;mut (*self.raw).data_ &gt;- } &gt;+ unsafe { &amp;mut (*self.raw).data_ } &gt; } &gt; &gt; /// Copy this buffer's data into a vec. &gt; pub fn copy_to_vec(&amp;self) -&gt; Vec&lt;u8&gt; { &gt;- let len = unsafe { &gt;- glue::GetLengthOfJSStructuredCloneData(self.data()) &gt;- }; &gt;+ let len = unsafe { glue::GetLengthOfJSStructuredCloneData(self.data()) }; &gt; let mut vec = Vec::with_capacity(len); &gt; unsafe { &gt; glue::CopyJSStructuredCloneData(self.data(), vec.as_mut_ptr()); &gt; } &gt; vec &gt; } &gt; &gt; /// Read a JS value out of this buffer. &gt;- pub fn read(&amp;mut self, &gt;- vp: jsapi::JS::MutableHandleValue, &gt;- callbacks: &amp;jsapi::JSStructuredCloneCallbacks) &gt;- -&gt; Result&lt;(), ()&gt; { &gt;- if unsafe { &gt;- (*self.raw).read(Runtime::get(), vp, callbacks, ptr::null_mut()) &gt;- } { &gt;+ pub fn read( &gt;+ &amp;mut self, &gt;+ vp: jsapi::JS::MutableHandleValue, &gt;+ callbacks: &amp;jsapi::JSStructuredCloneCallbacks, &gt;+ ) -&gt; Result&lt;(), ()&gt; { &gt;+ if unsafe { (*self.raw).read(Runtime::get(), vp, callbacks, ptr::null_mut()) } { &gt; Ok(()) &gt; } else { &gt; Err(()) &gt; } &gt; } &gt; &gt; /// Write a JS value into this buffer. &gt;- pub fn write(&amp;mut self, &gt;- v: jsapi::JS::HandleValue, &gt;- callbacks: &amp;jsapi::JSStructuredCloneCallbacks) &gt;- -&gt; Result&lt;(), ()&gt; { &gt;- if unsafe { &gt;- (*self.raw).write(Runtime::get(), v, callbacks, ptr::null_mut()) &gt;- } { &gt;+ pub fn write( &gt;+ &amp;mut self, &gt;+ v: jsapi::JS::HandleValue, &gt;+ callbacks: &amp;jsapi::JSStructuredCloneCallbacks, &gt;+ ) -&gt; Result&lt;(), ()&gt; { &gt;+ if unsafe { (*self.raw).write(Runtime::get(), v, callbacks, ptr::null_mut()) } { &gt; Ok(()) &gt; } else { &gt; Err(()) &gt; } &gt; } &gt; &gt; /// Copy the given slice into this buffer. &gt; pub fn write_bytes(&amp;mut self, bytes: &amp;[u8]) -&gt; Result&lt;(), ()&gt; { &gt; let len = bytes.len(); &gt; let src = bytes.as_ptr(); &gt;- if unsafe { &gt;- glue::WriteBytesToJSStructuredCloneData(src, len, self.data()) &gt;- } { &gt;+ if unsafe { glue::WriteBytesToJSStructuredCloneData(src, len, self.data()) } { &gt; Ok(()) &gt; } else { &gt; Err(()) &gt; } &gt; } &gt; } &gt; &gt; impl Drop for StructuredCloneBuffer { &gt;diff --git a/js/rust/src/typedarray.rs b/js/rust/src/typedarray.rs &gt;index f44721235a6b..f9fbf8ac9737 100644 &gt;--- a/js/rust/src/typedarray.rs &gt;+++ b/js/rust/src/typedarray.rs &gt;@@ -10,19 +10,19 @@ use glue::GetFloat32ArrayLengthAndData; &gt; use glue::GetFloat64ArrayLengthAndData; &gt; use glue::GetInt16ArrayLengthAndData; &gt; use glue::GetInt32ArrayLengthAndData; &gt; use glue::GetInt8ArrayLengthAndData; &gt; use glue::GetUint16ArrayLengthAndData; &gt; use glue::GetUint32ArrayLengthAndData; &gt; use glue::GetUint8ArrayLengthAndData; &gt; use glue::GetUint8ClampedArrayLengthAndData; &gt;-use jsapi::*; &gt; use jsapi::js::*; &gt; use jsapi::JS::*; &gt;+use jsapi::*; &gt; use rust::RootedGuard; &gt; use std::ptr; &gt; use std::slice; &gt; &gt; pub enum CreateWith&lt;'a, T: 'a&gt; { &gt; Length(u32), &gt; Slice(&amp;'a [T]), &gt; } &gt;@@ -32,20 +32,21 @@ pub struct TypedArray&lt;'a, T: 'a + TypedArrayElement&gt; { &gt; object: RootedGuard&lt;'a, *mut JSObject&gt;, &gt; computed: Option&lt;(*mut T::Element, u32)&gt;, &gt; } &gt; &gt; impl&lt;'a, T: TypedArrayElement&gt; TypedArray&lt;'a, T&gt; { &gt; /// Create a typed array representation that wraps an existing JS reflector. &gt; /// This operation will fail if attempted on a JS object that does not match &gt; /// the expected typed array details. &gt;- pub fn from(cx: *mut JSContext, &gt;- root: &amp;'a mut Rooted&lt;*mut JSObject&gt;, &gt;- object: *mut JSObject) &gt;- -&gt; Result&lt;Self, ()&gt; { &gt;+ pub fn from( &gt;+ cx: *mut JSContext, &gt;+ root: &amp;'a mut Rooted&lt;*mut JSObject&gt;, &gt;+ object: *mut JSObject, &gt;+ ) -&gt; Result&lt;Self, ()&gt; { &gt; if object.is_null() { &gt; return Err(()); &gt; } &gt; unsafe { &gt; let mut guard = RootedGuard::new(cx, root, object); &gt; let unwrapped = T::unwrap_array(*guard); &gt; if unwrapped.is_null() { &gt; return Err(()); &gt;@@ -89,20 +90,21 @@ impl&lt;'a, T: TypedArrayElement&gt; TypedArray&lt;'a, T&gt; { &gt; let (pointer, length) = self.data(); &gt; slice::from_raw_parts_mut(pointer, length as usize) &gt; } &gt; } &gt; &gt; impl&lt;'a, T: TypedArrayElementCreator + TypedArrayElement&gt; TypedArray&lt;'a, T&gt; { &gt; /// Create a new JS typed array, optionally providing initial data that will &gt; /// be copied into the newly-allocated buffer. Returns the new JS reflector. &gt;- pub unsafe fn create(cx: *mut JSContext, &gt;- with: CreateWith&lt;T::Element&gt;, &gt;- result: MutableHandleObject) &gt;- -&gt; Result&lt;(), ()&gt; { &gt;+ pub unsafe fn create( &gt;+ cx: *mut JSContext, &gt;+ with: CreateWith&lt;T::Element&gt;, &gt;+ result: MutableHandleObject, &gt;+ ) -&gt; Result&lt;(), ()&gt; { &gt; let length = match with { &gt; CreateWith::Length(len) =&gt; len, &gt; CreateWith::Slice(slice) =&gt; slice.len() as u32, &gt; }; &gt; &gt; result.set(T::create_new(cx, length)); &gt; if result.get().is_null() { &gt; return Err(()); &gt;@@ -145,17 +147,17 @@ pub trait TypedArrayElementCreator: TypedArrayElement { &gt; /// Get the data. &gt; unsafe fn get_data(obj: *mut JSObject) -&gt; *mut Self::Element; &gt; } &gt; &gt; macro_rules! typed_array_element { &gt; ($t: ident, &gt; $element: ty, &gt; $unwrap: ident, &gt;- $length_and_data: ident) =&gt; ( &gt;+ $length_and_data: ident) =&gt; { &gt; /// A kind of typed array. &gt; pub struct $t; &gt; &gt; impl TypedArrayElement for $t { &gt; type Element = $element; &gt; unsafe fn unwrap_array(obj: *mut JSObject) -&gt; *mut JSObject { &gt; $unwrap(obj) &gt; } &gt;@@ -164,105 +166,127 @@ macro_rules! typed_array_element { &gt; let mut len = 0; &gt; let mut shared = false; &gt; let mut data = ptr::null_mut(); &gt; $length_and_data(obj, &amp;mut len, &amp;mut shared, &amp;mut data); &gt; assert!(!shared); &gt; (data, len) &gt; } &gt; } &gt;- ); &gt;+ }; &gt; &gt; ($t: ident, &gt; $element: ty, &gt; $unwrap: ident, &gt; $length_and_data: ident, &gt; $create_new: ident, &gt;- $get_data: ident) =&gt; ( &gt;+ $get_data: ident) =&gt; { &gt; typed_array_element!($t, $element, $unwrap, $length_and_data); &gt; &gt; impl TypedArrayElementCreator for $t { &gt; unsafe fn create_new(cx: *mut JSContext, length: u32) -&gt; *mut JSObject { &gt; $create_new(cx, length) &gt; } &gt; &gt; unsafe fn get_data(obj: *mut JSObject) -&gt; *mut Self::Element { &gt; let mut shared = false; &gt; let data = $get_data(obj, &amp;mut shared, ptr::null_mut()); &gt; assert!(!shared); &gt; data &gt; } &gt; } &gt;- ); &gt;+ }; &gt; } &gt; &gt;-typed_array_element!(Uint8, &gt;- u8, &gt;- UnwrapUint8Array, &gt;- GetUint8ArrayLengthAndData, &gt;- JS_NewUint8Array, &gt;- JS_GetUint8ArrayData); &gt;-typed_array_element!(Uint16, &gt;- u16, &gt;- UnwrapUint16Array, &gt;- GetUint16ArrayLengthAndData, &gt;- JS_NewUint16Array, &gt;- JS_GetUint16ArrayData); &gt;-typed_array_element!(Uint32, &gt;- u32, &gt;- UnwrapUint32Array, &gt;- GetUint32ArrayLengthAndData, &gt;- JS_NewUint32Array, &gt;- JS_GetUint32ArrayData); &gt;-typed_array_element!(Int8, &gt;- i8, &gt;- UnwrapInt8Array, &gt;- GetInt8ArrayLengthAndData, &gt;- JS_NewInt8Array, &gt;- JS_GetInt8ArrayData); &gt;-typed_array_element!(Int16, &gt;- i16, &gt;- UnwrapInt16Array, &gt;- GetInt16ArrayLengthAndData, &gt;- JS_NewInt16Array, &gt;- JS_GetInt16ArrayData); &gt;-typed_array_element!(Int32, &gt;- i32, &gt;- UnwrapInt32Array, &gt;- GetInt32ArrayLengthAndData, &gt;- JS_NewInt32Array, &gt;- JS_GetInt32ArrayData); &gt;-typed_array_element!(Float32, &gt;- f32, &gt;- UnwrapFloat32Array, &gt;- GetFloat32ArrayLengthAndData, &gt;- JS_NewFloat32Array, &gt;- JS_GetFloat32ArrayData); &gt;-typed_array_element!(Float64, &gt;- f64, &gt;- UnwrapFloat64Array, &gt;- GetFloat64ArrayLengthAndData, &gt;- JS_NewFloat64Array, &gt;- JS_GetFloat64ArrayData); &gt;-typed_array_element!(ClampedU8, &gt;- u8, &gt;- UnwrapUint8ClampedArray, &gt;- GetUint8ClampedArrayLengthAndData, &gt;- JS_NewUint8ClampedArray, &gt;- JS_GetUint8ClampedArrayData); &gt;-typed_array_element!(ArrayBufferU8, &gt;- u8, &gt;- UnwrapArrayBuffer, &gt;- GetArrayBufferLengthAndData, &gt;- JS_NewArrayBuffer, &gt;- JS_GetArrayBufferData); &gt;-typed_array_element!(ArrayBufferViewU8, &gt;- u8, &gt;- UnwrapArrayBufferView, &gt;- GetArrayBufferViewLengthAndData); &gt;+typed_array_element!( &gt;+ Uint8, &gt;+ u8, &gt;+ UnwrapUint8Array, &gt;+ GetUint8ArrayLengthAndData, &gt;+ JS_NewUint8Array, &gt;+ JS_GetUint8ArrayData &gt;+); &gt;+typed_array_element!( &gt;+ Uint16, &gt;+ u16, &gt;+ UnwrapUint16Array, &gt;+ GetUint16ArrayLengthAndData, &gt;+ JS_NewUint16Array, &gt;+ JS_GetUint16ArrayData &gt;+); &gt;+typed_array_element!( &gt;+ Uint32, &gt;+ u32, &gt;+ UnwrapUint32Array, &gt;+ GetUint32ArrayLengthAndData, &gt;+ JS_NewUint32Array, &gt;+ JS_GetUint32ArrayData &gt;+); &gt;+typed_array_element!( &gt;+ Int8, &gt;+ i8, &gt;+ UnwrapInt8Array, &gt;+ GetInt8ArrayLengthAndData, &gt;+ JS_NewInt8Array, &gt;+ JS_GetInt8ArrayData &gt;+); &gt;+typed_array_element!( &gt;+ Int16, &gt;+ i16, &gt;+ UnwrapInt16Array, &gt;+ GetInt16ArrayLengthAndData, &gt;+ JS_NewInt16Array, &gt;+ JS_GetInt16ArrayData &gt;+); &gt;+typed_array_element!( &gt;+ Int32, &gt;+ i32, &gt;+ UnwrapInt32Array, &gt;+ GetInt32ArrayLengthAndData, &gt;+ JS_NewInt32Array, &gt;+ JS_GetInt32ArrayData &gt;+); &gt;+typed_array_element!( &gt;+ Float32, &gt;+ f32, &gt;+ UnwrapFloat32Array, &gt;+ GetFloat32ArrayLengthAndData, &gt;+ JS_NewFloat32Array, &gt;+ JS_GetFloat32ArrayData &gt;+); &gt;+typed_array_element!( &gt;+ Float64, &gt;+ f64, &gt;+ UnwrapFloat64Array, &gt;+ GetFloat64ArrayLengthAndData, &gt;+ JS_NewFloat64Array, &gt;+ JS_GetFloat64ArrayData &gt;+); &gt;+typed_array_element!( &gt;+ ClampedU8, &gt;+ u8, &gt;+ UnwrapUint8ClampedArray, &gt;+ GetUint8ClampedArrayLengthAndData, &gt;+ JS_NewUint8ClampedArray, &gt;+ JS_GetUint8ClampedArrayData &gt;+); &gt;+typed_array_element!( &gt;+ ArrayBufferU8, &gt;+ u8, &gt;+ UnwrapArrayBuffer, &gt;+ GetArrayBufferLengthAndData, &gt;+ JS_NewArrayBuffer, &gt;+ JS_GetArrayBufferData &gt;+); &gt;+typed_array_element!( &gt;+ ArrayBufferViewU8, &gt;+ u8, &gt;+ UnwrapArrayBufferView, &gt;+ GetArrayBufferViewLengthAndData &gt;+); &gt; &gt; /// The Uint8ClampedArray type. &gt; pub type Uint8ClampedArray&lt;'a&gt; = TypedArray&lt;'a, ClampedU8&gt;; &gt; /// The Uint8Array type. &gt; pub type Uint8Array&lt;'a&gt; = TypedArray&lt;'a, Uint8&gt;; &gt; /// The Int8Array type. &gt; pub type Int8Array&lt;'a&gt; = TypedArray&lt;'a, Int8&gt;; &gt; /// The Uint16Array type. &gt;@@ -292,10 +316,10 @@ impl&lt;'a&gt; ArrayBufferView&lt;'a&gt; { &gt; macro_rules! typedarray { &gt; (in($cx:expr) let $name:ident : $ty:ident = $init:expr) =&gt; { &gt; let mut __root = $crate::jsapi::JS::Rooted::new_unrooted(); &gt; let $name = $crate::typedarray::$ty::from($cx, &amp;mut __root, $init); &gt; }; &gt; (in($cx:expr) let mut $name:ident : $ty:ident = $init:expr) =&gt; { &gt; let mut __root = $crate::jsapi::JS::Rooted::new_unrooted(); &gt; let mut $name = $crate::typedarray::$ty::from($cx, &amp;mut __root, $init); &gt;- } &gt;+ }; &gt; } &gt;diff --git a/js/rust/tests/bigint.rs b/js/rust/tests/bigint.rs &gt;index 921931027fe4..03dc5287ed5d 100644 &gt;--- a/js/rust/tests/bigint.rs &gt;+++ b/js/rust/tests/bigint.rs &gt;@@ -1,13 +1,13 @@ &gt; #[macro_use] &gt; extern crate js; &gt; &gt;-use js::jsapi::root::JS::CompartmentOptions; &gt; use js::jsapi::root::JS_NewGlobalObject; &gt;+use js::jsapi::root::JS::CompartmentOptions; &gt; use js::jsapi::root::JS::OnNewGlobalHookOption; &gt; use js::jsval::UndefinedValue; &gt; use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS}; &gt; &gt; use std::ptr; &gt; &gt; #[test] &gt; fn is_bigint() { &gt;@@ -17,18 +17,20 @@ fn is_bigint() { &gt; unsafe { &gt; rooted!(in(cx) let global = &gt; JS_NewGlobalObject(cx, &amp;SIMPLE_GLOBAL_CLASS, ptr::null_mut(), &gt; OnNewGlobalHookOption::FireOnNewGlobalHook, &gt; &amp;CompartmentOptions::default()) &gt; ); &gt; &gt; rooted!(in(cx) let mut rval = UndefinedValue()); &gt;- assert!(rt.evaluate_script(global.handle(), "BigInt(0)", &gt;- "test", 1, rval.handle_mut()).is_ok()); &gt;+ assert!( &gt;+ rt.evaluate_script(global.handle(), "BigInt(0)", "test", 1, rval.handle_mut()) &gt;+ .is_ok() &gt;+ ); &gt; assert!(rval.is_bigint()); &gt; } &gt; } &gt; &gt; #[test] &gt; fn is_not_bigint() { &gt; let rt = Runtime::new(false).unwrap(); &gt; let cx = rt.cx(); &gt;@@ -36,13 +38,20 @@ fn is_not_bigint() { &gt; unsafe { &gt; rooted!(in(cx) let global = &gt; JS_NewGlobalObject(cx, &amp;SIMPLE_GLOBAL_CLASS, ptr::null_mut(), &gt; OnNewGlobalHookOption::FireOnNewGlobalHook, &gt; &amp;CompartmentOptions::default()) &gt; ); &gt; &gt; rooted!(in(cx) let mut rval = UndefinedValue()); &gt;- assert!(rt.evaluate_script(global.handle(), "'not a BigInt'", &gt;- "test", 1, rval.handle_mut()).is_ok()); &gt;+ assert!( &gt;+ rt.evaluate_script( &gt;+ global.handle(), &gt;+ "'not a BigInt'", &gt;+ "test", &gt;+ 1, &gt;+ rval.handle_mut() &gt;+ ).is_ok() &gt;+ ); &gt; assert!(!rval.is_bigint()); &gt; } &gt; } &gt;diff --git a/js/rust/tests/callback.rs b/js/rust/tests/callback.rs &gt;index a8c9972ff6dd..fa3c62c45af3 100644 &gt;--- a/js/rust/tests/callback.rs &gt;+++ b/js/rust/tests/callback.rs &gt;@@ -2,58 +2,73 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this file, &gt; * You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; #[macro_use] &gt; extern crate js; &gt; extern crate libc; &gt; &gt; use js::ac::AutoCompartment; &gt;-use js::jsapi::root::JS::CallArgs; &gt;-use js::jsapi::root::JS::RealmOptions; &gt; use js::jsapi::root::JSContext; &gt; use js::jsapi::root::JS_DefineFunction; &gt; use js::jsapi::root::JS_EncodeStringToUTF8; &gt; use js::jsapi::root::JS_NewGlobalObject; &gt; use js::jsapi::root::JS_ReportErrorASCII; &gt;+use js::jsapi::root::JS::CallArgs; &gt; use js::jsapi::root::JS::OnNewGlobalHookOption; &gt;+use js::jsapi::root::JS::RealmOptions; &gt; use js::jsapi::root::JS::Value; &gt; use js::jsval::UndefinedValue; &gt; use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS}; &gt; &gt; use std::ffi::CStr; &gt; use std::ptr; &gt; use std::str; &gt; &gt; #[test] &gt; fn callback() { &gt; let runtime = Runtime::new(false).unwrap(); &gt; let context = runtime.cx(); &gt; let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook; &gt; let c_option = RealmOptions::default(); &gt; &gt; unsafe { &gt;- let global = JS_NewGlobalObject(context, &amp;SIMPLE_GLOBAL_CLASS, ptr::null_mut(), h_option, &amp;c_option); &gt;+ let global = JS_NewGlobalObject( &gt;+ context, &gt;+ &amp;SIMPLE_GLOBAL_CLASS, &gt;+ ptr::null_mut(), &gt;+ h_option, &gt;+ &amp;c_option, &gt;+ ); &gt; rooted!(in(context) let global_root = global); &gt; let global = global_root.handle(); &gt; let _ac = AutoCompartment::with_obj(context, global.get()); &gt;- let function = JS_DefineFunction(context, global, b"puts\0".as_ptr() as *const libc::c_char, &gt;- Some(puts), 1, 0); &gt;+ let function = JS_DefineFunction( &gt;+ context, &gt;+ global, &gt;+ b"puts\0".as_ptr() as *const libc::c_char, &gt;+ Some(puts), &gt;+ 1, &gt;+ 0, &gt;+ ); &gt; assert!(!function.is_null()); &gt; let javascript = "puts('Test IñtërnâtiônÃ&nbsp;lizætiøn ┬─┬ノ( º _ ºノ) ');"; &gt; rooted!(in(context) let mut rval = UndefinedValue()); &gt; let _ = runtime.evaluate_script(global, javascript, "test.js", 0, rval.handle_mut()); &gt; } &gt; } &gt; &gt; unsafe extern "C" fn puts(context: *mut JSContext, argc: u32, vp: *mut Value) -&gt; bool { &gt; let args = CallArgs::from_vp(vp, argc); &gt; &gt; if args._base.argc_ != 1 { &gt;- JS_ReportErrorASCII(context, b"puts() requires exactly 1 argument\0".as_ptr() as *const libc::c_char); &gt;+ JS_ReportErrorASCII( &gt;+ context, &gt;+ b"puts() requires exactly 1 argument\0".as_ptr() as *const libc::c_char, &gt;+ ); &gt; return false; &gt; } &gt; &gt; let arg = args.get(0); &gt; let js = js::rust::ToString(context, arg); &gt; rooted!(in(context) let message_root = js); &gt; let message = JS_EncodeStringToUTF8(context, message_root.handle()); &gt; let message = CStr::from_ptr(message); &gt;diff --git a/js/rust/tests/enumerate.rs b/js/rust/tests/enumerate.rs &gt;index 3e7e02a99cc3..53c2d29a2a4d 100644 &gt;--- a/js/rust/tests/enumerate.rs &gt;+++ b/js/rust/tests/enumerate.rs &gt;@@ -2,22 +2,22 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; #[macro_use] &gt; extern crate js; &gt; &gt; use js::glue::RUST_JSID_IS_STRING; &gt; use js::glue::RUST_JSID_TO_STRING; &gt;-use js::jsapi::root::JS::RealmOptions; &gt; use js::jsapi::root::js::GetPropertyKeys; &gt;-use js::jsapi::root::JSITER_OWNONLY; &gt; use js::jsapi::root::JS_NewGlobalObject; &gt; use js::jsapi::root::JS_StringEqualsAscii; &gt; use js::jsapi::root::JS::OnNewGlobalHookOption; &gt;+use js::jsapi::root::JS::RealmOptions; &gt;+use js::jsapi::root::JSITER_OWNONLY; &gt; use js::jsval::UndefinedValue; &gt; use js::rust::IdVector; &gt; use js::rust::Runtime; &gt; use js::rust::SIMPLE_GLOBAL_CLASS; &gt; use std::ptr; &gt; &gt; #[test] &gt; fn enumerate() { &gt;@@ -27,30 +27,44 @@ fn enumerate() { &gt; unsafe { &gt; rooted!(in(cx) let global = &gt; JS_NewGlobalObject(cx, &amp;SIMPLE_GLOBAL_CLASS, ptr::null_mut(), &gt; OnNewGlobalHookOption::FireOnNewGlobalHook, &gt; &amp;RealmOptions::default()) &gt; ); &gt; &gt; rooted!(in(cx) let mut rval = UndefinedValue()); &gt;- assert!(rt.evaluate_script(global.handle(), "({ 'a': 7 })", &gt;- "test", 1, rval.handle_mut()).is_ok()); &gt;+ assert!( &gt;+ rt.evaluate_script( &gt;+ global.handle(), &gt;+ "({ 'a': 7 })", &gt;+ "test", &gt;+ 1, &gt;+ rval.handle_mut() &gt;+ ).is_ok() &gt;+ ); &gt; assert!(rval.is_object()); &gt; &gt; rooted!(in(cx) let object = rval.to_object()); &gt; let ids = IdVector::new(cx); &gt;- assert!(GetPropertyKeys(cx, object.handle(), JSITER_OWNONLY, ids.get())); &gt;+ assert!(GetPropertyKeys( &gt;+ cx, &gt;+ object.handle(), &gt;+ JSITER_OWNONLY, &gt;+ ids.get() &gt;+ )); &gt; &gt; assert_eq!(ids.len(), 1); &gt; rooted!(in(cx) let id = ids[0]); &gt; &gt; assert!(RUST_JSID_IS_STRING(id.handle())); &gt; rooted!(in(cx) let id = RUST_JSID_TO_STRING(id.handle())); &gt; &gt; let mut matches = false; &gt;- assert!(JS_StringEqualsAscii(cx, &gt;- id.get(), &gt;- b"a\0" as *const _ as *const _, &gt;- &amp;mut matches)); &gt;+ assert!(JS_StringEqualsAscii( &gt;+ cx, &gt;+ id.get(), &gt;+ b"a\0" as *const _ as *const _, &gt;+ &amp;mut matches &gt;+ )); &gt; assert!(matches); &gt; } &gt; } &gt;diff --git a/js/rust/tests/evaluate.rs b/js/rust/tests/evaluate.rs &gt;index ae8de51beb0b..7bdad8415243 100644 &gt;--- a/js/rust/tests/evaluate.rs &gt;+++ b/js/rust/tests/evaluate.rs &gt;@@ -1,32 +1,33 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; #[macro_use] &gt; extern crate js; &gt; &gt;-use js::jsapi::root::JS::RealmOptions; &gt; use js::jsapi::root::JS_NewGlobalObject; &gt; use js::jsapi::root::JS::OnNewGlobalHookOption; &gt;+use js::jsapi::root::JS::RealmOptions; &gt; use js::jsval::UndefinedValue; &gt; use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS}; &gt; &gt; use std::ptr; &gt; &gt; #[test] &gt; fn evaluate() { &gt; let rt = Runtime::new(false).unwrap(); &gt; let cx = rt.cx(); &gt; &gt; unsafe { &gt;- &gt; rooted!(in(cx) let global = &gt; JS_NewGlobalObject(cx, &amp;SIMPLE_GLOBAL_CLASS, ptr::null_mut(), &gt; OnNewGlobalHookOption::FireOnNewGlobalHook, &gt; &amp;RealmOptions::default()) &gt; ); &gt; rooted!(in(cx) let mut rval = UndefinedValue()); &gt;- assert!(rt.evaluate_script(global.handle(), "1 + 1", &gt;- "test", 1, rval.handle_mut()).is_ok()); &gt;+ assert!( &gt;+ rt.evaluate_script(global.handle(), "1 + 1", "test", 1, rval.handle_mut()) &gt;+ .is_ok() &gt;+ ); &gt; } &gt; } &gt;diff --git a/js/rust/tests/panic.rs b/js/rust/tests/panic.rs &gt;index 616fdd7d733e..41d66cba7f78 100644 &gt;--- a/js/rust/tests/panic.rs &gt;+++ b/js/rust/tests/panic.rs &gt;@@ -16,28 +16,35 @@ use std::str; &gt; #[should_panic] &gt; fn panic() { &gt; let runtime = Runtime::new(false).unwrap(); &gt; let context = runtime.cx(); &gt; let h_option = JS::OnNewGlobalHookOption::FireOnNewGlobalHook; &gt; let c_option = JS::RealmOptions::default(); &gt; &gt; unsafe { &gt;- let global = JS_NewGlobalObject(context, &amp;SIMPLE_GLOBAL_CLASS, &gt;- ptr::null_mut(), h_option, &amp;c_option); &gt;+ let global = JS_NewGlobalObject( &gt;+ context, &gt;+ &amp;SIMPLE_GLOBAL_CLASS, &gt;+ ptr::null_mut(), &gt;+ h_option, &gt;+ &amp;c_option, &gt;+ ); &gt; rooted!(in(context) let global_root = global); &gt; let global = global_root.handle(); &gt; let _ac = js::ac::AutoCompartment::with_obj(context, global.get()); &gt;- let function = JS_DefineFunction(context, global, &gt;- b"test\0".as_ptr() as *const _, &gt;- Some(test), 0, 0); &gt;+ let function = JS_DefineFunction( &gt;+ context, &gt;+ global, &gt;+ b"test\0".as_ptr() as *const _, &gt;+ Some(test), &gt;+ 0, &gt;+ 0, &gt;+ ); &gt; assert!(!function.is_null()); &gt; rooted!(in(context) let mut rval = UndefinedValue()); &gt;- let _ = runtime.evaluate_script(global, "test();", "test.js", 0, &gt;- rval.handle_mut()); &gt;+ let _ = runtime.evaluate_script(global, "test();", "test.js", 0, rval.handle_mut()); &gt; } &gt; } &gt; &gt; unsafe extern "C" fn test(_cx: *mut JSContext, _argc: u32, _vp: *mut JS::Value) -&gt; bool { &gt;- wrap_panic(|| { &gt;- panic!() &gt;- }, false) &gt;+ wrap_panic(|| panic!(), false) &gt; } &gt;diff --git a/js/rust/tests/rooting.rs b/js/rust/tests/rooting.rs &gt;index 2a4f147fd471..8e352ca0eff2 100644 &gt;--- a/js/rust/tests/rooting.rs &gt;+++ b/js/rust/tests/rooting.rs &gt;@@ -6,17 +6,17 @@ &gt; &gt; #[macro_use] &gt; extern crate js; &gt; #[macro_use] &gt; extern crate lazy_static; &gt; extern crate libc; &gt; &gt; use js::jsapi::*; &gt;-use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS, define_methods}; &gt;+use js::rust::{define_methods, Runtime, SIMPLE_GLOBAL_CLASS}; &gt; use std::ptr; &gt; &gt; #[test] &gt; fn rooting() { &gt; unsafe { &gt; let runtime = Runtime::new(false).unwrap(); &gt; JS_SetGCZeal(runtime.cx(), 2, 1); &gt; &gt;@@ -41,43 +41,55 @@ fn rooting() { &gt; unsafe extern "C" fn generic_method(_: *mut JSContext, _: u32, _: *mut JS::Value) -&gt; bool { &gt; true &gt; } &gt; &gt; lazy_static! { &gt; static ref METHODS: [JSFunctionSpec; 4] = [ &gt; JSFunctionSpec { &gt; name: b"addEventListener\0" as *const u8 as *const libc::c_char, &gt;- call: JSNativeWrapper { op: Some(generic_method), info: ptr::null() }, &gt;+ call: JSNativeWrapper { &gt;+ op: Some(generic_method), &gt;+ info: ptr::null() &gt;+ }, &gt; nargs: 2, &gt; flags: JSPROP_ENUMERATE as u16, &gt; selfHostedName: 0 as *const libc::c_char &gt; }, &gt; JSFunctionSpec { &gt; name: b"removeEventListener\0" as *const u8 as *const libc::c_char, &gt;- call: JSNativeWrapper { op: Some(generic_method), info: ptr::null() }, &gt;+ call: JSNativeWrapper { &gt;+ op: Some(generic_method), &gt;+ info: ptr::null() &gt;+ }, &gt; nargs: 2, &gt; flags: JSPROP_ENUMERATE as u16, &gt; selfHostedName: 0 as *const libc::c_char &gt; }, &gt; JSFunctionSpec { &gt; name: b"dispatchEvent\0" as *const u8 as *const libc::c_char, &gt;- call: JSNativeWrapper { op: Some(generic_method), info: ptr::null() }, &gt;+ call: JSNativeWrapper { &gt;+ op: Some(generic_method), &gt;+ info: ptr::null() &gt;+ }, &gt; nargs: 1, &gt; flags: JSPROP_ENUMERATE as u16, &gt; selfHostedName: 0 as *const libc::c_char &gt; }, &gt; JSFunctionSpec { &gt; name: ptr::null(), &gt;- call: JSNativeWrapper { op: None, info: ptr::null() }, &gt;+ call: JSNativeWrapper { &gt;+ op: None, &gt;+ info: ptr::null() &gt;+ }, &gt; nargs: 0, &gt; flags: 0, &gt; selfHostedName: ptr::null() &gt; } &gt; ]; &gt; } &gt; &gt; static CLASS: JSClass = JSClass { &gt; name: b"EventTargetPrototype\0" as *const u8 as *const libc::c_char, &gt; flags: 0, &gt; cOps: 0 as *const _, &gt;- reserved: [0 as *mut _; 3] &gt;+ reserved: [0 as *mut _; 3], &gt; }; &gt;diff --git a/js/rust/tests/runtime.rs b/js/rust/tests/runtime.rs &gt;index 86dd864a2baf..b31d1cebb5cd 100644 &gt;--- a/js/rust/tests/runtime.rs &gt;+++ b/js/rust/tests/runtime.rs &gt;@@ -26,17 +26,17 @@ fn runtime() { &gt; &amp;c_option)); &gt; let _ac = js::ac::AutoCompartment::with_obj(cx, global.get()); &gt; rooted!(in(cx) let _object = JS_NewObject(cx, &amp;CLASS as *const _)); &gt; } &gt; &gt; assert!(Runtime::new(false).is_err()); &gt; } &gt; &gt;-unsafe extern fn finalize(_fop: *mut JSFreeOp, _object: *mut JSObject) { &gt;+unsafe extern "C" fn finalize(_fop: *mut JSFreeOp, _object: *mut JSObject) { &gt; assert!(!Runtime::get().is_null()); &gt; } &gt; &gt; static CLASS_OPS: JSClassOps = JSClassOps { &gt; addProperty: None, &gt; delProperty: None, &gt; enumerate: None, &gt; newEnumerate: None, &gt;@@ -48,10 +48,10 @@ static CLASS_OPS: JSClassOps = JSClassOps { &gt; construct: None, &gt; trace: None, &gt; }; &gt; &gt; static CLASS: JSClass = JSClass { &gt; name: b"EventTargetPrototype\0" as *const u8 as *const libc::c_char, &gt; flags: 0 | JSCLASS_FOREGROUND_FINALIZE, &gt; cOps: &amp;CLASS_OPS as *const JSClassOps, &gt;- reserved: [0 as *mut _; 3] &gt;+ reserved: [0 as *mut _; 3], &gt; }; &gt;diff --git a/js/rust/tests/stack_limit.rs b/js/rust/tests/stack_limit.rs &gt;index e0a0bf1d0f9f..82c2510086d4 100644 &gt;--- a/js/rust/tests/stack_limit.rs &gt;+++ b/js/rust/tests/stack_limit.rs &gt;@@ -1,32 +1,44 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; #[macro_use] &gt; extern crate js; &gt; &gt;-use js::jsapi::root::JS::RealmOptions; &gt; use js::jsapi::root::JS_NewGlobalObject; &gt; use js::jsapi::root::JS::OnNewGlobalHookOption; &gt;+use js::jsapi::root::JS::RealmOptions; &gt; use js::jsval::UndefinedValue; &gt; use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS}; &gt; &gt; use std::ptr; &gt; &gt; #[test] &gt; fn stack_limit() { &gt; let rt = Runtime::new(false).unwrap(); &gt; let cx = rt.cx(); &gt; &gt; unsafe { &gt; let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook; &gt; let c_option = RealmOptions::default(); &gt;- let global = JS_NewGlobalObject(cx, &amp;SIMPLE_GLOBAL_CLASS, &gt;- ptr::null_mut(), h_option, &amp;c_option); &gt;+ let global = JS_NewGlobalObject( &gt;+ cx, &gt;+ &amp;SIMPLE_GLOBAL_CLASS, &gt;+ ptr::null_mut(), &gt;+ h_option, &gt;+ &amp;c_option, &gt;+ ); &gt; rooted!(in(cx) let global_root = global); &gt; let global = global_root.handle(); &gt; rooted!(in(cx) let mut rval = UndefinedValue()); &gt;- assert!(rt.evaluate_script(global, "function f() { f.apply() } f()", &gt;- "test", 1, rval.handle_mut()).is_err()); &gt;+ assert!( &gt;+ rt.evaluate_script( &gt;+ global, &gt;+ "function f() { f.apply() } f()", &gt;+ "test", &gt;+ 1, &gt;+ rval.handle_mut() &gt;+ ).is_err() &gt;+ ); &gt; } &gt; } &gt;diff --git a/js/rust/tests/typedarray.rs b/js/rust/tests/typedarray.rs &gt;index d99eab731861..b43bb68d32f1 100644 &gt;--- a/js/rust/tests/typedarray.rs &gt;+++ b/js/rust/tests/typedarray.rs &gt;@@ -22,28 +22,38 @@ fn typedarray() { &gt; JS_NewGlobalObject(cx, &amp;SIMPLE_GLOBAL_CLASS, ptr::null_mut(), &gt; JS::OnNewGlobalHookOption::FireOnNewGlobalHook, &gt; &amp;JS::RealmOptions::default()) &gt; ); &gt; &gt; let _ac = js::ac::AutoCompartment::with_obj(cx, global.get()); &gt; &gt; rooted!(in(cx) let mut rval = UndefinedValue()); &gt;- assert!(rt.evaluate_script(global.handle(), "new Uint8Array([0, 2, 4])", &gt;- "test", 1, rval.handle_mut()).is_ok()); &gt;+ assert!( &gt;+ rt.evaluate_script( &gt;+ global.handle(), &gt;+ "new Uint8Array([0, 2, 4])", &gt;+ "test", &gt;+ 1, &gt;+ rval.handle_mut() &gt;+ ).is_ok() &gt;+ ); &gt; assert!(rval.is_object()); &gt; &gt; typedarray!(in(cx) let array: Uint8Array = rval.to_object()); &gt; assert_eq!(array.unwrap().as_slice(), &amp;[0, 2, 4][..]); &gt; &gt; typedarray!(in(cx) let array: Uint16Array = rval.to_object()); &gt; assert!(array.is_err()); &gt; &gt; typedarray!(in(cx) let view: ArrayBufferView = rval.to_object()); &gt;- assert_eq!(view.unwrap().get_array_type(), js::jsapi::js::Scalar::Type::Uint8); &gt;+ assert_eq!( &gt;+ view.unwrap().get_array_type(), &gt;+ js::jsapi::js::Scalar::Type::Uint8 &gt;+ ); &gt; &gt; rooted!(in(cx) let mut rval = ptr::null_mut()); &gt; assert!(Uint32Array::create(cx, CreateWith::Slice(&amp;[1, 3, 5]), rval.handle_mut()).is_ok()); &gt; &gt; typedarray!(in(cx) let array: Uint32Array = rval.get()); &gt; assert_eq!(array.unwrap().as_slice(), &amp;[1, 3, 5][..]); &gt; &gt; typedarray!(in(cx) let mut array: Uint32Array = rval.get()); &gt;@@ -60,17 +70,20 @@ fn typedarray() { &gt; typedarray!(in(cx) let array: Uint32Array = rval.get()); &gt; assert_eq!(array.unwrap().as_slice(), &amp;[0, 0, 0, 0, 0]); &gt; &gt; typedarray!(in(cx) let mut array: Uint32Array = rval.get()); &gt; array.as_mut().unwrap().update(&amp;[0, 1, 2, 3]); &gt; assert_eq!(array.unwrap().as_slice(), &amp;[0, 1, 2, 3, 0]); &gt; &gt; typedarray!(in(cx) let view: ArrayBufferView = rval.get()); &gt;- assert_eq!(view.unwrap().get_array_type(), js::jsapi::js::Scalar::Type::Uint32); &gt;+ assert_eq!( &gt;+ view.unwrap().get_array_type(), &gt;+ js::jsapi::js::Scalar::Type::Uint32 &gt;+ ); &gt; } &gt; } &gt; &gt; #[test] &gt; #[should_panic] &gt; fn typedarray_update_panic() { &gt; let rt = Runtime_::new(false).unwrap(); &gt; let cx = rt.cx(); &gt;diff --git a/js/rust/tests/value.rs b/js/rust/tests/value.rs &gt;index a844a52118c9..299e0ed83ce3 100644 &gt;--- a/js/rust/tests/value.rs &gt;+++ b/js/rust/tests/value.rs &gt;@@ -1,18 +1,18 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; #[macro_use] &gt; extern crate js; &gt; &gt;-use js::jsapi::root::JS::RealmOptions; &gt; use js::jsapi::root::JS_NewGlobalObject; &gt; use js::jsapi::root::JS::OnNewGlobalHookOption; &gt;+use js::jsapi::root::JS::RealmOptions; &gt; use js::jsval::UndefinedValue; &gt; use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS}; &gt; &gt; use std::ptr; &gt; &gt; #[test] &gt; fn is_symbol() { &gt; let rt = Runtime::new(false).unwrap(); &gt;@@ -20,31 +20,45 @@ fn is_symbol() { &gt; &gt; unsafe { &gt; rooted!(in(cx) let global = &gt; JS_NewGlobalObject(cx, &amp;SIMPLE_GLOBAL_CLASS, ptr::null_mut(), &gt; OnNewGlobalHookOption::FireOnNewGlobalHook, &gt; &amp;RealmOptions::default()) &gt; ); &gt; rooted!(in(cx) let mut rval = UndefinedValue()); &gt;- assert!(rt.evaluate_script(global.handle(), "Symbol('test')", &gt;- "test", 1, rval.handle_mut()).is_ok()); &gt;+ assert!( &gt;+ rt.evaluate_script( &gt;+ global.handle(), &gt;+ "Symbol('test')", &gt;+ "test", &gt;+ 1, &gt;+ rval.handle_mut() &gt;+ ).is_ok() &gt;+ ); &gt; assert!(rval.is_symbol()); &gt; } &gt; } &gt; &gt; #[test] &gt; fn is_not_symbol() { &gt; let rt = Runtime::new(false).unwrap(); &gt; let cx = rt.cx(); &gt; &gt; unsafe { &gt; rooted!(in(cx) let global = &gt; JS_NewGlobalObject(cx, &amp;SIMPLE_GLOBAL_CLASS, ptr::null_mut(), &gt; OnNewGlobalHookOption::FireOnNewGlobalHook, &gt; &amp;RealmOptions::default()) &gt; ); &gt; rooted!(in(cx) let mut rval = UndefinedValue()); &gt;- assert!(rt.evaluate_script(global.handle(), "'not a symbol'", &gt;- "test", 1, rval.handle_mut()).is_ok()); &gt;+ assert!( &gt;+ rt.evaluate_script( &gt;+ global.handle(), &gt;+ "'not a symbol'", &gt;+ "test", &gt;+ 1, &gt;+ rval.handle_mut() &gt;+ ).is_ok() &gt;+ ); &gt; assert!(!rval.is_symbol()); &gt; } &gt; } &gt;diff --git a/js/rust/tests/vec_conversion.rs b/js/rust/tests/vec_conversion.rs &gt;index fca5d06b60e1..2c9db99fe08c 100644 &gt;--- a/js/rust/tests/vec_conversion.rs &gt;+++ b/js/rust/tests/vec_conversion.rs &gt;@@ -5,45 +5,47 @@ &gt; #[macro_use] &gt; extern crate js; &gt; &gt; use js::ac::AutoCompartment; &gt; use js::conversions::ConversionBehavior; &gt; use js::conversions::ConversionResult; &gt; use js::conversions::FromJSValConvertible; &gt; use js::conversions::ToJSValConvertible; &gt;-use js::jsapi::root::JS::RealmOptions; &gt;-use js::jsapi::root::JS::InitRealmStandardClasses; &gt; use js::jsapi::root::JS_NewGlobalObject; &gt;+use js::jsapi::root::JS::InitRealmStandardClasses; &gt; use js::jsapi::root::JS::OnNewGlobalHookOption; &gt;+use js::jsapi::root::JS::RealmOptions; &gt; use js::jsval::UndefinedValue; &gt; use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS}; &gt; &gt; use std::ptr; &gt; &gt;-fn assert_is_array(cx: *mut js::jsapi::root::JSContext, &gt;- val: js::jsapi::root::JS::HandleValue) { &gt;+fn assert_is_array(cx: *mut js::jsapi::root::JSContext, val: js::jsapi::root::JS::HandleValue) { &gt; let mut is_array = false; &gt;- assert!(unsafe { &gt;- js::jsapi::root::JS_IsArrayObject(cx, val, &amp;mut is_array as *mut _) &gt;- }); &gt;+ assert!(unsafe { js::jsapi::root::JS_IsArrayObject(cx, val, &amp;mut is_array as *mut _) }); &gt; assert!(is_array); &gt; } &gt; &gt; #[test] &gt; fn vec_conversion() { &gt; let rt = Runtime::new(false).unwrap(); &gt; let cx = rt.cx(); &gt; &gt; let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook; &gt; let c_option = RealmOptions::default(); &gt; &gt; unsafe { &gt;- let global = JS_NewGlobalObject(cx, &amp;SIMPLE_GLOBAL_CLASS, &gt;- ptr::null_mut(), h_option, &amp;c_option); &gt;+ let global = JS_NewGlobalObject( &gt;+ cx, &gt;+ &amp;SIMPLE_GLOBAL_CLASS, &gt;+ ptr::null_mut(), &gt;+ h_option, &gt;+ &amp;c_option, &gt;+ ); &gt; rooted!(in(cx) let global_root = global); &gt; let global = global_root.handle(); &gt; &gt; let _ac = AutoCompartment::with_obj(cx, global.get()); &gt; assert!(InitRealmStandardClasses(cx)); &gt; &gt; rooted!(in(cx) let mut rval = UndefinedValue()); &gt; &gt;@@ -51,30 +53,29 @@ fn vec_conversion() { &gt; orig_vec.to_jsval(cx, rval.handle_mut()); &gt; assert_is_array(cx, rval.handle()); &gt; let converted = Vec::&lt;f32&gt;::from_jsval(cx, rval.handle(), ()).unwrap(); &gt; assert_eq!(&amp;orig_vec, converted.get_success_value().unwrap()); &gt; &gt; let orig_vec: Vec&lt;i32&gt; = vec![1, 2, 3]; &gt; orig_vec.to_jsval(cx, rval.handle_mut()); &gt; assert_is_array(cx, rval.handle()); &gt;- let converted = Vec::&lt;i32&gt;::from_jsval(cx, rval.handle(), &gt;- ConversionBehavior::Default).unwrap(); &gt;+ let converted = &gt;+ Vec::&lt;i32&gt;::from_jsval(cx, rval.handle(), ConversionBehavior::Default).unwrap(); &gt; &gt; assert_eq!(&amp;orig_vec, converted.get_success_value().unwrap()); &gt; &gt;- rt.evaluate_script(global, "new Set([1, 2, 3])", &gt;- "test", 1, rval.handle_mut()).unwrap(); &gt;+ rt.evaluate_script(global, "new Set([1, 2, 3])", "test", 1, rval.handle_mut()) &gt;+ .unwrap(); &gt; let converted = &gt;- Vec::&lt;i32&gt;::from_jsval(cx, rval.handle(), &gt;- ConversionBehavior::Default).unwrap(); &gt;+ Vec::&lt;i32&gt;::from_jsval(cx, rval.handle(), ConversionBehavior::Default).unwrap(); &gt; &gt; assert_eq!(&amp;orig_vec, converted.get_success_value().unwrap()); &gt; &gt;- rt.evaluate_script(global, "({})", "test", 1, rval.handle_mut()).unwrap(); &gt;- let converted = Vec::&lt;i32&gt;::from_jsval(cx, rval.handle(), &gt;- ConversionBehavior::Default); &gt;+ rt.evaluate_script(global, "({})", "test", 1, rval.handle_mut()) &gt;+ .unwrap(); &gt;+ let converted = Vec::&lt;i32&gt;::from_jsval(cx, rval.handle(), ConversionBehavior::Default); &gt; assert!(match converted { &gt; Ok(ConversionResult::Failure(_)) =&gt; true, &gt; _ =&gt; false, &gt; }); &gt; } &gt; } &gt;diff --git a/js/src/build.rs b/js/src/build.rs &gt;index e42c1020d0b8..d4ca67837aea 100644 &gt;--- a/js/src/build.rs &gt;+++ b/js/src/build.rs &gt;@@ -11,43 +11,53 @@ fn main() { &gt; let out_dir = env::var("OUT_DIR").expect("Should have env var OUT_DIR"); &gt; let target = env::var("TARGET").expect("Should have env var TARGET"); &gt; &gt; let js_src = env::var("CARGO_MANIFEST_DIR").expect("Should have env var CARGO_MANIFEST_DIR"); &gt; &gt; env::set_var("MAKEFLAGS", format!("-j{}", num_cpus::get())); &gt; env::set_current_dir(&amp;js_src).unwrap(); &gt; &gt;- let variant = format!("{}{}", &gt;- if cfg!(feature = "bigint") { "bigint" } else { "plain" }, &gt;- if cfg!(feature = "debugmozjs") { "debug" } else { "" }); &gt;+ let variant = format!( &gt;+ "{}{}", &gt;+ if cfg!(feature = "bigint") { &gt;+ "bigint" &gt;+ } else { &gt;+ "plain" &gt;+ }, &gt;+ if cfg!(feature = "debugmozjs") { &gt;+ "debug" &gt;+ } else { &gt;+ "" &gt;+ } &gt;+ ); &gt; &gt; let python = env::var("PYTHON").unwrap_or("python2.7".into()); &gt; let mut cmd = Command::new(&amp;python); &gt;- cmd.args(&amp;["./devtools/automation/autospider.py", &gt;- // Only build SpiderMonkey, don't run all the tests. &gt;- "--build-only", &gt;- // Disable Mozilla's jemalloc; Rust has its own jemalloc that we &gt;- // can swap in instead and everything using a single malloc is &gt;- // good. &gt;- "--no-jemalloc", &gt;- // Don't try to clobber the output directory. Without &gt;- // this option, the build will fail because the directory &gt;- // already exists but wasn't created by autospider. &gt;- "--dep", &gt;- "--objdir", &amp;out_dir, &gt;- &amp;variant]) &gt;- .env("SOURCE", &amp;js_src) &gt;- .env("PWD", &amp;js_src) &gt;- .stdout(Stdio::inherit()) &gt;- .stderr(Stdio::inherit()); &gt;+ cmd.args(&amp;[ &gt;+ "./devtools/automation/autospider.py", &gt;+ // Only build SpiderMonkey, don't run all the tests. &gt;+ "--build-only", &gt;+ // Disable Mozilla's jemalloc; Rust has its own jemalloc that we &gt;+ // can swap in instead and everything using a single malloc is &gt;+ // good. &gt;+ "--no-jemalloc", &gt;+ // Don't try to clobber the output directory. Without &gt;+ // this option, the build will fail because the directory &gt;+ // already exists but wasn't created by autospider. &gt;+ "--dep", &gt;+ "--objdir", &gt;+ &amp;out_dir, &gt;+ &amp;variant, &gt;+ ]).env("SOURCE", &amp;js_src) &gt;+ .env("PWD", &amp;js_src) &gt;+ .stdout(Stdio::inherit()) &gt;+ .stderr(Stdio::inherit()); &gt; println!("Running command: {:?}", cmd); &gt;- let result = cmd &gt;- .status() &gt;- .expect("Should spawn autospider OK"); &gt;+ let result = cmd.status().expect("Should spawn autospider OK"); &gt; assert!(result.success(), "autospider should exit OK"); &gt; &gt; println!("cargo:rustc-link-search=native={}/js/src/build", out_dir); &gt; println!("cargo:rustc-link-search=native={}/js/src", out_dir); &gt; println!("cargo:rustc-link-lib=static=js_static"); &gt; &gt; println!("cargo:rustc-link-search=native={}/dist/bin", out_dir); &gt; println!("cargo:rustc-link-lib=nspr4"); &gt;diff --git a/js/src/frontend/binsource/src/main.rs b/js/src/frontend/binsource/src/main.rs &gt;index a69c20faabb0..c33f537b7812 100644 &gt;--- a/js/src/frontend/binsource/src/main.rs &gt;+++ b/js/src/frontend/binsource/src/main.rs &gt;@@ -1,28 +1,29 @@ &gt; extern crate binjs_meta; &gt; extern crate clap; &gt; extern crate env_logger; &gt; extern crate itertools; &gt;-#[macro_use] extern crate log; &gt;+#[macro_use] &gt;+extern crate log; &gt; extern crate webidl; &gt; extern crate yaml_rust; &gt; &gt;-use binjs_meta::export::{ ToWebidl, TypeDeanonymizer, TypeName }; &gt;+use binjs_meta::export::{ToWebidl, TypeDeanonymizer, TypeName}; &gt; use binjs_meta::import::Importer; &gt; use binjs_meta::spec::*; &gt;-use binjs_meta::util:: { Reindentable, ToCases, ToStr }; &gt;+use binjs_meta::util::{Reindentable, ToCases, ToStr}; &gt; &gt;-use std::collections::{ HashMap, HashSet }; &gt;+use std::collections::{HashMap, HashSet}; &gt; use std::fs::*; &gt;-use std::io::{ Read, Write }; &gt;+use std::io::{Read, Write}; &gt; use std::path::Path; &gt; use std::rc::Rc; &gt; &gt;-use clap::{ App, Arg }; &gt;+use clap::{App, Arg}; &gt; &gt; use itertools::Itertools; &gt; &gt; /// Rules for generating the code for parsing a single field &gt; /// of a node. &gt; /// &gt; /// Extracted from the yaml file. &gt; #[derive(Clone, Default)] &gt;@@ -51,17 +52,16 @@ struct FieldRules { &gt; extra_args: Option&lt;Rc&lt;String&gt;&gt;, &gt; } &gt; &gt; #[derive(Clone, Default)] &gt; struct SumRules { &gt; after_arm: Option&lt;String&gt;, &gt; } &gt; &gt;- &gt; /// Rules for generating the code for parsing a full node &gt; /// of a node. &gt; /// &gt; /// Extracted from the yaml file. &gt; #[derive(Clone, Default)] &gt; struct NodeRules { &gt; /// This node inherits from another node. &gt; inherits: Option&lt;NodeName&gt;, &gt;@@ -151,18 +151,17 @@ struct GlobalRules { &gt; /// Documentation for the `BinVariant` class enum. &gt; hpp_tokens_variants_doc: Option&lt;String&gt;, &gt; &gt; /// Per-node rules. &gt; per_node: HashMap&lt;NodeName, NodeRules&gt;, &gt; } &gt; impl GlobalRules { &gt; fn new(syntax: &amp;Spec, yaml: &amp;yaml_rust::yaml::Yaml) -&gt; Self { &gt;- let rules = yaml.as_hash() &gt;- .expect("Rules are not a dictionary"); &gt;+ let rules = yaml.as_hash().expect("Rules are not a dictionary"); &gt; &gt; let mut parser_class_name = None; &gt; let mut parser_class_template = None; &gt; let mut parser_type_ok = None; &gt; let mut parser_default_value = None; &gt; let mut parser_list_append = None; &gt; let mut cpp_header = None; &gt; let mut cpp_footer = None; &gt;@@ -170,17 +169,18 @@ impl GlobalRules { &gt; let mut hpp_tokens_header = None; &gt; let mut hpp_tokens_footer = None; &gt; let mut hpp_tokens_kind_doc = None; &gt; let mut hpp_tokens_field_doc = None; &gt; let mut hpp_tokens_variants_doc = None; &gt; let mut per_node = HashMap::new(); &gt; &gt; for (node_key, node_entries) in rules.iter() { &gt;- let node_key = node_key.as_str() &gt;+ let node_key = node_key &gt;+ .as_str() &gt; .expect("Could not convert node_key to string"); &gt; &gt; match node_key { &gt; "parser" =&gt; { &gt; update_rule_rc(&amp;mut parser_class_name, &amp;node_entries["class-name"]) &gt; .unwrap_or_else(|_| panic!("Rule parser.class-name must be a string")); &gt; update_rule(&amp;mut parser_class_template, &amp;node_entries["class-template"]) &gt; .unwrap_or_else(|_| panic!("Rule parser.class-template must be a string")); &gt;@@ -201,202 +201,323 @@ impl GlobalRules { &gt; } &gt; "hpp" =&gt; { &gt; update_rule(&amp;mut hpp_class_header, &amp;node_entries["class"]["header"]) &gt; .unwrap_or_else(|_| panic!("Rule hpp.class.header must be a string")); &gt; update_rule(&amp;mut hpp_tokens_header, &amp;node_entries["tokens"]["header"]) &gt; .unwrap_or_else(|_| panic!("Rule hpp.tokens.header must be a string")); &gt; update_rule(&amp;mut hpp_tokens_footer, &amp;node_entries["tokens"]["footer"]) &gt; .unwrap_or_else(|_| panic!("Rule hpp.tokens.footer must be a string")); &gt;- update_rule(&amp;mut hpp_tokens_kind_doc, &amp;node_entries["tokens"]["kind"]["doc"]) &gt;- .unwrap_or_else(|_| panic!("Rule hpp.tokens.kind.doc must be a string")); &gt;- update_rule(&amp;mut hpp_tokens_field_doc, &amp;node_entries["tokens"]["field"]["doc"]) &gt;- .unwrap_or_else(|_| panic!("Rule hpp.tokens.field.doc must be a string")); &gt;- update_rule(&amp;mut hpp_tokens_variants_doc, &amp;node_entries["tokens"]["variants"]["doc"]) &gt;- .unwrap_or_else(|_| panic!("Rule hpp.tokens.variants.doc must be a string")); &gt;+ update_rule( &gt;+ &amp;mut hpp_tokens_kind_doc, &gt;+ &amp;node_entries["tokens"]["kind"]["doc"], &gt;+ ).unwrap_or_else(|_| panic!("Rule hpp.tokens.kind.doc must be a string")); &gt;+ update_rule( &gt;+ &amp;mut hpp_tokens_field_doc, &gt;+ &amp;node_entries["tokens"]["field"]["doc"], &gt;+ ).unwrap_or_else(|_| panic!("Rule hpp.tokens.field.doc must be a string")); &gt;+ update_rule( &gt;+ &amp;mut hpp_tokens_variants_doc, &gt;+ &amp;node_entries["tokens"]["variants"]["doc"], &gt;+ ).unwrap_or_else(|_| panic!("Rule hpp.tokens.variants.doc must be a string")); &gt; continue; &gt; } &gt; _ =&gt; {} &gt; } &gt; &gt;- &gt;- let node_name = syntax.get_node_name(&amp;node_key) &gt;+ let node_name = syntax &gt;+ .get_node_name(&amp;node_key) &gt; .unwrap_or_else(|| panic!("Unknown node name {}", node_key)); &gt; &gt;- let hash = node_entries.as_hash() &gt;+ let hash = node_entries &gt;+ .as_hash() &gt; .unwrap_or_else(|| panic!("Node {} isn't a dictionary")); &gt; &gt; let mut node_rule = NodeRules::default(); &gt; for (node_item_key, node_item_entry) in hash { &gt;- let as_string = node_item_key.as_str() &gt;+ let as_string = node_item_key &gt;+ .as_str() &gt; .unwrap_or_else(|| panic!("Keys for rule {} must be strings", node_key)); &gt; match as_string { &gt; "inherits" =&gt; { &gt;- let name = node_item_entry.as_str() &gt;- .unwrap_or_else(|| panic!("Rule {}.{} must be a string", node_key, as_string)); &gt;- let inherits = syntax.get_node_name(name) &gt;+ let name = node_item_entry.as_str().unwrap_or_else(|| { &gt;+ panic!("Rule {}.{} must be a string", node_key, as_string) &gt;+ }); &gt;+ let inherits = syntax &gt;+ .get_node_name(name) &gt; .unwrap_or_else(|| panic!("Unknown node name {}", name)); &gt; node_rule.inherits = Some(inherits).cloned(); &gt; } &gt; "extra-params" =&gt; { &gt; update_rule_rc(&amp;mut node_rule.extra_params, node_item_entry) &gt;- .unwrap_or_else(|()| panic!("Rule {}.{} must be a string", node_key, as_string)); &gt;+ .unwrap_or_else(|()| { &gt;+ panic!("Rule {}.{} must be a string", node_key, as_string) &gt;+ }); &gt; } &gt; "extra-args" =&gt; { &gt;- update_rule_rc(&amp;mut node_rule.extra_args, node_item_entry) &gt;- .unwrap_or_else(|()| panic!("Rule {}.{} must be a string", node_key, as_string)); &gt;+ update_rule_rc(&amp;mut node_rule.extra_args, node_item_entry).unwrap_or_else( &gt;+ |()| panic!("Rule {}.{} must be a string", node_key, as_string), &gt;+ ); &gt; } &gt; "some" =&gt; { &gt; update_rule_rc(&amp;mut node_rule.some_before, &amp;node_item_entry["before"]) &gt;- .unwrap_or_else(|()| panic!("Rule {}.{}.before must be a string", node_key, as_string)); &gt;+ .unwrap_or_else(|()| { &gt;+ panic!("Rule {}.{}.before must be a string", node_key, as_string) &gt;+ }); &gt; update_rule_rc(&amp;mut node_rule.some_after, &amp;node_item_entry["after"]) &gt;- .unwrap_or_else(|()| panic!("Rule {}.{}.after must be a string", node_key, as_string)); &gt;+ .unwrap_or_else(|()| { &gt;+ panic!("Rule {}.{}.after must be a string", node_key, as_string) &gt;+ }); &gt; } &gt; "none" =&gt; { &gt; update_rule_rc(&amp;mut node_rule.none_replace, &amp;node_item_entry["replace"]) &gt;- .unwrap_or_else(|()| panic!("Rule {}.{}.replace must be a string", node_key, as_string)); &gt;+ .unwrap_or_else(|()| { &gt;+ panic!("Rule {}.{}.replace must be a string", node_key, as_string) &gt;+ }); &gt; } &gt; "init" =&gt; { &gt;- update_rule(&amp;mut node_rule.init, node_item_entry) &gt;- .unwrap_or_else(|()| panic!("Rule {}.{} must be a string", node_key, as_string)); &gt;+ update_rule(&amp;mut node_rule.init, node_item_entry).unwrap_or_else(|()| { &gt;+ panic!("Rule {}.{} must be a string", node_key, as_string) &gt;+ }); &gt; } &gt; "build" =&gt; { &gt;- update_rule(&amp;mut node_rule.build_result, node_item_entry) &gt;- .unwrap_or_else(|()| panic!("Rule {}.{} must be a string", node_key, as_string)); &gt;+ update_rule(&amp;mut node_rule.build_result, node_item_entry).unwrap_or_else( &gt;+ |()| panic!("Rule {}.{} must be a string", node_key, as_string), &gt;+ ); &gt; } &gt; "append" =&gt; { &gt;- update_rule(&amp;mut node_rule.append, node_item_entry) &gt;- .unwrap_or_else(|()| panic!("Rule {}.{} must be a string", node_key, as_string)); &gt;+ update_rule(&amp;mut node_rule.append, node_item_entry).unwrap_or_else(|()| { &gt;+ panic!("Rule {}.{} must be a string", node_key, as_string) &gt;+ }); &gt; } &gt; "type-ok" =&gt; { &gt;- update_rule_rc(&amp;mut node_rule.type_ok, node_item_entry) &gt;- .unwrap_or_else(|()| panic!("Rule {}.{} must be a string", node_key, as_string)); &gt;+ update_rule_rc(&amp;mut node_rule.type_ok, node_item_entry).unwrap_or_else( &gt;+ |()| panic!("Rule {}.{} must be a string", node_key, as_string), &gt;+ ); &gt; } &gt; "default-value" =&gt; { &gt; update_rule_rc(&amp;mut node_rule.default_value, node_item_entry) &gt;- .unwrap_or_else(|()| panic!("Rule {}.{} must be a string", node_key, as_string)); &gt;+ .unwrap_or_else(|()| { &gt;+ panic!("Rule {}.{} must be a string", node_key, as_string) &gt;+ }); &gt; } &gt; "fields" =&gt; { &gt;- let fields = node_item_entry.as_hash() &gt;- .unwrap_or_else(|| panic!("Rule {}.fields must be a hash, got {:?}", node_key, node_entries["fields"])); &gt;+ let fields = node_item_entry.as_hash().unwrap_or_else(|| { &gt;+ panic!( &gt;+ "Rule {}.fields must be a hash, got {:?}", &gt;+ node_key, node_entries["fields"] &gt;+ ) &gt;+ }); &gt; for (field_key, field_entry) in fields { &gt;- let field_key = field_key.as_str() &gt;- .unwrap_or_else(|| panic!("In rule {}, field entries must be field names", &gt;- node_key)) &gt;- .to_string(); &gt;- let field_name = syntax.get_field_name(&amp;field_key) &gt;- .unwrap_or_else(|| panic!("In rule {}, can't find field {}", &gt;- node_key, &gt;- field_key)); &gt;+ let field_key = field_key &gt;+ .as_str() &gt;+ .unwrap_or_else(|| { &gt;+ panic!( &gt;+ "In rule {}, field entries must be field names", &gt;+ node_key &gt;+ ) &gt;+ }).to_string(); &gt;+ let field_name = &gt;+ syntax.get_field_name(&amp;field_key).unwrap_or_else(|| { &gt;+ panic!("In rule {}, can't find field {}", node_key, field_key) &gt;+ }); &gt; &gt; let mut field_rule = FieldRules::default(); &gt;- for (field_config_key, field_config_entry) in field_entry.as_hash() &gt;- .unwrap_or_else(|| panic!("Rule {}.fields.{} must be a hash", node_key, field_key)) &gt;- { &gt;- let field_config_key = field_config_key.as_str() &gt;+ for (field_config_key, field_config_entry) in &gt;+ field_entry.as_hash().unwrap_or_else(|| { &gt;+ panic!("Rule {}.fields.{} must be a hash", node_key, field_key) &gt;+ }) { &gt;+ let field_config_key = field_config_key &gt;+ .as_str() &gt; .expect("Expected a string as a key"); &gt;- match field_config_key &gt;- { &gt;+ match field_config_key { &gt; "block" =&gt; { &gt;- update_rule(&amp;mut field_rule.declare, &amp;field_config_entry["declare"]) &gt;- .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "declare")); &gt;+ update_rule( &gt;+ &amp;mut field_rule.declare, &gt;+ &amp;field_config_entry["declare"], &gt;+ ).unwrap_or_else( &gt;+ |()| { &gt;+ panic!( &gt;+ "Rule {}.fields.{}.{}.{} must be a string", &gt;+ node_key, &gt;+ field_key, &gt;+ field_config_key, &gt;+ "declare" &gt;+ ) &gt;+ }, &gt;+ ); &gt; &gt;- update_rule(&amp;mut field_rule.replace, &amp;field_config_entry["replace"]) &gt;- .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "replace")); &gt;+ update_rule( &gt;+ &amp;mut field_rule.replace, &gt;+ &amp;field_config_entry["replace"], &gt;+ ).unwrap_or_else( &gt;+ |()| { &gt;+ panic!( &gt;+ "Rule {}.fields.{}.{}.{} must be a string", &gt;+ node_key, &gt;+ field_key, &gt;+ field_config_key, &gt;+ "replace" &gt;+ ) &gt;+ }, &gt;+ ); &gt; &gt;- update_rule(&amp;mut field_rule.block_before_field, &amp;field_config_entry["before"]) &gt;- .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "before")); &gt;+ update_rule( &gt;+ &amp;mut field_rule.block_before_field, &gt;+ &amp;field_config_entry["before"], &gt;+ ).unwrap_or_else( &gt;+ |()| { &gt;+ panic!( &gt;+ "Rule {}.fields.{}.{}.{} must be a string", &gt;+ node_key, field_key, field_config_key, "before" &gt;+ ) &gt;+ }, &gt;+ ); &gt; &gt;- update_rule(&amp;mut field_rule.block_after_field, &amp;field_config_entry["after"]) &gt;- .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{}.{} must be a string", node_key, field_key, field_config_key, "after")); &gt;+ update_rule( &gt;+ &amp;mut field_rule.block_after_field, &gt;+ &amp;field_config_entry["after"], &gt;+ ).unwrap_or_else( &gt;+ |()| { &gt;+ panic!( &gt;+ "Rule {}.fields.{}.{}.{} must be a string", &gt;+ node_key, field_key, field_config_key, "after" &gt;+ ) &gt;+ }, &gt;+ ); &gt; } &gt; "before" =&gt; { &gt;- update_rule(&amp;mut field_rule.before_field, &amp;field_config_entry) &gt;- .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{} must be a string", node_key, field_key, field_config_key)); &gt;+ update_rule( &gt;+ &amp;mut field_rule.before_field, &gt;+ &amp;field_config_entry, &gt;+ ).unwrap_or_else( &gt;+ |()| { &gt;+ panic!( &gt;+ "Rule {}.fields.{}.{} must be a string", &gt;+ node_key, field_key, field_config_key &gt;+ ) &gt;+ }, &gt;+ ); &gt; } &gt; "after" =&gt; { &gt;- update_rule(&amp;mut field_rule.after_field, &amp;field_config_entry) &gt;- .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{} must be a string", node_key, field_key, field_config_key)); &gt;+ update_rule( &gt;+ &amp;mut field_rule.after_field, &gt;+ &amp;field_config_entry, &gt;+ ).unwrap_or_else( &gt;+ |()| { &gt;+ panic!( &gt;+ "Rule {}.fields.{}.{} must be a string", &gt;+ node_key, field_key, field_config_key &gt;+ ) &gt;+ }, &gt;+ ); &gt; } &gt; "extra-args" =&gt; { &gt;- update_rule_rc(&amp;mut field_rule.extra_args, &amp;field_config_entry) &gt;- .unwrap_or_else(|()| panic!("Rule {}.fields.{}.{} must be a string", node_key, field_key, field_config_key)); &gt;- } &gt;- _ =&gt; { &gt;- panic!("Unexpected {}.fields.{}.{}", node_key, field_key, field_config_key) &gt;+ update_rule_rc( &gt;+ &amp;mut field_rule.extra_args, &gt;+ &amp;field_config_entry, &gt;+ ).unwrap_or_else( &gt;+ |()| { &gt;+ panic!( &gt;+ "Rule {}.fields.{}.{} must be a string", &gt;+ node_key, field_key, field_config_key &gt;+ ) &gt;+ }, &gt;+ ); &gt; } &gt;+ _ =&gt; panic!( &gt;+ "Unexpected {}.fields.{}.{}", &gt;+ node_key, field_key, field_config_key &gt;+ ), &gt; } &gt; } &gt; node_rule.by_field.insert(field_name.clone(), field_rule); &gt; } &gt; } &gt; "sum-arms" =&gt; { &gt;- let arms = node_item_entry.as_hash() &gt;- .unwrap_or_else(|| panic!("Rule {}.sum-arms must be a hash, got {:?}", node_key, node_entries["sum-arms"])); &gt;+ let arms = node_item_entry.as_hash().unwrap_or_else(|| { &gt;+ panic!( &gt;+ "Rule {}.sum-arms must be a hash, got {:?}", &gt;+ node_key, node_entries["sum-arms"] &gt;+ ) &gt;+ }); &gt; for (sum_arm_key, sum_arm_entry) in arms { &gt;- let sum_arm_key = sum_arm_key.as_str() &gt;- .unwrap_or_else(|| panic!("In rule {}, sum arms must be interface names")); &gt;- let sum_arm_name = syntax.get_node_name(&amp;sum_arm_key) &gt;- .unwrap_or_else(|| panic!("In rule {}. cannot find interface {}", node_key, sum_arm_key)); &gt;+ let sum_arm_key = sum_arm_key.as_str().unwrap_or_else(|| { &gt;+ panic!("In rule {}, sum arms must be interface names") &gt;+ }); &gt;+ let sum_arm_name = &gt;+ syntax.get_node_name(&amp;sum_arm_key).unwrap_or_else(|| { &gt;+ panic!( &gt;+ "In rule {}. cannot find interface {}", &gt;+ node_key, sum_arm_key &gt;+ ) &gt;+ }); &gt; &gt; let mut sum_rule = SumRules::default(); &gt;- for (arm_config_key, arm_config_entry) in sum_arm_entry.as_hash() &gt;- .unwrap_or_else(|| panic!("Rule {}.sum-arms.{} must be a hash", node_key, sum_arm_key)) &gt;- { &gt;- let arm_config_key = arm_config_key.as_str() &gt;- .expect("Expected a string as a key"); &gt;- match arm_config_key &gt;- { &gt;+ for (arm_config_key, arm_config_entry) in &gt;+ sum_arm_entry.as_hash().unwrap_or_else(|| { &gt;+ panic!( &gt;+ "Rule {}.sum-arms.{} must be a hash", &gt;+ node_key, sum_arm_key &gt;+ ) &gt;+ }) { &gt;+ let arm_config_key = &gt;+ arm_config_key.as_str().expect("Expected a string as a key"); &gt;+ match arm_config_key { &gt; "after" =&gt; { &gt; update_rule(&amp;mut sum_rule.after_arm, arm_config_entry) &gt;- .unwrap_or_else(|()| panic!("Rule {}.sum-arms.{}.{} must be a string", node_key, sum_arm_key, arm_config_key)); &gt;+ .unwrap_or_else(|()| { &gt;+ panic!( &gt;+ "Rule {}.sum-arms.{}.{} must be a string", &gt;+ node_key, sum_arm_key, arm_config_key &gt;+ ) &gt;+ }); &gt; } &gt; _ =&gt; { &gt;- panic!("Unexpected {}.sum-arms.{}.{}", node_key, sum_arm_key, arm_config_key); &gt;+ panic!( &gt;+ "Unexpected {}.sum-arms.{}.{}", &gt;+ node_key, sum_arm_key, arm_config_key &gt;+ ); &gt; } &gt; } &gt; } &gt; node_rule.by_sum.insert(sum_arm_name.clone(), sum_rule); &gt; } &gt; } &gt;- _ =&gt; panic!("Unexpected node_item_key {}.{}", node_key, as_string) &gt;+ _ =&gt; panic!("Unexpected node_item_key {}.{}", node_key, as_string), &gt; } &gt; } &gt; &gt; per_node.insert(node_name.clone(), node_rule); &gt; } &gt; &gt; Self { &gt;- parser_class_name: parser_class_name &gt;- .expect("parser.class-name should be specified"), &gt;+ parser_class_name: parser_class_name.expect("parser.class-name should be specified"), &gt; parser_class_template: Rc::new(if parser_class_template.is_some() { &gt; format!("{} ", parser_class_template.unwrap()) &gt; } else { &gt; "".to_string() &gt; }), &gt;- parser_type_ok: parser_type_ok &gt;- .expect("parser.type-ok should be specified"), &gt;+ parser_type_ok: parser_type_ok.expect("parser.type-ok should be specified"), &gt; parser_default_value: parser_default_value &gt; .expect("parser.default-value should be specified"), &gt; parser_list_append, &gt; cpp_header, &gt; cpp_footer, &gt; hpp_class_header, &gt; hpp_tokens_header, &gt; hpp_tokens_footer, &gt; hpp_tokens_kind_doc, &gt; hpp_tokens_field_doc, &gt; hpp_tokens_variants_doc, &gt; per_node, &gt; } &gt; } &gt; fn get(&amp;self, name: &amp;NodeName) -&gt; NodeRules { &gt;- let mut rules = self.per_node.get(name) &gt;- .cloned() &gt;- .unwrap_or_default(); &gt;+ let mut rules = self.per_node.get(name).cloned().unwrap_or_default(); &gt; if let Some(ref parent) = rules.inherits { &gt; let NodeRules { &gt; inherits: _, &gt; type_ok, &gt; default_value, &gt; extra_params, &gt; extra_args, &gt; some_before, &gt;@@ -434,22 +555,20 @@ impl GlobalRules { &gt; } &gt; if rules.append.is_none() { &gt; rules.append = append; &gt; } &gt; if rules.build_result.is_none() { &gt; rules.build_result = build_result; &gt; } &gt; for (key, value) in by_field { &gt;- rules.by_field.entry(key) &gt;- .or_insert(value); &gt;+ rules.by_field.entry(key).or_insert(value); &gt; } &gt; for (key, value) in by_sum { &gt;- rules.by_sum.entry(key) &gt;- .or_insert(value); &gt;+ rules.by_sum.entry(key).or_insert(value); &gt; } &gt; } &gt; rules &gt; } &gt; } &gt; &gt; /// The inforamtion used to generate a list parser. &gt; struct ListParserData { &gt;@@ -514,85 +633,105 @@ struct CPPExporter { &gt; &gt; impl CPPExporter { &gt; fn new(syntax: Spec, rules: GlobalRules) -&gt; Self { &gt; let mut list_parsers_to_generate = vec![]; &gt; let mut option_parsers_to_generate = vec![]; &gt; for (parser_node_name, typedef) in syntax.typedefs_by_name() { &gt; if typedef.is_optional() { &gt; let content_name = TypeName::type_spec(typedef.spec()); &gt;- let content_node_name = syntax.get_node_name(&amp;content_name) &gt;- .unwrap_or_else(|| panic!("While generating an option parser, could not find node name {}", content_name)) &gt;- .clone(); &gt;+ let content_node_name = syntax &gt;+ .get_node_name(&amp;content_name) &gt;+ .unwrap_or_else(|| { &gt;+ panic!( &gt;+ "While generating an option parser, could not find node name {}", &gt;+ content_name &gt;+ ) &gt;+ }).clone(); &gt; debug!(target: "generate_spidermonkey", "CPPExporter::new adding optional typedef {:?} =&gt; {:?} =&gt; {:?}", &gt; parser_node_name, &gt; content_name, &gt; content_node_name); &gt; option_parsers_to_generate.push(OptionParserData { &gt; name: parser_node_name.clone(), &gt;- elements: content_node_name &gt;+ elements: content_node_name, &gt; }); &gt;- } else if let TypeSpec::Array { ref contents, ref supports_empty } = *typedef.spec() { &gt;+ } else if let TypeSpec::Array { &gt;+ ref contents, &gt;+ ref supports_empty, &gt;+ } = *typedef.spec() &gt;+ { &gt; let content_name = TypeName::type_(&amp;**contents); &gt;- let content_node_name = syntax.get_node_name(&amp;content_name) &gt;- .unwrap_or_else(|| panic!("While generating an array parser, could not find node name {}", content_name)) &gt;- .clone(); &gt;+ let content_node_name = syntax &gt;+ .get_node_name(&amp;content_name) &gt;+ .unwrap_or_else(|| { &gt;+ panic!( &gt;+ "While generating an array parser, could not find node name {}", &gt;+ content_name &gt;+ ) &gt;+ }).clone(); &gt; list_parsers_to_generate.push(ListParserData { &gt; name: parser_node_name.clone(), &gt; supports_empty: *supports_empty, &gt;- elements: content_node_name &gt;+ elements: content_node_name, &gt; }); &gt; } &gt; } &gt; list_parsers_to_generate.sort_by(|a, b| str::cmp(a.name.to_str(), b.name.to_str())); &gt; option_parsers_to_generate.sort_by(|a, b| str::cmp(a.name.to_str(), b.name.to_str())); &gt; &gt; // Prepare variant_by_symbol, which will let us lookup the BinVariant name of &gt; // a symbol. Since some symbols can appear in several enums (e.g. "+" &gt; // is both a unary and a binary operator), we need to collect all the &gt; // string enums that contain each symbol and come up with a unique name &gt; // (note that there is no guarantee of unicity –Â&nbsp;if collisions show up, &gt; // we may need to tweak the name generation algorithm). &gt;- let mut enum_by_string : HashMap&lt;String, Vec&lt;NodeName&gt;&gt; = HashMap::new(); &gt;- let mut enum_types : HashMap&lt;NodeName, Rc&lt;String&gt;&gt; = HashMap::new(); &gt;+ let mut enum_by_string: HashMap&lt;String, Vec&lt;NodeName&gt;&gt; = HashMap::new(); &gt;+ let mut enum_types: HashMap&lt;NodeName, Rc&lt;String&gt;&gt; = HashMap::new(); &gt; for (name, enum_) in syntax.string_enums_by_name().iter() { &gt;- let type_ = format!("typename {parser_class_name}::{kind}", &gt;- parser_class_name = rules.parser_class_name, &gt;- kind = name.to_class_cases()); &gt;+ let type_ = format!( &gt;+ "typename {parser_class_name}::{kind}", &gt;+ parser_class_name = rules.parser_class_name, &gt;+ kind = name.to_class_cases() &gt;+ ); &gt; enum_types.insert(name.clone(), Rc::new(type_)); &gt; for string in enum_.strings().iter() { &gt;- let vec = enum_by_string.entry(string.clone()) &gt;+ let vec = enum_by_string &gt;+ .entry(string.clone()) &gt; .or_insert_with(|| vec![]); &gt; vec.push(name.clone()); &gt; } &gt; } &gt;- let variants_by_symbol = enum_by_string.drain() &gt;+ let variants_by_symbol = enum_by_string &gt;+ .drain() &gt; .map(|(string, names)| { &gt;- let expanded = format!("{names}{symbol}", &gt;- names = names.iter() &gt;+ let expanded = format!( &gt;+ "{names}{symbol}", &gt;+ names = names &gt;+ .iter() &gt; .map(NodeName::to_str) &gt; .sorted() &gt; .into_iter() &gt; .format("Or"), &gt;- symbol = string.to_cpp_enum_case()); &gt;+ symbol = string.to_cpp_enum_case() &gt;+ ); &gt; (string, expanded) &gt;- }) &gt;- .collect(); &gt;+ }).collect(); &gt; &gt; CPPExporter { &gt; syntax, &gt; rules, &gt; list_parsers_to_generate, &gt; option_parsers_to_generate, &gt; variants_by_symbol, &gt; enum_types, &gt; } &gt; } &gt; &gt;-// ----- Generating the header &gt;+ // ----- Generating the header &gt; &gt; /// Get the type representing a success for parsing this node. &gt; fn get_type_ok(&amp;self, name: &amp;NodeName) -&gt; Rc&lt;String&gt; { &gt; // enum has its own rule. &gt; if self.enum_types.contains_key(name) { &gt; return self.enum_types.get(name).unwrap().clone(); &gt; } &gt; &gt;@@ -612,265 +751,292 @@ impl CPPExporter { &gt; if let Some(type_ok) = rules_for_this_interface.type_ok { &gt; if type_ok.as_str() == "Ok" { &gt; return Rc::new("Ok()".to_string()); &gt; } &gt; } &gt; self.rules.parser_default_value.clone() &gt; } &gt; &gt;- fn get_method_signature(&amp;self, name: &amp;NodeName, prefix: &amp;str, args: &amp;str, &gt;- extra_params: &amp;Option&lt;Rc&lt;String&gt;&gt;) -&gt; String { &gt;+ fn get_method_signature( &gt;+ &amp;self, &gt;+ name: &amp;NodeName, &gt;+ prefix: &amp;str, &gt;+ args: &amp;str, &gt;+ extra_params: &amp;Option&lt;Rc&lt;String&gt;&gt;, &gt;+ ) -&gt; String { &gt; let type_ok = self.get_type_ok(name); &gt; let kind = name.to_class_cases(); &gt; let extra = match extra_params { &gt;- Some(s) =&gt; { &gt;- format!("{}\n{}", &gt;- if args.len() &gt; 0 { &gt;- "," &gt;- } else { &gt;- "" &gt;- }, &gt;- s.reindent(" ")) &gt;- } &gt;- _ =&gt; { &gt;- "".to_string() &gt;- } &gt;+ Some(s) =&gt; format!( &gt;+ "{}\n{}", &gt;+ if args.len() &gt; 0 { "," } else { "" }, &gt;+ s.reindent(" ") &gt;+ ), &gt;+ _ =&gt; "".to_string(), &gt; }; &gt;- format!(" JS::Result&lt;{type_ok}&gt; parse{prefix}{kind}({args}{extra});\n", &gt;+ format!( &gt;+ " JS::Result&lt;{type_ok}&gt; parse{prefix}{kind}({args}{extra});\n", &gt; prefix = prefix, &gt; type_ok = type_ok, &gt; kind = kind, &gt; args = args, &gt; extra = extra, &gt; ) &gt; } &gt; &gt;- fn get_method_definition_start(&amp;self, name: &amp;NodeName, prefix: &amp;str, args: &amp;str, &gt;- extra_params: &amp;Option&lt;Rc&lt;String&gt;&gt;) -&gt; String { &gt;+ fn get_method_definition_start( &gt;+ &amp;self, &gt;+ name: &amp;NodeName, &gt;+ prefix: &amp;str, &gt;+ args: &amp;str, &gt;+ extra_params: &amp;Option&lt;Rc&lt;String&gt;&gt;, &gt;+ ) -&gt; String { &gt; let type_ok = self.get_type_ok(name); &gt; let kind = name.to_class_cases(); &gt; let extra = match extra_params { &gt;- Some(s) =&gt; { &gt;- format!("{}\n{}", &gt;- if args.len() &gt; 0 { &gt;- "," &gt;- } else { &gt;- "" &gt;- }, &gt;- s.reindent(" ")) &gt;- } &gt;- _ =&gt; { &gt;- "".to_string() &gt;- } &gt;+ Some(s) =&gt; format!( &gt;+ "{}\n{}", &gt;+ if args.len() &gt; 0 { "," } else { "" }, &gt;+ s.reindent(" ") &gt;+ ), &gt;+ _ =&gt; "".to_string(), &gt; }; &gt; format!("{parser_class_template}JS::Result&lt;{type_ok}&gt;\n{parser_class_name}::parse{prefix}{kind}({args}{extra})", &gt; parser_class_template = self.rules.parser_class_template, &gt; prefix = prefix, &gt; type_ok = type_ok, &gt; parser_class_name = self.rules.parser_class_name, &gt; kind = kind, &gt; args = args, &gt; extra = extra, &gt; ) &gt; } &gt; &gt;- fn get_method_call(&amp;self, var_name: &amp;str, name: &amp;NodeName, &gt;- prefix: &amp;str, args: &amp;str, &gt;- extra_params: &amp;Option&lt;Rc&lt;String&gt;&gt;, &gt;- call_kind: MethodCallKind) -&gt; String { &gt;+ fn get_method_call( &gt;+ &amp;self, &gt;+ var_name: &amp;str, &gt;+ name: &amp;NodeName, &gt;+ prefix: &amp;str, &gt;+ args: &amp;str, &gt;+ extra_params: &amp;Option&lt;Rc&lt;String&gt;&gt;, &gt;+ call_kind: MethodCallKind, &gt;+ ) -&gt; String { &gt; let type_ok_is_ok = match call_kind { &gt;- MethodCallKind::Decl | MethodCallKind::Var =&gt; { &gt;- self.get_type_ok(name).to_str() == "Ok" &gt;- } &gt;- MethodCallKind::AlwaysDecl | MethodCallKind::AlwaysVar =&gt; { &gt;- false &gt;- } &gt;+ MethodCallKind::Decl | MethodCallKind::Var =&gt; self.get_type_ok(name).to_str() == "Ok", &gt;+ MethodCallKind::AlwaysDecl | MethodCallKind::AlwaysVar =&gt; false, &gt; }; &gt; let extra = match extra_params { &gt;- Some(s) =&gt; { &gt;- format!("{}\n{}", &gt;- if args.len() &gt; 0 { &gt;- "," &gt;- } else { &gt;- "" &gt;- }, &gt;- s.reindent(" ")) &gt;- } &gt;- _ =&gt; { &gt;- "".to_string() &gt;- } &gt;+ Some(s) =&gt; format!( &gt;+ "{}\n{}", &gt;+ if args.len() &gt; 0 { "," } else { "" }, &gt;+ s.reindent(" ") &gt;+ ), &gt;+ _ =&gt; "".to_string(), &gt; }; &gt;- let call = format!("parse{prefix}{name}({args}{extra})", &gt;- prefix = prefix, &gt;- name = name.to_class_cases(), &gt;- args = args, &gt;- extra = extra); &gt;+ let call = format!( &gt;+ "parse{prefix}{name}({args}{extra})", &gt;+ prefix = prefix, &gt;+ name = name.to_class_cases(), &gt;+ args = args, &gt;+ extra = extra &gt;+ ); &gt; &gt; if type_ok_is_ok { &gt; // Special case: `Ok` means that we shouldn't bind the return value. &gt;- format!("MOZ_TRY({call});", &gt;- call = call) &gt;+ format!("MOZ_TRY({call});", call = call) &gt; } else { &gt; match call_kind { &gt;- MethodCallKind::Decl | MethodCallKind::AlwaysDecl =&gt; { &gt;- format!("BINJS_MOZ_TRY_DECL({var_name}, {call});", &gt;- var_name = var_name, call = call) &gt;- } &gt;- MethodCallKind::Var | MethodCallKind::AlwaysVar =&gt; { &gt;- format!("MOZ_TRY_VAR({var_name}, {call});", &gt;- var_name = var_name, call = call) &gt;- } &gt;+ MethodCallKind::Decl | MethodCallKind::AlwaysDecl =&gt; format!( &gt;+ "BINJS_MOZ_TRY_DECL({var_name}, {call});", &gt;+ var_name = var_name, &gt;+ call = call &gt;+ ), &gt;+ MethodCallKind::Var | MethodCallKind::AlwaysVar =&gt; format!( &gt;+ "MOZ_TRY_VAR({var_name}, {call});", &gt;+ var_name = var_name, &gt;+ call = call &gt;+ ), &gt; } &gt; } &gt; } &gt; &gt; /// Declaring enums for kinds and fields. &gt; fn export_declare_kinds_and_fields_enums(&amp;self, buffer: &amp;mut String) { &gt; buffer.push_str(&amp;self.rules.hpp_tokens_header.reindent("")); &gt; &gt; buffer.push_str("\n\n"); &gt; if self.rules.hpp_tokens_kind_doc.is_some() { &gt; buffer.push_str(&amp;self.rules.hpp_tokens_kind_doc.reindent("")); &gt; } &gt; &gt;- let node_names = self.syntax.node_names() &gt;- .keys() &gt;- .sorted(); &gt;- buffer.push_str(&amp;format!("\n#define FOR_EACH_BIN_KIND(F) \\\n{nodes}\n", &gt;- nodes = node_names.iter() &gt;- .map(|name| format!(" F({enum_name}, \"{spec_name}\")", &gt;+ let node_names = self.syntax.node_names().keys().sorted(); &gt;+ buffer.push_str(&amp;format!( &gt;+ "\n#define FOR_EACH_BIN_KIND(F) \\\n{nodes}\n", &gt;+ nodes = node_names &gt;+ .iter() &gt;+ .map(|name| format!( &gt;+ " F({enum_name}, \"{spec_name}\")", &gt; enum_name = name.to_cpp_enum_case(), &gt;- spec_name = name)) &gt;- .format(" \\\n"))); &gt;- buffer.push_str(" &gt;+ spec_name = name &gt;+ )).format(" \\\n") &gt;+ )); &gt;+ buffer.push_str( &gt;+ " &gt; enum class BinKind { &gt; #define EMIT_ENUM(name, _) name, &gt; FOR_EACH_BIN_KIND(EMIT_ENUM) &gt; #undef EMIT_ENUM &gt; }; &gt;-"); &gt;+", &gt;+ ); &gt; &gt; buffer.push_str(&amp;format!("\n// The number of distinct values of BinKind.\nconst size_t BINKIND_LIMIT = {};\n\n\n", self.syntax.node_names().len())); &gt; buffer.push_str("\n\n"); &gt; if self.rules.hpp_tokens_field_doc.is_some() { &gt; buffer.push_str(&amp;self.rules.hpp_tokens_field_doc.reindent("")); &gt; } &gt; &gt;- let field_names = self.syntax.field_names() &gt;- .keys() &gt;- .sorted(); &gt;- buffer.push_str(&amp;format!("\n#define FOR_EACH_BIN_FIELD(F) \\\n{nodes}\n", &gt;- nodes = field_names.iter() &gt;- .map(|name| format!(" F({enum_name}, \"{spec_name}\")", &gt;+ let field_names = self.syntax.field_names().keys().sorted(); &gt;+ buffer.push_str(&amp;format!( &gt;+ "\n#define FOR_EACH_BIN_FIELD(F) \\\n{nodes}\n", &gt;+ nodes = field_names &gt;+ .iter() &gt;+ .map(|name| format!( &gt;+ " F({enum_name}, \"{spec_name}\")", &gt; spec_name = name, &gt;- enum_name = name.to_cpp_enum_case())) &gt;- .format(" \\\n"))); &gt;- buffer.push_str(" &gt;+ enum_name = name.to_cpp_enum_case() &gt;+ )).format(" \\\n") &gt;+ )); &gt;+ buffer.push_str( &gt;+ " &gt; enum class BinField { &gt; #define EMIT_ENUM(name, _) name, &gt; FOR_EACH_BIN_FIELD(EMIT_ENUM) &gt; #undef EMIT_ENUM &gt; }; &gt;-"); &gt;+", &gt;+ ); &gt; buffer.push_str(&amp;format!("\n// The number of distinct values of BinField.\nconst size_t BINFIELD_LIMIT = {};\n\n\n", self.syntax.field_names().len())); &gt; &gt; if self.rules.hpp_tokens_variants_doc.is_some() { &gt; buffer.push_str(&amp;self.rules.hpp_tokens_variants_doc.reindent("")); &gt; } &gt;- let enum_variants : Vec&lt;_&gt; = self.variants_by_symbol &gt;- .iter() &gt;- .sorted_by(|&amp;(ref symbol_1, ref name_1), &amp;(ref symbol_2, ref name_2)| { &gt;- Ord::cmp(name_1, name_2) &gt;- .then_with(|| Ord::cmp(symbol_1, symbol_2)) &gt;- }); &gt;+ let enum_variants: Vec&lt;_&gt; = self.variants_by_symbol.iter().sorted_by( &gt;+ |&amp;(ref symbol_1, ref name_1), &amp;(ref symbol_2, ref name_2)| { &gt;+ Ord::cmp(name_1, name_2).then_with(|| Ord::cmp(symbol_1, symbol_2)) &gt;+ }, &gt;+ ); &gt; &gt;- buffer.push_str(&amp;format!("\n#define FOR_EACH_BIN_VARIANT(F) \\\n{nodes}\n", &gt;- nodes = enum_variants.into_iter() &gt;- .map(|(symbol, name)| format!(" F({variant_name}, \"{spec_name}\")", &gt;+ buffer.push_str(&amp;format!( &gt;+ "\n#define FOR_EACH_BIN_VARIANT(F) \\\n{nodes}\n", &gt;+ nodes = enum_variants &gt;+ .into_iter() &gt;+ .map(|(symbol, name)| format!( &gt;+ " F({variant_name}, \"{spec_name}\")", &gt; spec_name = symbol, &gt;- variant_name = name)) &gt;- .format(" \\\n"))); &gt;+ variant_name = name &gt;+ )).format(" \\\n") &gt;+ )); &gt; &gt;- buffer.push_str(" &gt;+ buffer.push_str( &gt;+ " &gt; enum class BinVariant { &gt; #define EMIT_ENUM(name, _) name, &gt; FOR_EACH_BIN_VARIANT(EMIT_ENUM) &gt; #undef EMIT_ENUM &gt; }; &gt;-"); &gt;+", &gt;+ ); &gt; buffer.push_str(&amp;format!("\n// The number of distinct values of BinVariant.\nconst size_t BINVARIANT_LIMIT = {};\n\n\n", &gt; self.variants_by_symbol.len())); &gt; &gt; buffer.push_str(&amp;self.rules.hpp_tokens_footer.reindent("")); &gt; buffer.push_str("\n"); &gt; } &gt; &gt; /// Declare string enums &gt; fn export_declare_string_enums_classes(&amp;self, buffer: &amp;mut String) { &gt; buffer.push_str("\n\n// ----- Declaring string enums (by lexicographical order)\n"); &gt;- let string_enums_by_name = self.syntax.string_enums_by_name() &gt;+ let string_enums_by_name = self &gt;+ .syntax &gt;+ .string_enums_by_name() &gt; .iter() &gt; .sorted_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str())); &gt; for (name, enum_) in string_enums_by_name { &gt;- let rendered_cases = enum_.strings() &gt;+ let rendered_cases = enum_ &gt;+ .strings() &gt; .iter() &gt;- .map(|str| format!("{case:&lt;20} /* \"{original}\" */", &gt;- case = str.to_cpp_enum_case(), &gt;- original = str)) &gt;- .format(",\n "); &gt;- let rendered = format!("enum class {name} {{\n {cases}\n}};\n\n", &gt;+ .map(|str| { &gt;+ format!( &gt;+ "{case:&lt;20} /* \"{original}\" */", &gt;+ case = str.to_cpp_enum_case(), &gt;+ original = str &gt;+ ) &gt;+ }).format(",\n "); &gt;+ let rendered = format!( &gt;+ "enum class {name} {{\n {cases}\n}};\n\n", &gt; cases = rendered_cases, &gt;- name = name.to_class_cases()); &gt;+ name = name.to_class_cases() &gt;+ ); &gt; buffer.push_str(&amp;rendered); &gt; } &gt; } &gt; &gt; fn export_declare_sums_of_interface_methods(&amp;self, buffer: &amp;mut String) { &gt;- let sums_of_interfaces = self.syntax.resolved_sums_of_interfaces_by_name() &gt;+ let sums_of_interfaces = self &gt;+ .syntax &gt;+ .resolved_sums_of_interfaces_by_name() &gt; .iter() &gt; .sorted_by(|a, b| a.0.cmp(&amp;b.0)); &gt; buffer.push_str("\n\n// ----- Sums of interfaces (by lexicographical order)\n"); &gt; buffer.push_str("// Implementations are autogenerated\n"); &gt; buffer.push_str("// `ParseNode*` may never be nullptr\n"); &gt; for &amp;(ref name, _) in &amp;sums_of_interfaces { &gt; let rules_for_this_sum = self.rules.get(name); &gt; let extra_params = rules_for_this_sum.extra_params; &gt;- let rendered = self.get_method_signature(name, "", "", &gt;- &amp;extra_params); &gt;- buffer.push_str(&amp;rendered.reindent("") &gt;- .newline_if_not_empty()); &gt;+ let rendered = self.get_method_signature(name, "", "", &amp;extra_params); &gt;+ buffer.push_str(&amp;rendered.reindent("").newline_if_not_empty()); &gt; } &gt; for (name, _) in sums_of_interfaces { &gt; let rules_for_this_sum = self.rules.get(name); &gt; let extra_params = rules_for_this_sum.extra_params; &gt;- let rendered = self.get_method_signature(name, "Sum", "const size_t start, const BinKind kind, const BinFields&amp; fields", &gt;- &amp;extra_params); &gt;- buffer.push_str(&amp;rendered.reindent("") &gt;- .newline_if_not_empty()); &gt;+ let rendered = self.get_method_signature( &gt;+ name, &gt;+ "Sum", &gt;+ "const size_t start, const BinKind kind, const BinFields&amp; fields", &gt;+ &amp;extra_params, &gt;+ ); &gt;+ buffer.push_str(&amp;rendered.reindent("").newline_if_not_empty()); &gt; } &gt; } &gt; &gt; fn export_declare_single_interface_methods(&amp;self, buffer: &amp;mut String) { &gt; buffer.push_str("\n\n// ----- Interfaces (by lexicographical order)\n"); &gt; buffer.push_str("// Implementations are autogenerated\n"); &gt; buffer.push_str("// `ParseNode*` may never be nullptr\n"); &gt;- let interfaces_by_name = self.syntax.interfaces_by_name() &gt;+ let interfaces_by_name = self &gt;+ .syntax &gt;+ .interfaces_by_name() &gt; .iter() &gt; .sorted_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str())); &gt; &gt; let mut outer_parsers = Vec::with_capacity(interfaces_by_name.len()); &gt; let mut inner_parsers = Vec::with_capacity(interfaces_by_name.len()); &gt; &gt; for &amp;(name, _) in &amp;interfaces_by_name { &gt; let rules_for_this_interface = self.rules.get(name); &gt; let extra_params = rules_for_this_interface.extra_params; &gt; let outer = self.get_method_signature(name, "", "", &amp;extra_params); &gt;- let inner = self.get_method_signature(name, "Interface", "const size_t start, const BinKind kind, const BinFields&amp; fields", &gt;- &amp;extra_params); &gt;+ let inner = self.get_method_signature( &gt;+ name, &gt;+ "Interface", &gt;+ "const size_t start, const BinKind kind, const BinFields&amp; fields", &gt;+ &amp;extra_params, &gt;+ ); &gt; outer_parsers.push(outer.reindent("")); &gt; inner_parsers.push(inner.reindent("")); &gt; } &gt; &gt; for parser in outer_parsers.drain(..) { &gt; buffer.push_str(&amp;parser); &gt; buffer.push_str("\n"); &gt; } &gt;@@ -879,56 +1045,58 @@ enum class BinVariant { &gt; buffer.push_str(&amp;parser); &gt; buffer.push_str("\n"); &gt; } &gt; } &gt; &gt; fn export_declare_string_enums_methods(&amp;self, buffer: &amp;mut String) { &gt; buffer.push_str("\n\n// ----- String enums (by lexicographical order)\n"); &gt; buffer.push_str("// Implementations are autogenerated\n"); &gt;- let string_enums_by_name = self.syntax.string_enums_by_name() &gt;+ let string_enums_by_name = self &gt;+ .syntax &gt;+ .string_enums_by_name() &gt; .iter() &gt; .sorted_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str())); &gt; for (kind, _) in string_enums_by_name { &gt; let rendered = self.get_method_signature(kind, "", "", &amp;None); &gt; buffer.push_str(&amp;rendered.reindent("")); &gt; buffer.push_str("\n"); &gt; } &gt; } &gt; &gt; fn export_declare_list_methods(&amp;self, buffer: &amp;mut String) { &gt; buffer.push_str("\n\n// ----- Lists (by lexicographical order)\n"); &gt; buffer.push_str("// Implementations are autogenerated\n"); &gt; for parser in &amp;self.list_parsers_to_generate { &gt; let rules_for_this_node = self.rules.get(&amp;parser.name); &gt; let extra_params = rules_for_this_node.extra_params; &gt;- let rendered = self.get_method_signature(&amp;parser.name, "", "", &gt;- &amp;extra_params); &gt;+ let rendered = self.get_method_signature(&amp;parser.name, "", "", &amp;extra_params); &gt; buffer.push_str(&amp;rendered.reindent("")); &gt; buffer.push_str("\n"); &gt; } &gt; } &gt; &gt; fn export_declare_option_methods(&amp;self, buffer: &amp;mut String) { &gt; buffer.push_str("\n\n// ----- Default values (by lexicographical order)\n"); &gt; buffer.push_str("// Implementations are autogenerated\n"); &gt; for parser in &amp;self.option_parsers_to_generate { &gt; let rules_for_this_node = self.rules.get(&amp;parser.name); &gt; let extra_params = rules_for_this_node.extra_params; &gt;- let rendered = self.get_method_signature(&amp;parser.name, "", "", &gt;- &amp;extra_params); &gt;+ let rendered = self.get_method_signature(&amp;parser.name, "", "", &amp;extra_params); &gt; buffer.push_str(&amp;rendered.reindent("")); &gt; buffer.push_str("\n"); &gt; } &gt; } &gt; &gt; fn generate_autogenerated_warning(&amp;self) -&gt; String { &gt;- let warning = format!("// This file was autogenerated by binjs_generate_spidermonkey, &gt;+ let warning = format!( &gt;+ "// This file was autogenerated by binjs_generate_spidermonkey, &gt; // please DO NOT EDIT BY HAND. &gt;-"); &gt;+" &gt;+ ); &gt; warning &gt; } &gt; &gt; /// Generate C++ headers for SpiderMonkey &gt; fn to_spidermonkey_token_hpp(&amp;self) -&gt; String { &gt; let mut buffer = String::new(); &gt; &gt; buffer.push_str(&amp;self.generate_autogenerated_warning()); &gt;@@ -955,88 +1123,112 @@ enum class BinVariant { &gt; &gt; buffer.push_str("\n"); &gt; buffer &gt; } &gt; } &gt; &gt; impl CPPExporter { &gt; /// Generate implementation of a single typesum. &gt;- fn generate_implement_sum(&amp;self, buffer: &amp;mut String, name: &amp;NodeName, nodes: &amp;HashSet&lt;NodeName&gt;) { &gt;+ fn generate_implement_sum( &gt;+ &amp;self, &gt;+ buffer: &amp;mut String, &gt;+ name: &amp;NodeName, &gt;+ nodes: &amp;HashSet&lt;NodeName&gt;, &gt;+ ) { &gt; // Generate comments (FIXME: We should use the actual webidl, not the resolved sum) &gt; let rules_for_this_sum = self.rules.get(name); &gt; let extra_params = rules_for_this_sum.extra_params; &gt; let extra_args = rules_for_this_sum.extra_args; &gt;- let nodes = nodes.iter() &gt;- .sorted(); &gt;+ let nodes = nodes.iter().sorted(); &gt; let kind = name.to_class_cases(); &gt;- let rendered_bnf = format!("/*\n{name} ::= {nodes}\n*/", &gt;- nodes = nodes.iter() &gt;- .format("\n "), &gt;- name = name.to_str()); &gt;+ let rendered_bnf = format!( &gt;+ "/*\n{name} ::= {nodes}\n*/", &gt;+ nodes = nodes.iter().format("\n "), &gt;+ name = name.to_str() &gt;+ ); &gt; &gt; // Generate outer method &gt;- buffer.push_str(&amp;format!("{bnf} &gt;+ buffer.push_str(&amp;format!( &gt;+ "{bnf} &gt; {first_line} &gt; {{ &gt; BinKind kind; &gt; BinFields fields(cx_); &gt; AutoTaggedTuple guard(*tokenizer_); &gt; const auto start = tokenizer_-&gt;offset(); &gt; &gt; MOZ_TRY(tokenizer_-&gt;enterTaggedTuple(kind, fields, guard)); &gt; &gt; {call} &gt; &gt; MOZ_TRY(guard.done()); &gt; return result; &gt; }}\n", &gt;- bnf = rendered_bnf, &gt;- call = self.get_method_call("result", name, &gt;- "Sum", "start, kind, fields", &gt;- &amp;extra_args, &gt;- MethodCallKind::AlwaysDecl) &gt;- .reindent(" "), &gt;- first_line = self.get_method_definition_start(name, "", "", &gt;- &amp;extra_params) &gt;+ bnf = rendered_bnf, &gt;+ call = self &gt;+ .get_method_call( &gt;+ "result", &gt;+ name, &gt;+ "Sum", &gt;+ "start, kind, fields", &gt;+ &amp;extra_args, &gt;+ MethodCallKind::AlwaysDecl &gt;+ ).reindent(" "), &gt;+ first_line = self.get_method_definition_start(name, "", "", &amp;extra_params) &gt; )); &gt; &gt; // Generate inner method &gt; let mut buffer_cases = String::new(); &gt; for node in nodes { &gt;- buffer_cases.push_str(&amp;format!(" &gt;+ buffer_cases.push_str(&amp;format!( &gt;+ " &gt; case BinKind::{variant_name}: &gt; {call} &gt; {arm_after} break;", &gt;- call = self.get_method_call("result", node, &gt;- "Interface", "start, kind, fields", &gt;- &amp;extra_args, &gt;- MethodCallKind::AlwaysVar) &gt;- .reindent(" "), &gt;+ call = self &gt;+ .get_method_call( &gt;+ "result", &gt;+ node, &gt;+ "Interface", &gt;+ "start, kind, fields", &gt;+ &amp;extra_args, &gt;+ MethodCallKind::AlwaysVar &gt;+ ).reindent(" "), &gt; variant_name = node.to_cpp_enum_case(), &gt;- arm_after = rules_for_this_sum.by_sum.get(&amp;node) &gt;+ arm_after = rules_for_this_sum &gt;+ .by_sum &gt;+ .get(&amp;node) &gt; .cloned() &gt;- .unwrap_or_default().after_arm.reindent(" ") &gt;- .newline_if_not_empty())); &gt;+ .unwrap_or_default() &gt;+ .after_arm &gt;+ .reindent(" ") &gt;+ .newline_if_not_empty() &gt;+ )); &gt; } &gt;- buffer.push_str(&amp;format!("\n{first_line} &gt;+ buffer.push_str(&amp;format!( &gt;+ "\n{first_line} &gt; {{ &gt; {type_ok} result; &gt; switch (kind) {{{cases} &gt; default: &gt; return raiseInvalidKind(\"{kind}\", kind); &gt; }} &gt; return result; &gt; }} &gt; &gt; ", &gt; kind = kind, &gt; cases = buffer_cases, &gt;- first_line = self.get_method_definition_start(name, "Sum", "const size_t start, const BinKind kind, const BinFields&amp; fields", &gt;- &amp;extra_params), &gt;+ first_line = self.get_method_definition_start( &gt;+ name, &gt;+ "Sum", &gt;+ "const size_t start, const BinKind kind, const BinFields&amp; fields", &gt;+ &amp;extra_params &gt;+ ), &gt; type_ok = self.get_type_ok(name) &gt; )); &gt; } &gt; &gt; /// Generate the implementation of a single list parser &gt; fn generate_implement_list(&amp;self, buffer: &amp;mut String, parser: &amp;ListParserData) { &gt; let rules_for_this_list = self.rules.get(&amp;parser.name); &gt; let extra_params = rules_for_this_list.extra_params; &gt;@@ -1045,82 +1237,89 @@ impl CPPExporter { &gt; // Warn if some rules are unused. &gt; for &amp;(condition, name) in &amp;[ &gt; (rules_for_this_list.build_result.is_some(), "build:"), &gt; (rules_for_this_list.type_ok.is_some(), "type-ok:"), &gt; (rules_for_this_list.by_field.len() &gt; 0, "fields:"), &gt; (rules_for_this_list.by_sum.len() &gt; 0, "sum-arms:"), &gt; ] { &gt; if condition { &gt;- warn!("In {}, rule `{}` was specified but is ignored.", parser.name, name); &gt;+ warn!( &gt;+ "In {}, rule `{}` was specified but is ignored.", &gt;+ parser.name, name &gt;+ ); &gt; } &gt; } &gt; &gt; let kind = parser.name.to_class_cases(); &gt;- let first_line = self.get_method_definition_start(&amp;parser.name, "", "", &gt;- &amp;extra_params); &gt;+ let first_line = self.get_method_definition_start(&amp;parser.name, "", "", &amp;extra_params); &gt; &gt; let init = match rules_for_this_list.init { &gt; Some(str) =&gt; str.reindent(" "), &gt; None =&gt; { &gt; // We cannot generate the method if we don't know how to initialize the list. &gt;- let rendered = format!(" &gt;+ let rendered = format!( &gt;+ " &gt; {first_line} &gt; {{ &gt; return raiseError(\"FIXME: Not implemented yet ({kind})\"); &gt; }}\n", &gt; first_line = first_line, &gt; kind = kind, &gt; ); &gt; buffer.push_str(&amp;rendered); &gt; return; &gt; } &gt; }; &gt; let append = match rules_for_this_list.append { &gt; Some(str) =&gt; str.reindent(" ").newline_if_not_empty(), &gt;- None =&gt; { &gt;- match self.rules.parser_list_append { &gt;- Some(ref str) =&gt; str.reindent(" ").newline_if_not_empty(), &gt;- None =&gt; "".to_string(), &gt;- } &gt;- } &gt;+ None =&gt; match self.rules.parser_list_append { &gt;+ Some(ref str) =&gt; str.reindent(" ").newline_if_not_empty(), &gt;+ None =&gt; "".to_string(), &gt;+ }, &gt; }; &gt; &gt;- &gt;- let rendered = format!("\n{first_line} &gt;+ let rendered = format!( &gt;+ "\n{first_line} &gt; {{ &gt; uint32_t length; &gt; AutoList guard(*tokenizer_); &gt; &gt; const auto start = tokenizer_-&gt;offset(); &gt; MOZ_TRY(tokenizer_-&gt;enterList(length, guard));{empty_check} &gt; {init} &gt; &gt; for (uint32_t i = 0; i &lt; length; ++i) {{ &gt; {call} &gt; {append} }} &gt; &gt; MOZ_TRY(guard.done()); &gt; return result; &gt; }}\n", &gt; first_line = first_line, &gt;- empty_check = &gt;- if parser.supports_empty { &gt;- "".to_string() &gt;- } else { &gt;- format!("\n if (length == 0)\n return raiseEmpty(\"{kind}\");\n", &gt;- kind = kind) &gt;- }, &gt;- call = self.get_method_call("item", &gt;- &amp;parser.elements, "", "", &gt;- &amp;extra_args, &gt;- MethodCallKind::Decl) &gt;- .reindent(" "), &gt;+ empty_check = if parser.supports_empty { &gt;+ "".to_string() &gt;+ } else { &gt;+ format!( &gt;+ "\n if (length == 0)\n return raiseEmpty(\"{kind}\");\n", &gt;+ kind = kind &gt;+ ) &gt;+ }, &gt;+ call = self &gt;+ .get_method_call( &gt;+ "item", &gt;+ &amp;parser.elements, &gt;+ "", &gt;+ "", &gt;+ &amp;extra_args, &gt;+ MethodCallKind::Decl &gt;+ ).reindent(" "), &gt; init = init, &gt;- append = append); &gt;+ append = append &gt;+ ); &gt; buffer.push_str(&amp;rendered); &gt; } &gt; &gt; fn generate_implement_option(&amp;self, buffer: &amp;mut String, parser: &amp;OptionParserData) { &gt; debug!(target: "generate_spidermonkey", "Implementing optional value {} backed by {}", &gt; parser.name.to_str(), parser.elements.to_str()); &gt; &gt; let rules_for_this_node = self.rules.get(&amp;parser.name); &gt;@@ -1130,43 +1329,56 @@ impl CPPExporter { &gt; // Warn if some rules are unused. &gt; for &amp;(condition, name) in &amp;[ &gt; (rules_for_this_node.build_result.is_some(), "build:"), &gt; (rules_for_this_node.append.is_some(), "append:"), &gt; (rules_for_this_node.by_field.len() &gt; 0, "fields:"), &gt; (rules_for_this_node.by_sum.len() &gt; 0, "sum-arms:"), &gt; ] { &gt; if condition { &gt;- warn!("In {}, rule `{}` was specified but is ignored.", parser.name, name); &gt;+ warn!( &gt;+ "In {}, rule `{}` was specified but is ignored.", &gt;+ parser.name, name &gt;+ ); &gt; } &gt; } &gt; &gt; let type_ok = self.get_type_ok(&amp;parser.name); &gt; let default_value = self.get_default_value(&amp;parser.name); &gt; &gt; // At this stage, thanks to deanonymization, `contents` &gt; // is something like `OptionalFooBar`. &gt;- let named_implementation = &gt;- if let Some(NamedType::Typedef(ref typedef)) = self.syntax.get_type_by_name(&amp;parser.name) { &gt;- assert!(typedef.is_optional()); &gt;- if let TypeSpec::NamedType(ref named) = *typedef.spec() { &gt;- self.syntax.get_type_by_name(named) &gt;- .unwrap_or_else(|| panic!("Internal error: Could not find type {}, which should have been generated.", named.to_str())) &gt;- } else { &gt;- panic!("Internal error: In {}, type {:?} should have been a named type", &gt;- parser.name.to_str(), &gt;- typedef); &gt;- } &gt;+ let named_implementation = if let Some(NamedType::Typedef(ref typedef)) = &gt;+ self.syntax.get_type_by_name(&amp;parser.name) &gt;+ { &gt;+ assert!(typedef.is_optional()); &gt;+ if let TypeSpec::NamedType(ref named) = *typedef.spec() { &gt;+ self.syntax.get_type_by_name(named).unwrap_or_else(|| { &gt;+ panic!( &gt;+ "Internal error: Could not find type {}, which should have been generated.", &gt;+ named.to_str() &gt;+ ) &gt;+ }) &gt; } else { &gt;- panic!("Internal error: In {}, there should be a type with that name", &gt;- parser.name.to_str()); &gt;- }; &gt;+ panic!( &gt;+ "Internal error: In {}, type {:?} should have been a named type", &gt;+ parser.name.to_str(), &gt;+ typedef &gt;+ ); &gt;+ } &gt;+ } else { &gt;+ panic!( &gt;+ "Internal error: In {}, there should be a type with that name", &gt;+ parser.name.to_str() &gt;+ ); &gt;+ }; &gt; match named_implementation { &gt; NamedType::Interface(_) =&gt; { &gt;- buffer.push_str(&amp;format!("{first_line} &gt;+ buffer.push_str(&amp;format!( &gt;+ "{first_line} &gt; {{ &gt; BinKind kind; &gt; BinFields fields(cx_); &gt; AutoTaggedTuple guard(*tokenizer_); &gt; &gt; MOZ_TRY(tokenizer_-&gt;enterTaggedTuple(kind, fields, guard)); &gt; {type_ok} result; &gt; if (kind == BinKind::{null}) {{ &gt;@@ -1178,48 +1390,49 @@ impl CPPExporter { &gt; return raiseInvalidKind(\"{kind}\", kind); &gt; }} &gt; MOZ_TRY(guard.done()); &gt; &gt; return result; &gt; }} &gt; &gt; ", &gt;- first_line = self.get_method_definition_start(&amp;parser.name, "", "", &gt;- &amp;extra_params), &gt;+ first_line = &gt;+ self.get_method_definition_start(&amp;parser.name, "", "", &amp;extra_params), &gt; null = self.syntax.get_null_name().to_cpp_enum_case(), &gt;- call = self.get_method_call("result", &gt;- &amp;parser.elements, &gt;- "Interface", "start, kind, fields", &gt;- &amp;extra_args, &gt;- MethodCallKind::AlwaysVar) &gt;- .reindent(" "), &gt;- before = rules_for_this_node.some_before &gt;- .map_or_else(|| "".to_string(), &gt;- |s| s &gt;- .reindent(" ") &gt;- .newline_if_not_empty()), &gt;- after = rules_for_this_node.some_after &gt;- .map_or_else(|| "".to_string(), &gt;- |s| s &gt;- .reindent(" ") &gt;- .newline_if_not_empty()), &gt;- none_block = rules_for_this_node.none_replace &gt;- .map_or_else(|| format!("result = {default_value};", &gt;- default_value = default_value) &gt;- .reindent(" "), &gt;- |s| s.reindent(" ")), &gt;+ call = self &gt;+ .get_method_call( &gt;+ "result", &gt;+ &amp;parser.elements, &gt;+ "Interface", &gt;+ "start, kind, fields", &gt;+ &amp;extra_args, &gt;+ MethodCallKind::AlwaysVar &gt;+ ).reindent(" "), &gt;+ before = rules_for_this_node.some_before.map_or_else( &gt;+ || "".to_string(), &gt;+ |s| s.reindent(" ").newline_if_not_empty() &gt;+ ), &gt;+ after = rules_for_this_node.some_after.map_or_else( &gt;+ || "".to_string(), &gt;+ |s| s.reindent(" ").newline_if_not_empty() &gt;+ ), &gt;+ none_block = rules_for_this_node.none_replace.map_or_else( &gt;+ || format!("result = {default_value};", default_value = default_value) &gt;+ .reindent(" "), &gt;+ |s| s.reindent(" ") &gt;+ ), &gt; type_ok = type_ok, &gt; kind = parser.elements.to_cpp_enum_case(), &gt; )); &gt; } &gt;- NamedType::Typedef(ref type_) =&gt; { &gt;- match type_.spec() { &gt;- &amp;TypeSpec::TypeSum(_) =&gt; { &gt;- buffer.push_str(&amp;format!("{first_line} &gt;+ NamedType::Typedef(ref type_) =&gt; match type_.spec() { &gt;+ &amp;TypeSpec::TypeSum(_) =&gt; { &gt;+ buffer.push_str(&amp;format!( &gt;+ "{first_line} &gt; {{ &gt; BinKind kind; &gt; BinFields fields(cx_); &gt; AutoTaggedTuple guard(*tokenizer_); &gt; &gt; MOZ_TRY(tokenizer_-&gt;enterTaggedTuple(kind, fields, guard)); &gt; {type_ok} result; &gt; if (kind == BinKind::{null}) {{ &gt;@@ -1229,99 +1442,108 @@ impl CPPExporter { &gt; {before}{call}{after} &gt; }} &gt; MOZ_TRY(guard.done()); &gt; &gt; return result; &gt; }} &gt; &gt; ", &gt;- first_line = self.get_method_definition_start(&amp;parser.name, "", "", &gt;- &amp;extra_params), &gt;- call = self.get_method_call("result", &amp;parser.elements, &gt;- "Sum", "start, kind, fields", &gt;- &amp;extra_args, &gt;- MethodCallKind::AlwaysVar) &gt;+ first_line = &gt;+ self.get_method_definition_start(&amp;parser.name, "", "", &amp;extra_params), &gt;+ call = self &gt;+ .get_method_call( &gt;+ "result", &gt;+ &amp;parser.elements, &gt;+ "Sum", &gt;+ "start, kind, fields", &gt;+ &amp;extra_args, &gt;+ MethodCallKind::AlwaysVar &gt;+ ).reindent(" "), &gt;+ before = rules_for_this_node.some_before.map_or_else( &gt;+ || "".to_string(), &gt;+ |s| s.reindent(" ").newline_if_not_empty() &gt;+ ), &gt;+ after = rules_for_this_node.some_after.map_or_else( &gt;+ || "".to_string(), &gt;+ |s| s.reindent(" ").newline_if_not_empty() &gt;+ ), &gt;+ none_block = rules_for_this_node.none_replace.map_or_else( &gt;+ || format!("result = {default_value};", default_value = default_value) &gt; .reindent(" "), &gt;- before = rules_for_this_node.some_before &gt;- .map_or_else(|| "".to_string(), &gt;- |s| s &gt;- .reindent(" ") &gt;- .newline_if_not_empty()), &gt;- after = rules_for_this_node.some_after &gt;- .map_or_else(|| "".to_string(), &gt;- |s| s &gt;- .reindent(" ") &gt;- .newline_if_not_empty()), &gt;- none_block = rules_for_this_node.none_replace &gt;- .map_or_else(|| format!("result = {default_value};", &gt;- default_value = default_value) &gt;- .reindent(" "), &gt;- |s| s.reindent(" ")), &gt;- type_ok = type_ok, &gt;- null = self.syntax.get_null_name().to_cpp_enum_case(), &gt;- )); &gt;- } &gt;- &amp;TypeSpec::String =&gt; { &gt;- let build_result = rules_for_this_node.init.reindent(" "); &gt;- let first_line = self.get_method_definition_start(&amp;parser.name, "", "", &gt;- &amp;extra_params); &gt;- if build_result.len() == 0 { &gt;- buffer.push_str(&amp;format!("{first_line} &gt;+ |s| s.reindent(" ") &gt;+ ), &gt;+ type_ok = type_ok, &gt;+ null = self.syntax.get_null_name().to_cpp_enum_case(), &gt;+ )); &gt;+ } &gt;+ &amp;TypeSpec::String =&gt; { &gt;+ let build_result = rules_for_this_node.init.reindent(" "); &gt;+ let first_line = &gt;+ self.get_method_definition_start(&amp;parser.name, "", "", &amp;extra_params); &gt;+ if build_result.len() == 0 { &gt;+ buffer.push_str(&amp;format!( &gt;+ "{first_line} &gt; {{ &gt; return raiseError(\"FIXME: Not implemented yet ({kind})\"); &gt; }} &gt; &gt; ", &gt;- first_line = first_line, &gt;- kind = parser.name.to_str())); &gt;- } else { &gt;- buffer.push_str(&amp;format!("{first_line} &gt;+ first_line = first_line, &gt;+ kind = parser.name.to_str() &gt;+ )); &gt;+ } else { &gt;+ buffer.push_str(&amp;format!( &gt;+ "{first_line} &gt; {{ &gt; BINJS_MOZ_TRY_DECL(result, tokenizer_-&gt;readMaybeAtom()); &gt; &gt; {build} &gt; &gt; return result; &gt; }} &gt; &gt; ", &gt;- first_line = first_line, &gt;- build = build_result, &gt;- )); &gt;- } &gt;+ first_line = first_line, &gt;+ build = build_result, &gt;+ )); &gt; } &gt;- _else =&gt; unimplemented!("{:?}", _else) &gt; } &gt;- } &gt;- NamedType::StringEnum(_) =&gt; { &gt;- unimplemented!() &gt;- } &gt;+ _else =&gt; unimplemented!("{:?}", _else), &gt;+ }, &gt;+ NamedType::StringEnum(_) =&gt; unimplemented!(), &gt; } &gt; } &gt; &gt;- fn generate_implement_interface(&amp;self, buffer: &amp;mut String, name: &amp;NodeName, interface: &amp;Interface) { &gt;+ fn generate_implement_interface( &gt;+ &amp;self, &gt;+ buffer: &amp;mut String, &gt;+ name: &amp;NodeName, &gt;+ interface: &amp;Interface, &gt;+ ) { &gt; let rules_for_this_interface = self.rules.get(name); &gt; let extra_params = rules_for_this_interface.extra_params; &gt; let extra_args = rules_for_this_interface.extra_args; &gt; &gt;- for &amp;(condition, rule_name) in &amp;[ &gt;- (rules_for_this_interface.append.is_some(), "build:"), &gt;- ] { &gt;+ for &amp;(condition, rule_name) in &amp;[(rules_for_this_interface.append.is_some(), "build:")] { &gt; if condition { &gt;- warn!("In {}, rule `{}` was specified but is ignored.", name, rule_name); &gt;+ warn!( &gt;+ "In {}, rule `{}` was specified but is ignored.", &gt;+ name, rule_name &gt;+ ); &gt; } &gt; } &gt; &gt; // Generate comments &gt; let comment = format!("\n/*\n{}*/\n", ToWebidl::interface(interface, "", " ")); &gt; buffer.push_str(&amp;comment); &gt; &gt; // Generate public method &gt;- buffer.push_str(&amp;format!("{first_line} &gt;+ buffer.push_str(&amp;format!( &gt;+ "{first_line} &gt; {{ &gt; BinKind kind; &gt; BinFields fields(cx_); &gt; AutoTaggedTuple guard(*tokenizer_); &gt; &gt; MOZ_TRY(tokenizer_-&gt;enterTaggedTuple(kind, fields, guard)); &gt; if (kind != BinKind::{kind}) {{ &gt; return raiseInvalidKind(\"{kind}\", kind); &gt;@@ -1329,180 +1551,265 @@ impl CPPExporter { &gt; const auto start = tokenizer_-&gt;offset(); &gt; {call} &gt; MOZ_TRY(guard.done()); &gt; &gt; return result; &gt; }} &gt; &gt; ", &gt;- first_line = self.get_method_definition_start(name, "", "", &gt;- &amp;extra_params), &gt;+ first_line = self.get_method_definition_start(name, "", "", &amp;extra_params), &gt; kind = name.to_cpp_enum_case(), &gt;- call = self.get_method_call("result", name, &gt;- "Interface", "start, kind, fields", &gt;- &amp;extra_args, &gt;- MethodCallKind::AlwaysDecl) &gt;- .reindent(" ") &gt;+ call = self &gt;+ .get_method_call( &gt;+ "result", &gt;+ name, &gt;+ "Interface", &gt;+ "start, kind, fields", &gt;+ &amp;extra_args, &gt;+ MethodCallKind::AlwaysDecl &gt;+ ).reindent(" ") &gt; )); &gt; &gt; // Generate aux method &gt; let number_of_fields = interface.contents().fields().len(); &gt;- let first_line = self.get_method_definition_start(name, "Interface", "const size_t start, const BinKind kind, const BinFields&amp; fields", &gt;- &amp;extra_params); &gt;+ let first_line = self.get_method_definition_start( &gt;+ name, &gt;+ "Interface", &gt;+ "const size_t start, const BinKind kind, const BinFields&amp; fields", &gt;+ &amp;extra_params, &gt;+ ); &gt; &gt;- let fields_type_list = format!("{{ {} }}", interface.contents() &gt;- .fields() &gt;- .iter() &gt;- .map(|field| format!("BinField::{}", field.name().to_cpp_enum_case())) &gt;- .format(", ")); &gt;+ let fields_type_list = format!( &gt;+ "{{ {} }}", &gt;+ interface &gt;+ .contents() &gt;+ .fields() &gt;+ .iter() &gt;+ .map(|field| format!("BinField::{}", field.name().to_cpp_enum_case())) &gt;+ .format(", ") &gt;+ ); &gt; &gt; let mut fields_implem = String::new(); &gt; for field in interface.contents().fields() { &gt;- let rules_for_this_field = rules_for_this_interface.by_field.get(field.name()) &gt;+ let rules_for_this_field = rules_for_this_interface &gt;+ .by_field &gt;+ .get(field.name()) &gt; .cloned() &gt; .unwrap_or_default(); &gt;- let needs_block = rules_for_this_field.block_before_field.is_some() || rules_for_this_field.block_after_field.is_some(); &gt;+ let needs_block = rules_for_this_field.block_before_field.is_some() &gt;+ || rules_for_this_field.block_after_field.is_some(); &gt; &gt; let var_name = field.name().to_cpp_field_case(); &gt; let (decl_var, parse_var) = match field.type_().get_primitive(&amp;self.syntax) { &gt;- Some(IsNullable { is_nullable: false, content: Primitive::Number }) =&gt; { &gt;+ Some(IsNullable { &gt;+ is_nullable: false, &gt;+ content: Primitive::Number, &gt;+ }) =&gt; { &gt; if needs_block { &gt;- (Some(format!("double {var_name};", var_name = var_name)), &gt;- Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_-&gt;readDouble());", var_name = var_name))) &gt;+ ( &gt;+ Some(format!("double {var_name};", var_name = var_name)), &gt;+ Some(format!( &gt;+ "MOZ_TRY_VAR({var_name}, tokenizer_-&gt;readDouble());", &gt;+ var_name = var_name &gt;+ )), &gt;+ ) &gt; } else { &gt;- (None, &gt;- Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_-&gt;readDouble());", var_name = var_name))) &gt;+ ( &gt;+ None, &gt;+ Some(format!( &gt;+ "BINJS_MOZ_TRY_DECL({var_name}, tokenizer_-&gt;readDouble());", &gt;+ var_name = var_name &gt;+ )), &gt;+ ) &gt; } &gt; } &gt;- Some(IsNullable { is_nullable: false, content: Primitive::Boolean }) =&gt; { &gt;+ Some(IsNullable { &gt;+ is_nullable: false, &gt;+ content: Primitive::Boolean, &gt;+ }) =&gt; { &gt; if needs_block { &gt;- (Some(format!("bool {var_name};", var_name = var_name)), &gt;- Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_-&gt;readBool());", var_name = var_name))) &gt;+ ( &gt;+ Some(format!("bool {var_name};", var_name = var_name)), &gt;+ Some(format!( &gt;+ "MOZ_TRY_VAR({var_name}, tokenizer_-&gt;readBool());", &gt;+ var_name = var_name &gt;+ )), &gt;+ ) &gt; } else { &gt;- (None, &gt;- Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_-&gt;readBool());", var_name = var_name))) &gt;+ ( &gt;+ None, &gt;+ Some(format!( &gt;+ "BINJS_MOZ_TRY_DECL({var_name}, tokenizer_-&gt;readBool());", &gt;+ var_name = var_name &gt;+ )), &gt;+ ) &gt; } &gt; } &gt;- Some(IsNullable { is_nullable: false, content: Primitive::Offset }) =&gt; { &gt;+ Some(IsNullable { &gt;+ is_nullable: false, &gt;+ content: Primitive::Offset, &gt;+ }) =&gt; { &gt; if needs_block { &gt;- (Some(format!("BinTokenReaderBase::SkippableSubTree {var_name};", var_name = var_name)), &gt;- Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_-&gt;readSkippableSubTree());", var_name = var_name))) &gt;+ ( &gt;+ Some(format!( &gt;+ "BinTokenReaderBase::SkippableSubTree {var_name};", &gt;+ var_name = var_name &gt;+ )), &gt;+ Some(format!( &gt;+ "MOZ_TRY_VAR({var_name}, tokenizer_-&gt;readSkippableSubTree());", &gt;+ var_name = var_name &gt;+ )), &gt;+ ) &gt; } else { &gt; (None, &gt; Some(format!("BINJS_MOZ_TRY_DECL({var_name}, tokenizer_-&gt;readSkippableSubTree());", var_name = var_name))) &gt; } &gt; } &gt;- Some(IsNullable { content: Primitive::Void, .. }) =&gt; { &gt;+ Some(IsNullable { &gt;+ content: Primitive::Void, &gt;+ .. &gt;+ }) =&gt; { &gt; warn!("Internal error: We shouldn't have any `void` types at this stage."); &gt;- (Some(format!("// Skipping void field {}", field.name().to_str())), &gt;- None) &gt;- } &gt;- Some(IsNullable { is_nullable: false, content: Primitive::String }) =&gt; { &gt;- (Some(format!("RootedAtom {var_name}(cx_);", var_name = var_name)), &gt;- Some(format!("MOZ_TRY_VAR({var_name}, tokenizer_-&gt;readAtom());", var_name = var_name))) &gt;+ ( &gt;+ Some(format!("// Skipping void field {}", field.name().to_str())), &gt;+ None, &gt;+ ) &gt; } &gt;+ Some(IsNullable { &gt;+ is_nullable: false, &gt;+ content: Primitive::String, &gt;+ }) =&gt; ( &gt;+ Some(format!("RootedAtom {var_name}(cx_);", var_name = var_name)), &gt;+ Some(format!( &gt;+ "MOZ_TRY_VAR({var_name}, tokenizer_-&gt;readAtom());", &gt;+ var_name = var_name &gt;+ )), &gt;+ ), &gt; _else =&gt; { &gt; let typename = TypeName::type_(field.type_()); &gt;- let name = self.syntax.get_node_name(typename.to_str()) &gt;+ let name = self &gt;+ .syntax &gt;+ .get_node_name(typename.to_str()) &gt; .expect("NodeName for the field type should exist."); &gt; let field_extra_args = rules_for_this_field.extra_args; &gt; &gt; let (decl_var, call_kind) = if needs_block { &gt;- (Some(format!("{typename} {var_name};", &gt;- var_name = var_name, &gt;- typename = typename)), &gt;- MethodCallKind::Var) &gt;+ ( &gt;+ Some(format!( &gt;+ "{typename} {var_name};", &gt;+ var_name = var_name, &gt;+ typename = typename &gt;+ )), &gt;+ MethodCallKind::Var, &gt;+ ) &gt; } else { &gt;- (None, &gt;- MethodCallKind::Decl) &gt;+ (None, MethodCallKind::Decl) &gt; }; &gt; &gt;- (decl_var, &gt;- Some(self.get_method_call(var_name.to_str(), &gt;- &amp;name, "", "", &amp;field_extra_args, &gt;- call_kind))) &gt;+ ( &gt;+ decl_var, &gt;+ Some(self.get_method_call( &gt;+ var_name.to_str(), &gt;+ &amp;name, &gt;+ "", &gt;+ "", &gt;+ &amp;field_extra_args, &gt;+ call_kind, &gt;+ )), &gt;+ ) &gt; } &gt; }; &gt; &gt; let rendered = { &gt; if rules_for_this_field.replace.is_some() { &gt; for &amp;(condition, rule_name) in &amp;[ &gt; (rules_for_this_field.before_field.is_some(), "before:"), &gt; (rules_for_this_field.after_field.is_some(), "after:"), &gt; (rules_for_this_field.declare.is_some(), "declare:"), &gt; ] { &gt; if condition { &gt; warn!("In {}, rule `{}` was specified but is ignored because `replace:` is also specified.", name, rule_name); &gt; } &gt; } &gt;- rules_for_this_field.replace.reindent(" ") &gt;- .newline() &gt;+ rules_for_this_field.replace.reindent(" ").newline() &gt; } else { &gt; let before_field = rules_for_this_field.before_field.reindent(" "); &gt; let after_field = rules_for_this_field.after_field.reindent(" "); &gt; let decl_var = if rules_for_this_field.declare.is_some() { &gt; rules_for_this_field.declare.reindent(" ") &gt; } else { &gt; decl_var.reindent(" ") &gt; }; &gt; if needs_block { &gt; let parse_var = parse_var.reindent(" "); &gt;- format!("{before_field}{decl_var} {{ &gt;+ format!( &gt;+ "{before_field}{decl_var} {{ &gt; {block_before_field}{parse_var}{block_after_field} &gt; }} &gt; {after_field}", &gt; before_field = before_field.reindent(" ").newline_if_not_empty(), &gt; decl_var = decl_var.reindent(" ").newline_if_not_empty(), &gt;- block_before_field = rules_for_this_field.block_before_field.reindent(" ").newline_if_not_empty(), &gt;+ block_before_field = rules_for_this_field &gt;+ .block_before_field &gt;+ .reindent(" ") &gt;+ .newline_if_not_empty(), &gt; parse_var = parse_var.reindent(" ").newline_if_not_empty(), &gt;- block_after_field = rules_for_this_field.block_after_field.reindent(" "), &gt;- after_field = after_field.reindent(" ")) &gt;+ block_after_field = &gt;+ rules_for_this_field.block_after_field.reindent(" "), &gt;+ after_field = after_field.reindent(" ") &gt;+ ) &gt; } else { &gt; // We have a before_field and an after_field. This will create newlines &gt; // for them. &gt;- format!(" &gt;+ format!( &gt;+ " &gt; {before_field}{decl_var}{parse_var}{after_field}", &gt; before_field = before_field.reindent(" ").newline_if_not_empty(), &gt; decl_var = decl_var.reindent(" ").newline_if_not_empty(), &gt; parse_var = parse_var.reindent(" ").newline_if_not_empty(), &gt;- after_field = after_field.reindent(" ")) &gt;+ after_field = after_field.reindent(" ") &gt;+ ) &gt; } &gt; } &gt; }; &gt; fields_implem.push_str(&amp;rendered); &gt; } &gt; &gt; let init = rules_for_this_interface.init.reindent(" "); &gt; let build_result = rules_for_this_interface.build_result.reindent(" "); &gt; &gt; if build_result == "" { &gt;- buffer.push_str(&amp;format!("{first_line} &gt;+ buffer.push_str(&amp;format!( &gt;+ "{first_line} &gt; {{ &gt; return raiseError(\"FIXME: Not implemented yet ({class_name})\"); &gt; }} &gt; &gt; ", &gt; class_name = name.to_class_cases(), &gt; first_line = first_line, &gt; )); &gt; } else { &gt; let check_fields = if number_of_fields == 0 { &gt; format!("MOZ_TRY(tokenizer_-&gt;checkFields0(kind, fields));") &gt; } else { &gt; // The following strategy is designed for old versions of clang. &gt;- format!(" &gt;+ format!( &gt;+ " &gt; #if defined(DEBUG) &gt; const BinField expected_fields[{number_of_fields}] = {fields_type_list}; &gt; MOZ_TRY(tokenizer_-&gt;checkFields(kind, fields, expected_fields)); &gt; #endif // defined(DEBUG)", &gt; fields_type_list = fields_type_list, &gt;- number_of_fields = number_of_fields) &gt;+ number_of_fields = number_of_fields &gt;+ ) &gt; }; &gt;- buffer.push_str(&amp;format!("{first_line} &gt;+ buffer.push_str(&amp;format!( &gt;+ "{first_line} &gt; {{ &gt; MOZ_ASSERT(kind == BinKind::{kind}); &gt; BINJS_TRY(CheckRecursionLimit(cx_)); &gt; {check_fields} &gt; {pre}{fields_implem} &gt; {post} return result; &gt; }} &gt; &gt;@@ -1523,84 +1830,93 @@ impl CPPExporter { &gt; &gt; buffer.push_str(&amp;self.generate_autogenerated_warning()); &gt; &gt; // 0. Header &gt; buffer.push_str(&amp;self.rules.cpp_header.reindent("")); &gt; buffer.push_str("\n"); &gt; &gt; // 1. Typesums &gt;- buffer.push_str("\n\n// ----- Sums of interfaces (autogenerated, by lexicographical order)\n"); &gt;+ buffer.push_str( &gt;+ "\n\n// ----- Sums of interfaces (autogenerated, by lexicographical order)\n", &gt;+ ); &gt; buffer.push_str("// Sums of sums are flattened.\n"); &gt; &gt;- let sums_of_interfaces = self.syntax.resolved_sums_of_interfaces_by_name() &gt;+ let sums_of_interfaces = self &gt;+ .syntax &gt;+ .resolved_sums_of_interfaces_by_name() &gt; .iter() &gt; .sorted_by(|a, b| a.0.cmp(&amp;b.0)); &gt; &gt; for (name, nodes) in sums_of_interfaces { &gt; self.generate_implement_sum(&amp;mut buffer, name, nodes); &gt; } &gt; &gt; // 2. Single interfaces &gt; buffer.push_str("\n\n// ----- Interfaces (autogenerated, by lexicographical order)\n"); &gt; buffer.push_str("// When fields have a non-trivial type, implementation is deanonymized and delegated to another parser.\n"); &gt;- let interfaces_by_name = self.syntax.interfaces_by_name() &gt;+ let interfaces_by_name = self &gt;+ .syntax &gt;+ .interfaces_by_name() &gt; .iter() &gt; .sorted_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str())); &gt; &gt; for (name, interface) in interfaces_by_name { &gt; self.generate_implement_interface(&amp;mut buffer, name, interface); &gt; } &gt; &gt; // 3. String Enums &gt; buffer.push_str("\n\n// ----- String enums (autogenerated, by lexicographical order)\n"); &gt; { &gt;- let string_enums_by_name = self.syntax.string_enums_by_name() &gt;+ let string_enums_by_name = self &gt;+ .syntax &gt;+ .string_enums_by_name() &gt; .iter() &gt; .sorted_by(|a, b| str::cmp(a.0.to_str(), b.0.to_str())); &gt; for (kind, enum_) in string_enums_by_name { &gt;- let convert = format!(" switch (variant) {{ &gt;+ let convert = format!( &gt;+ " switch (variant) {{ &gt; {cases} &gt; default: &gt; return raiseInvalidVariant(\"{kind}\", variant); &gt; }}", &gt; kind = kind, &gt;- cases = enum_.strings() &gt;+ cases = enum_ &gt;+ .strings() &gt; .iter() &gt;- .map(|symbol| { &gt;- format!(" case BinVariant::{binvariant_variant}: &gt;+ .map(|symbol| format!( &gt;+ " case BinVariant::{binvariant_variant}: &gt; return {kind}::{specialized_variant};", &gt;- kind = kind, &gt;- specialized_variant = symbol.to_cpp_enum_case(), &gt;- binvariant_variant = self.variants_by_symbol.get(symbol) &gt;- .unwrap() &gt;- ) &gt;- }) &gt;- .format("\n") &gt;+ kind = kind, &gt;+ specialized_variant = symbol.to_cpp_enum_case(), &gt;+ binvariant_variant = self.variants_by_symbol.get(symbol).unwrap() &gt;+ )).format("\n") &gt; ); &gt; &gt;- let rendered_doc = format!("/*\nenum {kind} {{\n{cases}\n}};\n*/\n", &gt;+ let rendered_doc = format!( &gt;+ "/*\nenum {kind} {{\n{cases}\n}};\n*/\n", &gt; kind = kind, &gt;- cases = enum_.strings() &gt;- .iter() &gt;- .map(|s| format!(" \"{}\"", s)) &gt;- .format(",\n") &gt;+ cases = enum_ &gt;+ .strings() &gt;+ .iter() &gt;+ .map(|s| format!(" \"{}\"", s)) &gt;+ .format(",\n") &gt; ); &gt;- buffer.push_str(&amp;format!("{rendered_doc}{first_line} &gt;+ buffer.push_str(&amp;format!( &gt;+ "{rendered_doc}{first_line} &gt; {{ &gt; BINJS_MOZ_TRY_DECL(variant, tokenizer_-&gt;readVariant()); &gt; &gt; {convert} &gt; }} &gt; &gt; ", &gt; rendered_doc = rendered_doc, &gt; convert = convert, &gt;- first_line = self.get_method_definition_start(kind, "", "", &gt;- &amp;None) &gt;+ first_line = self.get_method_definition_start(kind, "", "", &amp;None) &gt; )); &gt; } &gt; } &gt; &gt; // 4. Lists &gt; buffer.push_str("\n\n// ----- Lists (autogenerated, by lexicographical order)\n"); &gt; for parser in &amp;self.list_parsers_to_generate { &gt; self.generate_implement_list(&amp;mut buffer, parser); &gt;@@ -1617,25 +1933,28 @@ impl CPPExporter { &gt; buffer.push_str("\n"); &gt; &gt; buffer &gt; } &gt; } &gt; &gt; fn update_rule(rule: &amp;mut Option&lt;String&gt;, entry: &amp;yaml_rust::Yaml) -&gt; Result&lt;Option&lt;()&gt;, ()&gt; { &gt; if entry.is_badvalue() { &gt;- return Ok(None) &gt;+ return Ok(None); &gt; } else if let Some(as_str) = entry.as_str() { &gt; *rule = Some(as_str.to_string()); &gt; Ok(Some(())) &gt; } else { &gt; Err(()) &gt; } &gt; } &gt;-fn update_rule_rc(rule: &amp;mut Option&lt;Rc&lt;String&gt;&gt;, entry: &amp;yaml_rust::Yaml) -&gt; Result&lt;Option&lt;()&gt;, ()&gt; { &gt;+fn update_rule_rc( &gt;+ rule: &amp;mut Option&lt;Rc&lt;String&gt;&gt;, &gt;+ entry: &amp;yaml_rust::Yaml, &gt;+) -&gt; Result&lt;Option&lt;()&gt;, ()&gt; { &gt; let mut value = None; &gt; let ret = update_rule(&amp;mut value, entry)?; &gt; if let Some(s) = value { &gt; *rule = Some(Rc::new(s)); &gt; } &gt; Ok(ret) &gt; } &gt; &gt;@@ -1665,105 +1984,116 @@ fn main() { &gt; Arg::with_name("OUT_IMPL_FILE") &gt; .long("out-impl") &gt; .required(true) &gt; .takes_value(true) &gt; .help("Output implementation file (.cpp)"), &gt; ]) &gt; .get_matches(); &gt; &gt;- let source_path = matches.value_of("INPUT.webidl") &gt;+ let source_path = matches &gt;+ .value_of("INPUT.webidl") &gt; .expect("Expected INPUT.webidl"); &gt; &gt;- let mut file = File::open(source_path) &gt;- .expect("Could not open source"); &gt;+ let mut file = File::open(source_path).expect("Could not open source"); &gt; let mut source = String::new(); &gt; file.read_to_string(&amp;mut source) &gt; .expect("Could not read source"); &gt; &gt; println!("...parsing webidl"); &gt;- let ast = webidl::parse_string(&amp;source) &gt;- .expect("Could not parse source"); &gt;+ let ast = webidl::parse_string(&amp;source).expect("Could not parse source"); &gt; &gt; println!("...verifying grammar"); &gt; let mut builder = Importer::import(&amp;ast); &gt; let fake_root = builder.node_name("@@ROOT@@"); // Unused &gt; let null = builder.node_name(""); // Used &gt;- builder.add_interface(&amp;null) &gt;- .unwrap(); &gt;+ builder.add_interface(&amp;null).unwrap(); &gt; let syntax = builder.into_spec(SpecOptions { &gt; root: &amp;fake_root, &gt; null: &amp;null, &gt; }); &gt; &gt; let deanonymizer = TypeDeanonymizer::new(&amp;syntax); &gt; let syntax_options = SpecOptions { &gt; root: &amp;fake_root, &gt; null: &amp;null, &gt; }; &gt; let new_syntax = deanonymizer.into_spec(syntax_options); &gt; &gt; let rules_source_path = matches.value_of("INPUT.yaml").unwrap(); &gt; println!("...generating rules"); &gt;- let mut file = File::open(rules_source_path) &gt;- .expect("Could not open rules"); &gt;+ let mut file = File::open(rules_source_path).expect("Could not open rules"); &gt; let mut data = String::new(); &gt; file.read_to_string(&amp;mut data) &gt; .expect("Could not read rules"); &gt; &gt;- let yaml = yaml_rust::YamlLoader::load_from_str(&amp;data) &gt;- .expect("Could not parse rules"); &gt;+ let yaml = yaml_rust::YamlLoader::load_from_str(&amp;data).expect("Could not parse rules"); &gt; assert_eq!(yaml.len(), 1); &gt; &gt; let global_rules = GlobalRules::new(&amp;new_syntax, &amp;yaml[0]); &gt; let exporter = CPPExporter::new(new_syntax, global_rules); &gt; &gt; let get_file_content = |path: &amp;str| { &gt; if !Path::new(path).is_file() { &gt; return None; &gt; } &gt; &gt;- let mut f = File::open(path) &gt;- .expect("File not found"); &gt;+ let mut f = File::open(path).expect("File not found"); &gt; let mut contents = String::new(); &gt; f.read_to_string(&amp;mut contents) &gt; .expect("Failed to read file"); &gt; Some(contents) &gt; }; &gt; let write_to = |description, arg, data: &amp;String| { &gt;- let dest_path = matches.value_of(arg) &gt;- .unwrap(); &gt;- print!("...exporting {description}: {path} ... ", &gt;+ let dest_path = matches.value_of(arg).unwrap(); &gt;+ print!( &gt;+ "...exporting {description}: {path} ... ", &gt; description = description, &gt;- path = dest_path); &gt;+ path = dest_path &gt;+ ); &gt; &gt; if let Some(old_data) = get_file_content(dest_path) { &gt; if old_data == *data { &gt; // To avoid unnecessary rebuild, do not touch the file if the &gt; // content is not updated. &gt; println!("skip"); &gt; return; &gt; } &gt; }; &gt; &gt;- let mut dest = File::create(&amp;dest_path) &gt;- .unwrap_or_else(|e| panic!("Could not create {description} at {path}: {error}", &gt;- description = description, &gt;- path = dest_path, &gt;- error = e)); &gt;- dest.write_all(data.as_bytes()) &gt;- .unwrap_or_else(|e| panic!("Could not write {description} at {path}: {error}", &gt;- description = description, &gt;- path = dest_path, &gt;- error = e)); &gt;+ let mut dest = File::create(&amp;dest_path).unwrap_or_else(|e| { &gt;+ panic!( &gt;+ "Could not create {description} at {path}: {error}", &gt;+ description = description, &gt;+ path = dest_path, &gt;+ error = e &gt;+ ) &gt;+ }); &gt;+ dest.write_all(data.as_bytes()).unwrap_or_else(|e| { &gt;+ panic!( &gt;+ "Could not write {description} at {path}: {error}", &gt;+ description = description, &gt;+ path = dest_path, &gt;+ error = e &gt;+ ) &gt;+ }); &gt; &gt; println!("done"); &gt; }; &gt; &gt;- write_to("C++ class header code", "OUT_HEADER_CLASS_FILE", &gt;- &amp;exporter.to_spidermonkey_class_hpp()); &gt;- write_to("C++ token header code", "OUT_TOKEN_FILE", &gt;- &amp;exporter.to_spidermonkey_token_hpp()); &gt;- write_to("C++ token implementation code", "OUT_IMPL_FILE", &gt;- &amp;exporter.to_spidermonkey_cpp()); &gt;+ write_to( &gt;+ "C++ class header code", &gt;+ "OUT_HEADER_CLASS_FILE", &gt;+ &amp;exporter.to_spidermonkey_class_hpp(), &gt;+ ); &gt;+ write_to( &gt;+ "C++ token header code", &gt;+ "OUT_TOKEN_FILE", &gt;+ &amp;exporter.to_spidermonkey_token_hpp(), &gt;+ ); &gt;+ write_to( &gt;+ "C++ token implementation code", &gt;+ "OUT_IMPL_FILE", &gt;+ &amp;exporter.to_spidermonkey_cpp(), &gt;+ ); &gt; &gt; println!("...done"); &gt; } &gt;diff --git a/js/src/lib.rs b/js/src/lib.rs &gt;index d8f6ce78db7e..390dfe414163 100644 &gt;--- a/js/src/lib.rs &gt;+++ b/js/src/lib.rs &gt;@@ -1,2 +1 @@ &gt; extern crate libz_sys; &gt;- &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs b/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs &gt;index 2972eba0d664..1d4c2e636372 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_funcs.rs &gt;@@ -1,159 +1,219 @@ &gt; // This code is generated. &gt; &gt; use super::*; &gt; &gt; #[cfg(feature = "dlopen")] &gt; macro_rules! cstr { &gt;- ($x:expr) =&gt; { concat!($x, "\0").as_bytes().as_ptr() as *const c_char } &gt;+ ($x:expr) =&gt; { &gt;+ concat!($x, "\0").as_bytes().as_ptr() as *const c_char &gt;+ }; &gt; } &gt; &gt; #[cfg(not(feature = "dlopen"))] &gt; mod static_fns { &gt; use super::*; &gt; use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void}; &gt; &gt; #[link(name = "pulse")] &gt; extern "C" { &gt; pub fn pa_get_library_version() -&gt; *const c_char; &gt; pub fn pa_channel_map_can_balance(map: *const pa_channel_map) -&gt; c_int; &gt; pub fn pa_channel_map_init(m: *mut pa_channel_map) -&gt; *mut pa_channel_map; &gt;- pub fn pa_context_connect(c: *mut pa_context, &gt;- server: *const c_char, &gt;- flags: pa_context_flags_t, &gt;- api: *const pa_spawn_api) &gt;- -&gt; c_int; &gt;+ pub fn pa_context_connect( &gt;+ c: *mut pa_context, &gt;+ server: *const c_char, &gt;+ flags: pa_context_flags_t, &gt;+ api: *const pa_spawn_api, &gt;+ ) -&gt; c_int; &gt; pub fn pa_context_disconnect(c: *mut pa_context); &gt;- pub fn pa_context_drain(c: *mut pa_context, &gt;- cb: pa_context_notify_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation; &gt;- pub fn pa_context_get_server_info(c: *const pa_context, &gt;- cb: pa_server_info_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation; &gt;- pub fn pa_context_get_sink_info_by_name(c: *const pa_context, &gt;- name: *const c_char, &gt;- cb: pa_sink_info_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation; &gt;- pub fn pa_context_get_sink_info_list(c: *const pa_context, &gt;- cb: pa_sink_info_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation; &gt;- pub fn pa_context_get_sink_input_info(c: *const pa_context, &gt;- idx: u32, &gt;- cb: pa_sink_input_info_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation; &gt;- pub fn pa_context_get_source_info_list(c: *const pa_context, &gt;- cb: pa_source_info_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation; &gt;+ pub fn pa_context_drain( &gt;+ c: *mut pa_context, &gt;+ cb: pa_context_notify_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation; &gt;+ pub fn pa_context_get_server_info( &gt;+ c: *const pa_context, &gt;+ cb: pa_server_info_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation; &gt;+ pub fn pa_context_get_sink_info_by_name( &gt;+ c: *const pa_context, &gt;+ name: *const c_char, &gt;+ cb: pa_sink_info_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation; &gt;+ pub fn pa_context_get_sink_info_list( &gt;+ c: *const pa_context, &gt;+ cb: pa_sink_info_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation; &gt;+ pub fn pa_context_get_sink_input_info( &gt;+ c: *const pa_context, &gt;+ idx: u32, &gt;+ cb: pa_sink_input_info_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation; &gt;+ pub fn pa_context_get_source_info_list( &gt;+ c: *const pa_context, &gt;+ cb: pa_source_info_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation; &gt; pub fn pa_context_get_state(c: *const pa_context) -&gt; pa_context_state_t; &gt;- pub fn pa_context_new(mainloop: *mut pa_mainloop_api, name: *const c_char) -&gt; *mut pa_context; &gt;- pub fn pa_context_rttime_new(c: *const pa_context, &gt;- usec: pa_usec_t, &gt;- cb: pa_time_event_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_time_event; &gt;- pub fn pa_context_set_sink_input_volume(c: *mut pa_context, &gt;- idx: u32, &gt;- volume: *const pa_cvolume, &gt;- cb: pa_context_success_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation; &gt;- pub fn pa_context_set_state_callback(c: *mut pa_context, cb: pa_context_notify_cb_t, userdata: *mut c_void); &gt;+ pub fn pa_context_new( &gt;+ mainloop: *mut pa_mainloop_api, &gt;+ name: *const c_char, &gt;+ ) -&gt; *mut pa_context; &gt;+ pub fn pa_context_rttime_new( &gt;+ c: *const pa_context, &gt;+ usec: pa_usec_t, &gt;+ cb: pa_time_event_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_time_event; &gt;+ pub fn pa_context_set_sink_input_volume( &gt;+ c: *mut pa_context, &gt;+ idx: u32, &gt;+ volume: *const pa_cvolume, &gt;+ cb: pa_context_success_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation; &gt;+ pub fn pa_context_set_state_callback( &gt;+ c: *mut pa_context, &gt;+ cb: pa_context_notify_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ); &gt; pub fn pa_context_errno(c: *mut pa_context) -&gt; c_int; &gt;- pub fn pa_context_set_subscribe_callback(c: *mut pa_context, &gt;- cb: pa_context_subscribe_cb_t, &gt;- userdata: *mut c_void); &gt;- pub fn pa_context_subscribe(c: *mut pa_context, &gt;- m: pa_subscription_mask_t, &gt;- cb: pa_context_success_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation; &gt;+ pub fn pa_context_set_subscribe_callback( &gt;+ c: *mut pa_context, &gt;+ cb: pa_context_subscribe_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ); &gt;+ pub fn pa_context_subscribe( &gt;+ c: *mut pa_context, &gt;+ m: pa_subscription_mask_t, &gt;+ cb: pa_context_success_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation; &gt; pub fn pa_context_ref(c: *mut pa_context) -&gt; *mut pa_context; &gt; pub fn pa_context_unref(c: *mut pa_context); &gt;- pub fn pa_cvolume_set(a: *mut pa_cvolume, channels: c_uint, v: pa_volume_t) -&gt; *mut pa_cvolume; &gt;- pub fn pa_cvolume_set_balance(v: *mut pa_cvolume, &gt;- map: *const pa_channel_map, &gt;- new_balance: c_float) &gt;- -&gt; *mut pa_cvolume; &gt;+ pub fn pa_cvolume_set( &gt;+ a: *mut pa_cvolume, &gt;+ channels: c_uint, &gt;+ v: pa_volume_t, &gt;+ ) -&gt; *mut pa_cvolume; &gt;+ pub fn pa_cvolume_set_balance( &gt;+ v: *mut pa_cvolume, &gt;+ map: *const pa_channel_map, &gt;+ new_balance: c_float, &gt;+ ) -&gt; *mut pa_cvolume; &gt; pub fn pa_frame_size(spec: *const pa_sample_spec) -&gt; usize; &gt;- pub fn pa_mainloop_api_once(m: *mut pa_mainloop_api, &gt;- callback: pa_mainloop_api_once_cb_t, &gt;- userdata: *mut c_void); &gt;+ pub fn pa_mainloop_api_once( &gt;+ m: *mut pa_mainloop_api, &gt;+ callback: pa_mainloop_api_once_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ); &gt; pub fn pa_strerror(error: pa_error_code_t) -&gt; *const c_char; &gt; pub fn pa_operation_ref(o: *mut pa_operation) -&gt; *mut pa_operation; &gt; pub fn pa_operation_unref(o: *mut pa_operation); &gt; pub fn pa_operation_cancel(o: *mut pa_operation); &gt; pub fn pa_operation_get_state(o: *const pa_operation) -&gt; pa_operation_state_t; &gt;- pub fn pa_operation_set_state_callback(o: *mut pa_operation, &gt;- cb: pa_operation_notify_cb_t, &gt;- userdata: *mut c_void); &gt;+ pub fn pa_operation_set_state_callback( &gt;+ o: *mut pa_operation, &gt;+ cb: pa_operation_notify_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ); &gt; pub fn pa_proplist_gets(p: *mut pa_proplist, key: *const c_char) -&gt; *const c_char; &gt; pub fn pa_rtclock_now() -&gt; pa_usec_t; &gt;- pub fn pa_stream_begin_write(p: *mut pa_stream, data: *mut *mut c_void, nbytes: *mut usize) -&gt; c_int; &gt;+ pub fn pa_stream_begin_write( &gt;+ p: *mut pa_stream, &gt;+ data: *mut *mut c_void, &gt;+ nbytes: *mut usize, &gt;+ ) -&gt; c_int; &gt; pub fn pa_stream_cancel_write(p: *mut pa_stream) -&gt; c_int; &gt; pub fn pa_stream_is_suspended(s: *const pa_stream) -&gt; c_int; &gt; pub fn pa_stream_is_corked(s: *const pa_stream) -&gt; c_int; &gt;- pub fn pa_stream_connect_playback(s: *mut pa_stream, &gt;- dev: *const c_char, &gt;- attr: *const pa_buffer_attr, &gt;- flags: pa_stream_flags_t, &gt;- volume: *const pa_cvolume, &gt;- sync_stream: *const pa_stream) &gt;- -&gt; c_int; &gt;- pub fn pa_stream_connect_record(s: *mut pa_stream, &gt;- dev: *const c_char, &gt;- attr: *const pa_buffer_attr, &gt;- flags: pa_stream_flags_t) &gt;- -&gt; c_int; &gt;- pub fn pa_stream_cork(s: *mut pa_stream, &gt;- b: c_int, &gt;- cb: pa_stream_success_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation; &gt;+ pub fn pa_stream_connect_playback( &gt;+ s: *mut pa_stream, &gt;+ dev: *const c_char, &gt;+ attr: *const pa_buffer_attr, &gt;+ flags: pa_stream_flags_t, &gt;+ volume: *const pa_cvolume, &gt;+ sync_stream: *const pa_stream, &gt;+ ) -&gt; c_int; &gt;+ pub fn pa_stream_connect_record( &gt;+ s: *mut pa_stream, &gt;+ dev: *const c_char, &gt;+ attr: *const pa_buffer_attr, &gt;+ flags: pa_stream_flags_t, &gt;+ ) -&gt; c_int; &gt;+ pub fn pa_stream_cork( &gt;+ s: *mut pa_stream, &gt;+ b: c_int, &gt;+ cb: pa_stream_success_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation; &gt; pub fn pa_stream_disconnect(s: *mut pa_stream) -&gt; c_int; &gt; pub fn pa_stream_drop(p: *mut pa_stream) -&gt; c_int; &gt; pub fn pa_stream_get_buffer_attr(s: *const pa_stream) -&gt; *const pa_buffer_attr; &gt; pub fn pa_stream_get_channel_map(s: *const pa_stream) -&gt; *const pa_channel_map; &gt; pub fn pa_stream_get_device_name(s: *const pa_stream) -&gt; *const c_char; &gt; pub fn pa_stream_get_index(s: *const pa_stream) -&gt; u32; &gt;- pub fn pa_stream_get_latency(s: *const pa_stream, r_usec: *mut pa_usec_t, negative: *mut c_int) -&gt; c_int; &gt;+ pub fn pa_stream_get_latency( &gt;+ s: *const pa_stream, &gt;+ r_usec: *mut pa_usec_t, &gt;+ negative: *mut c_int, &gt;+ ) -&gt; c_int; &gt; pub fn pa_stream_get_sample_spec(s: *const pa_stream) -&gt; *const pa_sample_spec; &gt; pub fn pa_stream_get_state(p: *const pa_stream) -&gt; pa_stream_state_t; &gt; pub fn pa_stream_get_context(s: *const pa_stream) -&gt; *mut pa_context; &gt; pub fn pa_stream_get_time(s: *const pa_stream, r_usec: *mut pa_usec_t) -&gt; c_int; &gt;- pub fn pa_stream_new(c: *mut pa_context, &gt;- name: *const c_char, &gt;- ss: *const pa_sample_spec, &gt;- map: *const pa_channel_map) &gt;- -&gt; *mut pa_stream; &gt;- pub fn pa_stream_peek(p: *mut pa_stream, data: *mut *const c_void, nbytes: *mut usize) -&gt; c_int; &gt;+ pub fn pa_stream_new( &gt;+ c: *mut pa_context, &gt;+ name: *const c_char, &gt;+ ss: *const pa_sample_spec, &gt;+ map: *const pa_channel_map, &gt;+ ) -&gt; *mut pa_stream; &gt;+ pub fn pa_stream_peek( &gt;+ p: *mut pa_stream, &gt;+ data: *mut *const c_void, &gt;+ nbytes: *mut usize, &gt;+ ) -&gt; c_int; &gt; pub fn pa_stream_readable_size(p: *const pa_stream) -&gt; usize; &gt;- pub fn pa_stream_set_state_callback(s: *mut pa_stream, cb: pa_stream_notify_cb_t, userdata: *mut c_void); &gt;- pub fn pa_stream_set_write_callback(p: *mut pa_stream, cb: pa_stream_request_cb_t, userdata: *mut c_void); &gt;- pub fn pa_stream_set_read_callback(p: *mut pa_stream, cb: pa_stream_request_cb_t, userdata: *mut c_void); &gt;+ pub fn pa_stream_set_state_callback( &gt;+ s: *mut pa_stream, &gt;+ cb: pa_stream_notify_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ); &gt;+ pub fn pa_stream_set_write_callback( &gt;+ p: *mut pa_stream, &gt;+ cb: pa_stream_request_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ); &gt;+ pub fn pa_stream_set_read_callback( &gt;+ p: *mut pa_stream, &gt;+ cb: pa_stream_request_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ); &gt; pub fn pa_stream_ref(s: *mut pa_stream) -&gt; *mut pa_stream; &gt; pub fn pa_stream_unref(s: *mut pa_stream); &gt;- pub fn pa_stream_update_timing_info(p: *mut pa_stream, &gt;- cb: pa_stream_success_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation; &gt;+ pub fn pa_stream_update_timing_info( &gt;+ p: *mut pa_stream, &gt;+ cb: pa_stream_success_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation; &gt; pub fn pa_stream_writable_size(p: *const pa_stream) -&gt; usize; &gt;- pub fn pa_stream_write(p: *mut pa_stream, &gt;- data: *const c_void, &gt;- nbytes: usize, &gt;- free_cb: pa_free_cb_t, &gt;- offset: i64, &gt;- seek: pa_seek_mode_t) &gt;- -&gt; c_int; &gt;+ pub fn pa_stream_write( &gt;+ p: *mut pa_stream, &gt;+ data: *const c_void, &gt;+ nbytes: usize, &gt;+ free_cb: pa_free_cb_t, &gt;+ offset: i64, &gt;+ seek: pa_seek_mode_t, &gt;+ ) -&gt; c_int; &gt; pub fn pa_sw_volume_from_linear(v: c_double) -&gt; pa_volume_t; &gt; pub fn pa_threaded_mainloop_free(m: *mut pa_threaded_mainloop); &gt; pub fn pa_threaded_mainloop_get_api(m: *mut pa_threaded_mainloop) -&gt; *mut pa_mainloop_api; &gt; pub fn pa_threaded_mainloop_in_thread(m: *mut pa_threaded_mainloop) -&gt; c_int; &gt; pub fn pa_threaded_mainloop_lock(m: *mut pa_threaded_mainloop); &gt; pub fn pa_threaded_mainloop_new() -&gt; *mut pa_threaded_mainloop; &gt; pub fn pa_threaded_mainloop_signal(m: *mut pa_threaded_mainloop, wait_for_accept: c_int); &gt; pub fn pa_threaded_mainloop_start(m: *mut pa_threaded_mainloop) -&gt; c_int; &gt;@@ -166,17 +226,17 @@ mod static_fns { &gt; } &gt; &gt; #[cfg(not(feature = "dlopen"))] &gt; pub use self::static_fns::*; &gt; &gt; #[cfg(feature = "dlopen")] &gt; mod dynamic_fns { &gt; use super::*; &gt;- use libc::{RTLD_LAZY, dlclose, dlopen, dlsym}; &gt;+ use libc::{dlclose, dlopen, dlsym, RTLD_LAZY}; &gt; use std::os::raw::{c_char, c_double, c_float, c_int, c_uint, c_void}; &gt; &gt; #[derive(Debug)] &gt; pub struct LibLoader { &gt; _lib: *mut ::libc::c_void, &gt; } &gt; &gt; impl LibLoader { &gt;@@ -707,19 +767,17 @@ mod dynamic_fns { &gt; PA_XREALLOC = { &gt; let fp = dlsym(h, cstr!("pa_xrealloc")); &gt; if fp.is_null() { &gt; return None; &gt; } &gt; fp &gt; }; &gt; &gt;- Some(LibLoader { &gt;- _lib: h, &gt;- }) &gt;+ Some(LibLoader { _lib: h }) &gt; } &gt; } &gt; &gt; impl ::std::ops::Drop for LibLoader { &gt; #[inline] &gt; fn drop(&amp;mut self) { &gt; unsafe { &gt; dlclose(self._lib); &gt;@@ -731,276 +789,315 @@ mod dynamic_fns { &gt; #[inline] &gt; pub unsafe fn pa_get_library_version() -&gt; *const c_char { &gt; (::std::mem::transmute::&lt;_, extern "C" fn() -&gt; *const c_char&gt;(PA_GET_LIBRARY_VERSION))() &gt; } &gt; &gt; static mut PA_CHANNEL_MAP_CAN_BALANCE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_channel_map_can_balance(map: *const pa_channel_map) -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_channel_map) -&gt; c_int&gt;(PA_CHANNEL_MAP_CAN_BALANCE))(map) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_channel_map) -&gt; c_int&gt;( &gt;+ PA_CHANNEL_MAP_CAN_BALANCE, &gt;+ ))(map) &gt; } &gt; &gt; static mut PA_CHANNEL_MAP_INIT: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_channel_map_init(m: *mut pa_channel_map) -&gt; *mut pa_channel_map { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_channel_map) -&gt; *mut pa_channel_map&gt;(PA_CHANNEL_MAP_INIT))(m) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_channel_map) -&gt; *mut pa_channel_map&gt;( &gt;+ PA_CHANNEL_MAP_INIT, &gt;+ ))(m) &gt; } &gt; &gt; static mut PA_CONTEXT_CONNECT: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_connect(c: *mut pa_context, &gt;- server: *const c_char, &gt;- flags: pa_context_flags_t, &gt;- api: *const pa_spawn_api) &gt;- -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_context, &gt;- *const c_char, &gt;- pa_context_flags_t, &gt;- *const pa_spawn_api) &gt;- -&gt; c_int&gt;(PA_CONTEXT_CONNECT))(c, server, flags, api) &gt;+ pub unsafe fn pa_context_connect( &gt;+ c: *mut pa_context, &gt;+ server: *const c_char, &gt;+ flags: pa_context_flags_t, &gt;+ api: *const pa_spawn_api, &gt;+ ) -&gt; c_int { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_context, *const c_char, pa_context_flags_t, *const pa_spawn_api) &gt;+ -&gt; c_int, &gt;+ &gt;(PA_CONTEXT_CONNECT))(c, server, flags, api) &gt; } &gt; &gt; static mut PA_CONTEXT_DISCONNECT: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_context_disconnect(c: *mut pa_context) { &gt; (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_context)&gt;(PA_CONTEXT_DISCONNECT))(c) &gt; } &gt; &gt; static mut PA_CONTEXT_DRAIN: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_drain(c: *mut pa_context, &gt;- cb: pa_context_notify_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_context, pa_context_notify_cb_t, *mut c_void) &gt;- -&gt; *mut pa_operation&gt;(PA_CONTEXT_DRAIN))(c, cb, userdata) &gt;+ pub unsafe fn pa_context_drain( &gt;+ c: *mut pa_context, &gt;+ cb: pa_context_notify_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_context, pa_context_notify_cb_t, *mut c_void) &gt;+ -&gt; *mut pa_operation, &gt;+ &gt;(PA_CONTEXT_DRAIN))(c, cb, userdata) &gt; } &gt; &gt; static mut PA_CONTEXT_GET_SERVER_INFO: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_get_server_info(c: *const pa_context, &gt;- cb: pa_server_info_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_context, pa_server_info_cb_t, *mut c_void) &gt;- -&gt; *mut pa_operation&gt;(PA_CONTEXT_GET_SERVER_INFO))(c, cb, userdata) &gt;+ pub unsafe fn pa_context_get_server_info( &gt;+ c: *const pa_context, &gt;+ cb: pa_server_info_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*const pa_context, pa_server_info_cb_t, *mut c_void) -&gt; *mut pa_operation, &gt;+ &gt;(PA_CONTEXT_GET_SERVER_INFO))(c, cb, userdata) &gt; } &gt; &gt; static mut PA_CONTEXT_GET_SINK_INFO_BY_NAME: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_get_sink_info_by_name(c: *const pa_context, &gt;- name: *const c_char, &gt;- cb: pa_sink_info_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_context, &gt;- *const c_char, &gt;- pa_sink_info_cb_t, &gt;- *mut c_void) &gt;- -&gt; *mut pa_operation&gt;(PA_CONTEXT_GET_SINK_INFO_BY_NAME))(c, &gt;- name, &gt;- cb, &gt;- userdata) &gt;+ pub unsafe fn pa_context_get_sink_info_by_name( &gt;+ c: *const pa_context, &gt;+ name: *const c_char, &gt;+ cb: pa_sink_info_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*const pa_context, *const c_char, pa_sink_info_cb_t, *mut c_void) &gt;+ -&gt; *mut pa_operation, &gt;+ &gt;(PA_CONTEXT_GET_SINK_INFO_BY_NAME))(c, name, cb, userdata) &gt; } &gt; &gt; static mut PA_CONTEXT_GET_SINK_INFO_LIST: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_get_sink_info_list(c: *const pa_context, &gt;- cb: pa_sink_info_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_context, pa_sink_info_cb_t, *mut c_void) &gt;- -&gt; *mut pa_operation&gt;(PA_CONTEXT_GET_SINK_INFO_LIST))(c, cb, userdata) &gt;+ pub unsafe fn pa_context_get_sink_info_list( &gt;+ c: *const pa_context, &gt;+ cb: pa_sink_info_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*const pa_context, pa_sink_info_cb_t, *mut c_void) -&gt; *mut pa_operation, &gt;+ &gt;(PA_CONTEXT_GET_SINK_INFO_LIST))(c, cb, userdata) &gt; } &gt; &gt; static mut PA_CONTEXT_GET_SINK_INPUT_INFO: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_get_sink_input_info(c: *const pa_context, &gt;- idx: u32, &gt;- cb: pa_sink_input_info_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_context, u32, pa_sink_input_info_cb_t, *mut c_void) &gt;- -&gt; *mut pa_operation&gt;(PA_CONTEXT_GET_SINK_INPUT_INFO))(c, &gt;- idx, &gt;- cb, &gt;- userdata) &gt;+ pub unsafe fn pa_context_get_sink_input_info( &gt;+ c: *const pa_context, &gt;+ idx: u32, &gt;+ cb: pa_sink_input_info_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*const pa_context, u32, pa_sink_input_info_cb_t, *mut c_void) &gt;+ -&gt; *mut pa_operation, &gt;+ &gt;(PA_CONTEXT_GET_SINK_INPUT_INFO))(c, idx, cb, userdata) &gt; } &gt; &gt; static mut PA_CONTEXT_GET_SOURCE_INFO_LIST: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_get_source_info_list(c: *const pa_context, &gt;- cb: pa_source_info_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_context, pa_source_info_cb_t, *mut c_void) &gt;- -&gt; *mut pa_operation&gt;(PA_CONTEXT_GET_SOURCE_INFO_LIST))(c, cb, userdata) &gt;+ pub unsafe fn pa_context_get_source_info_list( &gt;+ c: *const pa_context, &gt;+ cb: pa_source_info_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*const pa_context, pa_source_info_cb_t, *mut c_void) -&gt; *mut pa_operation, &gt;+ &gt;(PA_CONTEXT_GET_SOURCE_INFO_LIST))(c, cb, userdata) &gt; } &gt; &gt; static mut PA_CONTEXT_GET_STATE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_context_get_state(c: *const pa_context) -&gt; pa_context_state_t { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_context) -&gt; pa_context_state_t&gt;(PA_CONTEXT_GET_STATE))(c) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_context) -&gt; pa_context_state_t&gt;( &gt;+ PA_CONTEXT_GET_STATE, &gt;+ ))(c) &gt; } &gt; &gt; static mut PA_CONTEXT_NEW: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_new(mainloop: *mut pa_mainloop_api, name: *const c_char) -&gt; *mut pa_context { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_mainloop_api, *const c_char) &gt;- -&gt; *mut pa_context&gt;(PA_CONTEXT_NEW))(mainloop, name) &gt;+ pub unsafe fn pa_context_new( &gt;+ mainloop: *mut pa_mainloop_api, &gt;+ name: *const c_char, &gt;+ ) -&gt; *mut pa_context { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_mainloop_api, *const c_char) -&gt; *mut pa_context, &gt;+ &gt;(PA_CONTEXT_NEW))(mainloop, name) &gt; } &gt; &gt; static mut PA_CONTEXT_RTTIME_NEW: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_rttime_new(c: *const pa_context, &gt;- usec: pa_usec_t, &gt;- cb: pa_time_event_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_time_event { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_context, &gt;- pa_usec_t, &gt;- pa_time_event_cb_t, &gt;- *mut c_void) &gt;- -&gt; *mut pa_time_event&gt;(PA_CONTEXT_RTTIME_NEW))(c, usec, cb, userdata) &gt;+ pub unsafe fn pa_context_rttime_new( &gt;+ c: *const pa_context, &gt;+ usec: pa_usec_t, &gt;+ cb: pa_time_event_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_time_event { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*const pa_context, pa_usec_t, pa_time_event_cb_t, *mut c_void) &gt;+ -&gt; *mut pa_time_event, &gt;+ &gt;(PA_CONTEXT_RTTIME_NEW))(c, usec, cb, userdata) &gt; } &gt; &gt; static mut PA_CONTEXT_SET_SINK_INPUT_VOLUME: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_set_sink_input_volume(c: *mut pa_context, &gt;- idx: u32, &gt;- volume: *const pa_cvolume, &gt;- cb: pa_context_success_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_context, &gt;- u32, &gt;- *const pa_cvolume, &gt;- pa_context_success_cb_t, &gt;- *mut c_void) &gt;- -&gt; *mut pa_operation&gt;(PA_CONTEXT_SET_SINK_INPUT_VOLUME))(c, &gt;- idx, &gt;- volume, &gt;- cb, &gt;- userdata) &gt;+ pub unsafe fn pa_context_set_sink_input_volume( &gt;+ c: *mut pa_context, &gt;+ idx: u32, &gt;+ volume: *const pa_cvolume, &gt;+ cb: pa_context_success_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn( &gt;+ *mut pa_context, &gt;+ u32, &gt;+ *const pa_cvolume, &gt;+ pa_context_success_cb_t, &gt;+ *mut c_void, &gt;+ ) -&gt; *mut pa_operation, &gt;+ &gt;(PA_CONTEXT_SET_SINK_INPUT_VOLUME))(c, idx, volume, cb, userdata) &gt; } &gt; &gt; static mut PA_CONTEXT_SET_STATE_CALLBACK: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_set_state_callback(c: *mut pa_context, &gt;- cb: pa_context_notify_cb_t, &gt;- userdata: *mut c_void) { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_context, &gt;- pa_context_notify_cb_t, &gt;- *mut c_void)&gt;(PA_CONTEXT_SET_STATE_CALLBACK))(c, cb, userdata) &gt;+ pub unsafe fn pa_context_set_state_callback( &gt;+ c: *mut pa_context, &gt;+ cb: pa_context_notify_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_context, pa_context_notify_cb_t, *mut c_void), &gt;+ &gt;(PA_CONTEXT_SET_STATE_CALLBACK))(c, cb, userdata) &gt; } &gt; &gt; static mut PA_CONTEXT_ERRNO: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_context_errno(c: *mut pa_context) -&gt; c_int { &gt; (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_context) -&gt; c_int&gt;(PA_CONTEXT_ERRNO))(c) &gt; } &gt; &gt; static mut PA_CONTEXT_SET_SUBSCRIBE_CALLBACK: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_set_subscribe_callback(c: *mut pa_context, &gt;- cb: pa_context_subscribe_cb_t, &gt;- userdata: *mut c_void) { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_context, &gt;- pa_context_subscribe_cb_t, &gt;- *mut c_void)&gt;(PA_CONTEXT_SET_SUBSCRIBE_CALLBACK))(c, cb, userdata) &gt;+ pub unsafe fn pa_context_set_subscribe_callback( &gt;+ c: *mut pa_context, &gt;+ cb: pa_context_subscribe_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_context, pa_context_subscribe_cb_t, *mut c_void), &gt;+ &gt;(PA_CONTEXT_SET_SUBSCRIBE_CALLBACK))(c, cb, userdata) &gt; } &gt; &gt; static mut PA_CONTEXT_SUBSCRIBE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_context_subscribe(c: *mut pa_context, &gt;- m: pa_subscription_mask_t, &gt;- cb: pa_context_success_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_context, &gt;- pa_subscription_mask_t, &gt;- pa_context_success_cb_t, &gt;- *mut c_void) &gt;- -&gt; *mut pa_operation&gt;(PA_CONTEXT_SUBSCRIBE))(c, m, cb, userdata) &gt;+ pub unsafe fn pa_context_subscribe( &gt;+ c: *mut pa_context, &gt;+ m: pa_subscription_mask_t, &gt;+ cb: pa_context_success_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn( &gt;+ *mut pa_context, &gt;+ pa_subscription_mask_t, &gt;+ pa_context_success_cb_t, &gt;+ *mut c_void, &gt;+ ) -&gt; *mut pa_operation, &gt;+ &gt;(PA_CONTEXT_SUBSCRIBE))(c, m, cb, userdata) &gt; } &gt; &gt; static mut PA_CONTEXT_REF: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_context_ref(c: *mut pa_context) -&gt; *mut pa_context { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_context) -&gt; *mut pa_context&gt;(PA_CONTEXT_REF))(c) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_context) -&gt; *mut pa_context&gt;( &gt;+ PA_CONTEXT_REF, &gt;+ ))(c) &gt; } &gt; &gt; static mut PA_CONTEXT_UNREF: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_context_unref(c: *mut pa_context) { &gt; (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_context)&gt;(PA_CONTEXT_UNREF))(c) &gt; } &gt; &gt; static mut PA_CVOLUME_SET: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_cvolume_set(a: *mut pa_cvolume, channels: c_uint, v: pa_volume_t) -&gt; *mut pa_cvolume { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_cvolume, c_uint, pa_volume_t) &gt;- -&gt; *mut pa_cvolume&gt;(PA_CVOLUME_SET))(a, channels, v) &gt;+ pub unsafe fn pa_cvolume_set( &gt;+ a: *mut pa_cvolume, &gt;+ channels: c_uint, &gt;+ v: pa_volume_t, &gt;+ ) -&gt; *mut pa_cvolume { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_cvolume, c_uint, pa_volume_t) -&gt; *mut pa_cvolume, &gt;+ &gt;(PA_CVOLUME_SET))(a, channels, v) &gt; } &gt; &gt; static mut PA_CVOLUME_SET_BALANCE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_cvolume_set_balance(v: *mut pa_cvolume, &gt;- map: *const pa_channel_map, &gt;- new_balance: c_float) &gt;- -&gt; *mut pa_cvolume { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_cvolume, &gt;- *const pa_channel_map, &gt;- c_float) &gt;- -&gt; *mut pa_cvolume&gt;(PA_CVOLUME_SET_BALANCE))(v, map, new_balance) &gt;+ pub unsafe fn pa_cvolume_set_balance( &gt;+ v: *mut pa_cvolume, &gt;+ map: *const pa_channel_map, &gt;+ new_balance: c_float, &gt;+ ) -&gt; *mut pa_cvolume { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_cvolume, *const pa_channel_map, c_float) -&gt; *mut pa_cvolume, &gt;+ &gt;(PA_CVOLUME_SET_BALANCE))(v, map, new_balance) &gt; } &gt; &gt; static mut PA_FRAME_SIZE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_frame_size(spec: *const pa_sample_spec) -&gt; usize { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_sample_spec) -&gt; usize&gt;(PA_FRAME_SIZE))(spec) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_sample_spec) -&gt; usize&gt;(PA_FRAME_SIZE))( &gt;+ spec, &gt;+ ) &gt; } &gt; &gt; static mut PA_MAINLOOP_API_ONCE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_mainloop_api_once(m: *mut pa_mainloop_api, &gt;- callback: pa_mainloop_api_once_cb_t, &gt;- userdata: *mut c_void) { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_mainloop_api, &gt;- pa_mainloop_api_once_cb_t, &gt;- *mut c_void)&gt;(PA_MAINLOOP_API_ONCE))(m, callback, userdata) &gt;+ pub unsafe fn pa_mainloop_api_once( &gt;+ m: *mut pa_mainloop_api, &gt;+ callback: pa_mainloop_api_once_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_mainloop_api, pa_mainloop_api_once_cb_t, *mut c_void), &gt;+ &gt;(PA_MAINLOOP_API_ONCE))(m, callback, userdata) &gt; } &gt; &gt; static mut PA_STRERROR: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_strerror(error: pa_error_code_t) -&gt; *const c_char { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(pa_error_code_t) -&gt; *const c_char&gt;(PA_STRERROR))(error) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(pa_error_code_t) -&gt; *const c_char&gt;(PA_STRERROR))( &gt;+ error, &gt;+ ) &gt; } &gt; &gt; static mut PA_OPERATION_REF: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_operation_ref(o: *mut pa_operation) -&gt; *mut pa_operation { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_operation) -&gt; *mut pa_operation&gt;(PA_OPERATION_REF))(o) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_operation) -&gt; *mut pa_operation&gt;( &gt;+ PA_OPERATION_REF, &gt;+ ))(o) &gt; } &gt; &gt; static mut PA_OPERATION_UNREF: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_operation_unref(o: *mut pa_operation) { &gt; (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_operation)&gt;(PA_OPERATION_UNREF))(o) &gt; } &gt; &gt;@@ -1008,390 +1105,463 @@ mod dynamic_fns { &gt; #[inline] &gt; pub unsafe fn pa_operation_cancel(o: *mut pa_operation) { &gt; (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_operation)&gt;(PA_OPERATION_CANCEL))(o) &gt; } &gt; &gt; static mut PA_OPERATION_GET_STATE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_operation_get_state(o: *const pa_operation) -&gt; pa_operation_state_t { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_operation) &gt;- -&gt; pa_operation_state_t&gt;(PA_OPERATION_GET_STATE))(o) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_operation) -&gt; pa_operation_state_t&gt;( &gt;+ PA_OPERATION_GET_STATE, &gt;+ ))(o) &gt; } &gt; &gt; static mut PA_OPERATION_SET_STATE_CALLBACK: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_operation_set_state_callback(o: *mut pa_operation, &gt;- cb: pa_operation_notify_cb_t, &gt;- userdata: *mut c_void) { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_operation, &gt;- pa_operation_notify_cb_t, &gt;- *mut c_void)&gt;(PA_OPERATION_SET_STATE_CALLBACK))(o, cb, userdata) &gt;+ pub unsafe fn pa_operation_set_state_callback( &gt;+ o: *mut pa_operation, &gt;+ cb: pa_operation_notify_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_operation, pa_operation_notify_cb_t, *mut c_void), &gt;+ &gt;(PA_OPERATION_SET_STATE_CALLBACK))(o, cb, userdata) &gt; } &gt; &gt; static mut PA_PROPLIST_GETS: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_proplist_gets(p: *mut pa_proplist, key: *const c_char) -&gt; *const c_char { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_proplist, *const c_char) &gt;- -&gt; *const c_char&gt;(PA_PROPLIST_GETS))(p, key) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_proplist, *const c_char) -&gt; *const c_char&gt;( &gt;+ PA_PROPLIST_GETS, &gt;+ ))(p, key) &gt; } &gt; &gt; static mut PA_RTCLOCK_NOW: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_rtclock_now() -&gt; pa_usec_t { &gt; (::std::mem::transmute::&lt;_, extern "C" fn() -&gt; pa_usec_t&gt;(PA_RTCLOCK_NOW))() &gt; } &gt; &gt; static mut PA_STREAM_BEGIN_WRITE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_begin_write(p: *mut pa_stream, data: *mut *mut c_void, nbytes: *mut usize) -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_stream, &gt;- *mut *mut c_void, &gt;- *mut usize) &gt;- -&gt; c_int&gt;(PA_STREAM_BEGIN_WRITE))(p, data, nbytes) &gt;+ pub unsafe fn pa_stream_begin_write( &gt;+ p: *mut pa_stream, &gt;+ data: *mut *mut c_void, &gt;+ nbytes: *mut usize, &gt;+ ) -&gt; c_int { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_stream, *mut *mut c_void, *mut usize) -&gt; c_int, &gt;+ &gt;(PA_STREAM_BEGIN_WRITE))(p, data, nbytes) &gt; } &gt; &gt; static mut PA_STREAM_CANCEL_WRITE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_cancel_write(p: *mut pa_stream) -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_stream) -&gt; c_int&gt;(PA_STREAM_CANCEL_WRITE))(p) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_stream) -&gt; c_int&gt;(PA_STREAM_CANCEL_WRITE))( &gt;+ p, &gt;+ ) &gt; } &gt; &gt; static mut PA_STREAM_IS_SUSPENDED: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_is_suspended(s: *const pa_stream) -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; c_int&gt;(PA_STREAM_IS_SUSPENDED))(s) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; c_int&gt;( &gt;+ PA_STREAM_IS_SUSPENDED, &gt;+ ))(s) &gt; } &gt; &gt; static mut PA_STREAM_IS_CORKED: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_is_corked(s: *const pa_stream) -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; c_int&gt;(PA_STREAM_IS_CORKED))(s) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; c_int&gt;(PA_STREAM_IS_CORKED))( &gt;+ s, &gt;+ ) &gt; } &gt; &gt; static mut PA_STREAM_CONNECT_PLAYBACK: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_connect_playback(s: *mut pa_stream, &gt;- dev: *const c_char, &gt;- attr: *const pa_buffer_attr, &gt;- flags: pa_stream_flags_t, &gt;- volume: *const pa_cvolume, &gt;- sync_stream: *const pa_stream) &gt;- -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_stream, &gt;- *const c_char, &gt;- *const pa_buffer_attr, &gt;- pa_stream_flags_t, &gt;- *const pa_cvolume, &gt;- *const pa_stream) &gt;- -&gt; c_int&gt;(PA_STREAM_CONNECT_PLAYBACK))(s, &gt;- dev, &gt;- attr, &gt;- flags, &gt;- volume, &gt;- sync_stream) &gt;+ pub unsafe fn pa_stream_connect_playback( &gt;+ s: *mut pa_stream, &gt;+ dev: *const c_char, &gt;+ attr: *const pa_buffer_attr, &gt;+ flags: pa_stream_flags_t, &gt;+ volume: *const pa_cvolume, &gt;+ sync_stream: *const pa_stream, &gt;+ ) -&gt; c_int { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn( &gt;+ *mut pa_stream, &gt;+ *const c_char, &gt;+ *const pa_buffer_attr, &gt;+ pa_stream_flags_t, &gt;+ *const pa_cvolume, &gt;+ *const pa_stream, &gt;+ ) -&gt; c_int, &gt;+ &gt;(PA_STREAM_CONNECT_PLAYBACK))(s, dev, attr, flags, volume, sync_stream) &gt; } &gt; &gt; static mut PA_STREAM_CONNECT_RECORD: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_connect_record(s: *mut pa_stream, &gt;- dev: *const c_char, &gt;- attr: *const pa_buffer_attr, &gt;- flags: pa_stream_flags_t) &gt;- -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_stream, &gt;- *const c_char, &gt;- *const pa_buffer_attr, &gt;- pa_stream_flags_t) &gt;- -&gt; c_int&gt;(PA_STREAM_CONNECT_RECORD))(s, dev, attr, flags) &gt;+ pub unsafe fn pa_stream_connect_record( &gt;+ s: *mut pa_stream, &gt;+ dev: *const c_char, &gt;+ attr: *const pa_buffer_attr, &gt;+ flags: pa_stream_flags_t, &gt;+ ) -&gt; c_int { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_stream, *const c_char, *const pa_buffer_attr, pa_stream_flags_t) &gt;+ -&gt; c_int, &gt;+ &gt;(PA_STREAM_CONNECT_RECORD))(s, dev, attr, flags) &gt; } &gt; &gt; static mut PA_STREAM_CORK: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_cork(s: *mut pa_stream, &gt;- b: c_int, &gt;- cb: pa_stream_success_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_stream, c_int, pa_stream_success_cb_t, *mut c_void) &gt;- -&gt; *mut pa_operation&gt;(PA_STREAM_CORK))(s, b, cb, userdata) &gt;+ pub unsafe fn pa_stream_cork( &gt;+ s: *mut pa_stream, &gt;+ b: c_int, &gt;+ cb: pa_stream_success_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_stream, c_int, pa_stream_success_cb_t, *mut c_void) &gt;+ -&gt; *mut pa_operation, &gt;+ &gt;(PA_STREAM_CORK))(s, b, cb, userdata) &gt; } &gt; &gt; static mut PA_STREAM_DISCONNECT: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_disconnect(s: *mut pa_stream) -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_stream) -&gt; c_int&gt;(PA_STREAM_DISCONNECT))(s) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_stream) -&gt; c_int&gt;(PA_STREAM_DISCONNECT))( &gt;+ s, &gt;+ ) &gt; } &gt; &gt; static mut PA_STREAM_DROP: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_drop(p: *mut pa_stream) -&gt; c_int { &gt; (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_stream) -&gt; c_int&gt;(PA_STREAM_DROP))(p) &gt; } &gt; &gt; static mut PA_STREAM_GET_BUFFER_ATTR: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_get_buffer_attr(s: *const pa_stream) -&gt; *const pa_buffer_attr { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_stream) &gt;- -&gt; *const pa_buffer_attr&gt;(PA_STREAM_GET_BUFFER_ATTR))(s) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; *const pa_buffer_attr&gt;( &gt;+ PA_STREAM_GET_BUFFER_ATTR, &gt;+ ))(s) &gt; } &gt; &gt; static mut PA_STREAM_GET_CHANNEL_MAP: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_get_channel_map(s: *const pa_stream) -&gt; *const pa_channel_map { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_stream) &gt;- -&gt; *const pa_channel_map&gt;(PA_STREAM_GET_CHANNEL_MAP))(s) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; *const pa_channel_map&gt;( &gt;+ PA_STREAM_GET_CHANNEL_MAP, &gt;+ ))(s) &gt; } &gt; &gt; static mut PA_STREAM_GET_DEVICE_NAME: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_get_device_name(s: *const pa_stream) -&gt; *const c_char { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; *const c_char&gt;(PA_STREAM_GET_DEVICE_NAME))(s) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; *const c_char&gt;( &gt;+ PA_STREAM_GET_DEVICE_NAME, &gt;+ ))(s) &gt; } &gt; &gt; static mut PA_STREAM_GET_INDEX: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_get_index(s: *const pa_stream) -&gt; u32 { &gt; (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; u32&gt;(PA_STREAM_GET_INDEX))(s) &gt; } &gt; &gt; static mut PA_STREAM_GET_LATENCY: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_get_latency(s: *const pa_stream, r_usec: *mut pa_usec_t, negative: *mut c_int) -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_stream, &gt;- *mut pa_usec_t, &gt;- *mut c_int) &gt;- -&gt; c_int&gt;(PA_STREAM_GET_LATENCY))(s, r_usec, negative) &gt;+ pub unsafe fn pa_stream_get_latency( &gt;+ s: *const pa_stream, &gt;+ r_usec: *mut pa_usec_t, &gt;+ negative: *mut c_int, &gt;+ ) -&gt; c_int { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*const pa_stream, *mut pa_usec_t, *mut c_int) -&gt; c_int, &gt;+ &gt;(PA_STREAM_GET_LATENCY))(s, r_usec, negative) &gt; } &gt; &gt; static mut PA_STREAM_GET_SAMPLE_SPEC: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_get_sample_spec(s: *const pa_stream) -&gt; *const pa_sample_spec { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_stream) &gt;- -&gt; *const pa_sample_spec&gt;(PA_STREAM_GET_SAMPLE_SPEC))(s) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; *const pa_sample_spec&gt;( &gt;+ PA_STREAM_GET_SAMPLE_SPEC, &gt;+ ))(s) &gt; } &gt; &gt; static mut PA_STREAM_GET_STATE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_get_state(p: *const pa_stream) -&gt; pa_stream_state_t { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; pa_stream_state_t&gt;(PA_STREAM_GET_STATE))(p) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; pa_stream_state_t&gt;( &gt;+ PA_STREAM_GET_STATE, &gt;+ ))(p) &gt; } &gt; &gt; static mut PA_STREAM_GET_CONTEXT: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_get_context(s: *const pa_stream) -&gt; *mut pa_context { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; *mut pa_context&gt;(PA_STREAM_GET_CONTEXT))(s) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; *mut pa_context&gt;( &gt;+ PA_STREAM_GET_CONTEXT, &gt;+ ))(s) &gt; } &gt; &gt; static mut PA_STREAM_GET_TIME: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_get_time(s: *const pa_stream, r_usec: *mut pa_usec_t) -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*const pa_stream, *mut pa_usec_t) &gt;- -&gt; c_int&gt;(PA_STREAM_GET_TIME))(s, r_usec) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream, *mut pa_usec_t) -&gt; c_int&gt;( &gt;+ PA_STREAM_GET_TIME, &gt;+ ))(s, r_usec) &gt; } &gt; &gt; static mut PA_STREAM_NEW: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_new(c: *mut pa_context, &gt;- name: *const c_char, &gt;- ss: *const pa_sample_spec, &gt;- map: *const pa_channel_map) &gt;- -&gt; *mut pa_stream { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_context, &gt;- *const c_char, &gt;- *const pa_sample_spec, &gt;- *const pa_channel_map) &gt;- -&gt; *mut pa_stream&gt;(PA_STREAM_NEW))(c, name, ss, map) &gt;+ pub unsafe fn pa_stream_new( &gt;+ c: *mut pa_context, &gt;+ name: *const c_char, &gt;+ ss: *const pa_sample_spec, &gt;+ map: *const pa_channel_map, &gt;+ ) -&gt; *mut pa_stream { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn( &gt;+ *mut pa_context, &gt;+ *const c_char, &gt;+ *const pa_sample_spec, &gt;+ *const pa_channel_map, &gt;+ ) -&gt; *mut pa_stream, &gt;+ &gt;(PA_STREAM_NEW))(c, name, ss, map) &gt; } &gt; &gt; static mut PA_STREAM_PEEK: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_peek(p: *mut pa_stream, data: *mut *const c_void, nbytes: *mut usize) -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_stream, &gt;- *mut *const c_void, &gt;- *mut usize) &gt;- -&gt; c_int&gt;(PA_STREAM_PEEK))(p, data, nbytes) &gt;+ pub unsafe fn pa_stream_peek( &gt;+ p: *mut pa_stream, &gt;+ data: *mut *const c_void, &gt;+ nbytes: *mut usize, &gt;+ ) -&gt; c_int { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_stream, *mut *const c_void, *mut usize) -&gt; c_int, &gt;+ &gt;(PA_STREAM_PEEK))(p, data, nbytes) &gt; } &gt; &gt; static mut PA_STREAM_READABLE_SIZE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_readable_size(p: *const pa_stream) -&gt; usize { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; usize&gt;(PA_STREAM_READABLE_SIZE))(p) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; usize&gt;( &gt;+ PA_STREAM_READABLE_SIZE, &gt;+ ))(p) &gt; } &gt; &gt; static mut PA_STREAM_SET_STATE_CALLBACK: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_set_state_callback(s: *mut pa_stream, cb: pa_stream_notify_cb_t, userdata: *mut c_void) { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_stream, &gt;- pa_stream_notify_cb_t, &gt;- *mut c_void)&gt;(PA_STREAM_SET_STATE_CALLBACK))(s, cb, userdata) &gt;+ pub unsafe fn pa_stream_set_state_callback( &gt;+ s: *mut pa_stream, &gt;+ cb: pa_stream_notify_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_stream, pa_stream_notify_cb_t, *mut c_void), &gt;+ &gt;(PA_STREAM_SET_STATE_CALLBACK))(s, cb, userdata) &gt; } &gt; &gt; static mut PA_STREAM_SET_WRITE_CALLBACK: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_set_write_callback(p: *mut pa_stream, cb: pa_stream_request_cb_t, userdata: *mut c_void) { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_stream, &gt;- pa_stream_request_cb_t, &gt;- *mut c_void)&gt;(PA_STREAM_SET_WRITE_CALLBACK))(p, cb, userdata) &gt;+ pub unsafe fn pa_stream_set_write_callback( &gt;+ p: *mut pa_stream, &gt;+ cb: pa_stream_request_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_stream, pa_stream_request_cb_t, *mut c_void), &gt;+ &gt;(PA_STREAM_SET_WRITE_CALLBACK))(p, cb, userdata) &gt; } &gt; &gt; static mut PA_STREAM_SET_READ_CALLBACK: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_set_read_callback(p: *mut pa_stream, cb: pa_stream_request_cb_t, userdata: *mut c_void) { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_stream, &gt;- pa_stream_request_cb_t, &gt;- *mut c_void)&gt;(PA_STREAM_SET_READ_CALLBACK))(p, cb, userdata) &gt;+ pub unsafe fn pa_stream_set_read_callback( &gt;+ p: *mut pa_stream, &gt;+ cb: pa_stream_request_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_stream, pa_stream_request_cb_t, *mut c_void), &gt;+ &gt;(PA_STREAM_SET_READ_CALLBACK))(p, cb, userdata) &gt; } &gt; &gt; static mut PA_STREAM_REF: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_ref(s: *mut pa_stream) -&gt; *mut pa_stream { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_stream) -&gt; *mut pa_stream&gt;(PA_STREAM_REF))(s) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_stream) -&gt; *mut pa_stream&gt;(PA_STREAM_REF))( &gt;+ s, &gt;+ ) &gt; } &gt; &gt; static mut PA_STREAM_UNREF: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_unref(s: *mut pa_stream) { &gt; (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_stream)&gt;(PA_STREAM_UNREF))(s) &gt; } &gt; &gt; static mut PA_STREAM_UPDATE_TIMING_INFO: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_update_timing_info(p: *mut pa_stream, &gt;- cb: pa_stream_success_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_operation { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_stream, pa_stream_success_cb_t, *mut c_void) &gt;- -&gt; *mut pa_operation&gt;(PA_STREAM_UPDATE_TIMING_INFO))(p, cb, userdata) &gt;+ pub unsafe fn pa_stream_update_timing_info( &gt;+ p: *mut pa_stream, &gt;+ cb: pa_stream_success_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_operation { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_stream, pa_stream_success_cb_t, *mut c_void) -&gt; *mut pa_operation, &gt;+ &gt;(PA_STREAM_UPDATE_TIMING_INFO))(p, cb, userdata) &gt; } &gt; &gt; static mut PA_STREAM_WRITABLE_SIZE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_stream_writable_size(p: *const pa_stream) -&gt; usize { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; usize&gt;(PA_STREAM_WRITABLE_SIZE))(p) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*const pa_stream) -&gt; usize&gt;( &gt;+ PA_STREAM_WRITABLE_SIZE, &gt;+ ))(p) &gt; } &gt; &gt; static mut PA_STREAM_WRITE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_stream_write(p: *mut pa_stream, &gt;- data: *const c_void, &gt;- nbytes: usize, &gt;- free_cb: pa_free_cb_t, &gt;- offset: i64, &gt;- seek: pa_seek_mode_t) &gt;- -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_stream, &gt;- *const c_void, &gt;- usize, &gt;- pa_free_cb_t, &gt;- i64, &gt;- pa_seek_mode_t) &gt;- -&gt; c_int&gt;(PA_STREAM_WRITE))(p, data, nbytes, free_cb, offset, seek) &gt;+ pub unsafe fn pa_stream_write( &gt;+ p: *mut pa_stream, &gt;+ data: *const c_void, &gt;+ nbytes: usize, &gt;+ free_cb: pa_free_cb_t, &gt;+ offset: i64, &gt;+ seek: pa_seek_mode_t, &gt;+ ) -&gt; c_int { &gt;+ (::std::mem::transmute::&lt; &gt;+ _, &gt;+ extern "C" fn(*mut pa_stream, *const c_void, usize, pa_free_cb_t, i64, pa_seek_mode_t) &gt;+ -&gt; c_int, &gt;+ &gt;(PA_STREAM_WRITE))(p, data, nbytes, free_cb, offset, seek) &gt; } &gt; &gt; static mut PA_SW_VOLUME_FROM_LINEAR: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_sw_volume_from_linear(v: c_double) -&gt; pa_volume_t { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(c_double) -&gt; pa_volume_t&gt;(PA_SW_VOLUME_FROM_LINEAR))(v) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(c_double) -&gt; pa_volume_t&gt;( &gt;+ PA_SW_VOLUME_FROM_LINEAR, &gt;+ ))(v) &gt; } &gt; &gt; static mut PA_THREADED_MAINLOOP_FREE: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_threaded_mainloop_free(m: *mut pa_threaded_mainloop) { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop)&gt;(PA_THREADED_MAINLOOP_FREE))(m) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop)&gt;( &gt;+ PA_THREADED_MAINLOOP_FREE, &gt;+ ))(m) &gt; } &gt; &gt; static mut PA_THREADED_MAINLOOP_GET_API: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_threaded_mainloop_get_api(m: *mut pa_threaded_mainloop) -&gt; *mut pa_mainloop_api { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_threaded_mainloop) &gt;- -&gt; *mut pa_mainloop_api&gt;(PA_THREADED_MAINLOOP_GET_API))(m) &gt;+ pub unsafe fn pa_threaded_mainloop_get_api( &gt;+ m: *mut pa_threaded_mainloop, &gt;+ ) -&gt; *mut pa_mainloop_api { &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop) -&gt; *mut pa_mainloop_api&gt;( &gt;+ PA_THREADED_MAINLOOP_GET_API, &gt;+ ))(m) &gt; } &gt; &gt; static mut PA_THREADED_MAINLOOP_IN_THREAD: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_threaded_mainloop_in_thread(m: *mut pa_threaded_mainloop) -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_threaded_mainloop) &gt;- -&gt; c_int&gt;(PA_THREADED_MAINLOOP_IN_THREAD))(m) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop) -&gt; c_int&gt;( &gt;+ PA_THREADED_MAINLOOP_IN_THREAD, &gt;+ ))(m) &gt; } &gt; &gt; static mut PA_THREADED_MAINLOOP_LOCK: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_threaded_mainloop_lock(m: *mut pa_threaded_mainloop) { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop)&gt;(PA_THREADED_MAINLOOP_LOCK))(m) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop)&gt;( &gt;+ PA_THREADED_MAINLOOP_LOCK, &gt;+ ))(m) &gt; } &gt; &gt; static mut PA_THREADED_MAINLOOP_NEW: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_threaded_mainloop_new() -&gt; *mut pa_threaded_mainloop { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn() -&gt; *mut pa_threaded_mainloop&gt;(PA_THREADED_MAINLOOP_NEW))() &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn() -&gt; *mut pa_threaded_mainloop&gt;( &gt;+ PA_THREADED_MAINLOOP_NEW, &gt;+ ))() &gt; } &gt; &gt; static mut PA_THREADED_MAINLOOP_SIGNAL: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt;- pub unsafe fn pa_threaded_mainloop_signal(m: *mut pa_threaded_mainloop, wait_for_accept: c_int) { &gt;- (::std::mem::transmute::&lt;_, &gt;- extern "C" fn(*mut pa_threaded_mainloop, &gt;- c_int)&gt;(PA_THREADED_MAINLOOP_SIGNAL))(m, wait_for_accept) &gt;+ pub unsafe fn pa_threaded_mainloop_signal( &gt;+ m: *mut pa_threaded_mainloop, &gt;+ wait_for_accept: c_int, &gt;+ ) { &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop, c_int)&gt;( &gt;+ PA_THREADED_MAINLOOP_SIGNAL, &gt;+ ))(m, wait_for_accept) &gt; } &gt; &gt; static mut PA_THREADED_MAINLOOP_START: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_threaded_mainloop_start(m: *mut pa_threaded_mainloop) -&gt; c_int { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop) -&gt; c_int&gt;(PA_THREADED_MAINLOOP_START))(m) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop) -&gt; c_int&gt;( &gt;+ PA_THREADED_MAINLOOP_START, &gt;+ ))(m) &gt; } &gt; &gt; static mut PA_THREADED_MAINLOOP_STOP: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_threaded_mainloop_stop(m: *mut pa_threaded_mainloop) { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop)&gt;(PA_THREADED_MAINLOOP_STOP))(m) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop)&gt;( &gt;+ PA_THREADED_MAINLOOP_STOP, &gt;+ ))(m) &gt; } &gt; &gt; static mut PA_THREADED_MAINLOOP_UNLOCK: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_threaded_mainloop_unlock(m: *mut pa_threaded_mainloop) { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop)&gt;(PA_THREADED_MAINLOOP_UNLOCK))(m) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop)&gt;( &gt;+ PA_THREADED_MAINLOOP_UNLOCK, &gt;+ ))(m) &gt; } &gt; &gt; static mut PA_THREADED_MAINLOOP_WAIT: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_threaded_mainloop_wait(m: *mut pa_threaded_mainloop) { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop)&gt;(PA_THREADED_MAINLOOP_WAIT))(m) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut pa_threaded_mainloop)&gt;( &gt;+ PA_THREADED_MAINLOOP_WAIT, &gt;+ ))(m) &gt; } &gt; &gt; static mut PA_USEC_TO_BYTES: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_usec_to_bytes(t: pa_usec_t, spec: *const pa_sample_spec) -&gt; usize { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(pa_usec_t, *const pa_sample_spec) -&gt; usize&gt;(PA_USEC_TO_BYTES))(t, &gt;- spec) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(pa_usec_t, *const pa_sample_spec) -&gt; usize&gt;( &gt;+ PA_USEC_TO_BYTES, &gt;+ ))(t, spec) &gt; } &gt; &gt; static mut PA_XREALLOC: *mut ::libc::c_void = 0 as *mut _; &gt; #[inline] &gt; pub unsafe fn pa_xrealloc(ptr: *mut c_void, size: usize) -&gt; *mut c_void { &gt;- (::std::mem::transmute::&lt;_, extern "C" fn(*mut c_void, usize) -&gt; *mut c_void&gt;(PA_XREALLOC))(ptr, size) &gt;+ (::std::mem::transmute::&lt;_, extern "C" fn(*mut c_void, usize) -&gt; *mut c_void&gt;(PA_XREALLOC))( &gt;+ ptr, size, &gt;+ ) &gt; } &gt; &gt; } &gt; &gt; #[cfg(feature = "dlopen")] &gt; pub use self::dynamic_fns::*; &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs b/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs &gt;index 0bfad62bca7e..baf6920e467c 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/ffi_types.rs &gt;@@ -49,17 +49,20 @@ pub const PA_CONTEXT_AUTHORIZING: c_int = 2; &gt; pub const PA_CONTEXT_SETTING_NAME: c_int = 3; &gt; pub const PA_CONTEXT_READY: c_int = 4; &gt; pub const PA_CONTEXT_FAILED: c_int = 5; &gt; pub const PA_CONTEXT_TERMINATED: c_int = 6; &gt; pub type pa_context_state_t = c_int; &gt; &gt; #[allow(non_snake_case)] &gt; pub fn PA_CONTEXT_IS_GOOD(x: pa_context_state_t) -&gt; bool { &gt;- x == PA_CONTEXT_CONNECTING || x == PA_CONTEXT_AUTHORIZING || x == PA_CONTEXT_SETTING_NAME || x == PA_CONTEXT_READY &gt;+ x == PA_CONTEXT_CONNECTING &gt;+ || x == PA_CONTEXT_AUTHORIZING &gt;+ || x == PA_CONTEXT_SETTING_NAME &gt;+ || x == PA_CONTEXT_READY &gt; } &gt; &gt; pub const PA_STREAM_UNCONNECTED: c_int = 0; &gt; pub const PA_STREAM_CREATING: c_int = 1; &gt; pub const PA_STREAM_READY: c_int = 2; &gt; pub const PA_STREAM_FAILED: c_int = 3; &gt; pub const PA_STREAM_TERMINATED: c_int = 4; &gt; pub type pa_stream_state_t = c_int; &gt;@@ -292,85 +295,103 @@ pub type pa_port_available_t = c_int; &gt; &gt; pub const PA_IO_EVENT_NULL: c_int = 0; &gt; pub const PA_IO_EVENT_INPUT: c_int = 1; &gt; pub const PA_IO_EVENT_OUTPUT: c_int = 2; &gt; pub const PA_IO_EVENT_HANGUP: c_int = 4; &gt; pub const PA_IO_EVENT_ERROR: c_int = 8; &gt; pub type pa_io_event_flags_t = c_int; &gt; &gt;-pub enum pa_io_event { } &gt;-pub type pa_io_event_cb_t = Option&lt;unsafe extern "C" fn(ea: *mut pa_mainloop_api, &gt;- e: *mut pa_io_event, &gt;- fd: c_int, &gt;- events: pa_io_event_flags_t, &gt;- userdata: *mut c_void)&gt;; &gt;-pub type pa_io_event_destroy_cb_t = Option&lt;unsafe extern "C" fn(a: *mut pa_mainloop_api, &gt;- e: *mut pa_io_event, &gt;- userdata: *mut c_void)&gt;; &gt;-pub enum pa_time_event { } &gt;-pub type pa_time_event_cb_t = Option&lt;unsafe extern "C" fn(a: *mut pa_mainloop_api, &gt;- e: *mut pa_time_event, &gt;- tv: *const timeval, &gt;- userdata: *mut c_void)&gt;; &gt;-pub type pa_time_event_destroy_cb_t = Option&lt;unsafe extern "C" fn(a: *mut pa_mainloop_api, &gt;- e: *mut pa_time_event, &gt;- userdata: *mut c_void)&gt;; &gt;+pub enum pa_io_event {} &gt;+pub type pa_io_event_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ ea: *mut pa_mainloop_api, &gt;+ e: *mut pa_io_event, &gt;+ fd: c_int, &gt;+ events: pa_io_event_flags_t, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt;+pub type pa_io_event_destroy_cb_t = Option&lt; &gt;+ unsafe extern "C" fn(a: *mut pa_mainloop_api, e: *mut pa_io_event, userdata: *mut c_void), &gt;+&gt;; &gt;+pub enum pa_time_event {} &gt;+pub type pa_time_event_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ a: *mut pa_mainloop_api, &gt;+ e: *mut pa_time_event, &gt;+ tv: *const timeval, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt;+pub type pa_time_event_destroy_cb_t = Option&lt; &gt;+ unsafe extern "C" fn(a: *mut pa_mainloop_api, e: *mut pa_time_event, userdata: *mut c_void), &gt;+&gt;; &gt; &gt;-pub enum pa_defer_event { } &gt;-pub type pa_defer_event_cb_t = Option&lt;unsafe extern "C" fn(a: *mut pa_mainloop_api, &gt;- e: *mut pa_defer_event, &gt;- userdata: *mut c_void)&gt;; &gt;-pub type pa_defer_event_destroy_cb_t = Option&lt;unsafe extern "C" fn(a: *mut pa_mainloop_api, &gt;- e: *mut pa_defer_event, &gt;- userdata: *mut c_void)&gt;; &gt;-pub type IoNewFn = Option&lt;unsafe extern "C" fn(a: *mut pa_mainloop_api, &gt;- fd: c_int, &gt;- events: pa_io_event_flags_t, &gt;- cb: pa_io_event_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_io_event&gt;; &gt;-pub type TimeNewFn = Option&lt;unsafe extern "C" fn(a: *mut pa_mainloop_api, &gt;- tv: *const timeval, &gt;- cb: pa_time_event_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_time_event&gt;; &gt;-pub type DeferNewFn = Option&lt;unsafe extern "C" fn(a: *mut pa_mainloop_api, &gt;- cb: pa_defer_event_cb_t, &gt;- userdata: *mut c_void) &gt;- -&gt; *mut pa_defer_event&gt;; &gt;+pub enum pa_defer_event {} &gt;+pub type pa_defer_event_cb_t = Option&lt; &gt;+ unsafe extern "C" fn(a: *mut pa_mainloop_api, e: *mut pa_defer_event, userdata: *mut c_void), &gt;+&gt;; &gt;+pub type pa_defer_event_destroy_cb_t = Option&lt; &gt;+ unsafe extern "C" fn(a: *mut pa_mainloop_api, e: *mut pa_defer_event, userdata: *mut c_void), &gt;+&gt;; &gt;+pub type IoNewFn = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ a: *mut pa_mainloop_api, &gt;+ fd: c_int, &gt;+ events: pa_io_event_flags_t, &gt;+ cb: pa_io_event_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_io_event, &gt;+&gt;; &gt;+pub type TimeNewFn = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ a: *mut pa_mainloop_api, &gt;+ tv: *const timeval, &gt;+ cb: pa_time_event_cb_t, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut pa_time_event, &gt;+&gt;; &gt;+pub type DeferNewFn = Option&lt; &gt;+ unsafe extern "C" fn(a: *mut pa_mainloop_api, cb: pa_defer_event_cb_t, userdata: *mut c_void) &gt;+ -&gt; *mut pa_defer_event, &gt;+&gt;; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_mainloop_api { &gt; pub userdata: *mut c_void, &gt; pub io_new: IoNewFn, &gt; pub io_enable: Option&lt;unsafe extern "C" fn(e: *mut pa_io_event, events: pa_io_event_flags_t)&gt;, &gt; pub io_free: Option&lt;unsafe extern "C" fn(e: *mut pa_io_event)&gt;, &gt;- pub io_set_destroy: Option&lt;unsafe extern "C" fn(e: *mut pa_io_event, cb: pa_io_event_destroy_cb_t)&gt;, &gt;+ pub io_set_destroy: &gt;+ Option&lt;unsafe extern "C" fn(e: *mut pa_io_event, cb: pa_io_event_destroy_cb_t)&gt;, &gt; pub time_new: TimeNewFn, &gt; pub time_restart: Option&lt;unsafe extern "C" fn(e: *mut pa_time_event, tv: *const timeval)&gt;, &gt; pub time_free: Option&lt;unsafe extern "C" fn(e: *mut pa_time_event)&gt;, &gt;- pub time_set_destroy: Option&lt;unsafe extern "C" fn(e: *mut pa_time_event, cb: pa_time_event_destroy_cb_t)&gt;, &gt;+ pub time_set_destroy: &gt;+ Option&lt;unsafe extern "C" fn(e: *mut pa_time_event, cb: pa_time_event_destroy_cb_t)&gt;, &gt; pub defer_new: DeferNewFn, &gt; pub defer_enable: Option&lt;unsafe extern "C" fn(e: *mut pa_defer_event, b: c_int)&gt;, &gt; pub defer_free: Option&lt;unsafe extern "C" fn(e: *mut pa_defer_event)&gt;, &gt;- pub defer_set_destroy: Option&lt;unsafe extern "C" fn(e: *mut pa_defer_event, cb: pa_defer_event_destroy_cb_t)&gt;, &gt;+ pub defer_set_destroy: &gt;+ Option&lt;unsafe extern "C" fn(e: *mut pa_defer_event, cb: pa_defer_event_destroy_cb_t)&gt;, &gt; pub quit: Option&lt;unsafe extern "C" fn(a: *mut pa_mainloop_api, retval: c_int)&gt;, &gt; } &gt; &gt; impl ::std::default::Default for pa_mainloop_api { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_mainloop_api_once_cb_t = Option&lt;unsafe extern "C" fn(m: *mut pa_mainloop_api, userdata: *mut c_void)&gt;; &gt;+pub type pa_mainloop_api_once_cb_t = &gt;+ Option&lt;unsafe extern "C" fn(m: *mut pa_mainloop_api, userdata: *mut c_void)&gt;; &gt; &gt;-pub enum pa_proplist { } &gt;+pub enum pa_proplist {} &gt; &gt; pub const PA_UPDATE_SET: c_int = 0; &gt; pub const PA_UPDATE_MERGE: c_int = 1; &gt; pub const PA_UPDATE_REPLACE: c_int = 2; &gt; pub type pa_update_mode_t = c_int; &gt; &gt; pub const PA_CHANNEL_POSITION_INVALID: c_int = -1; &gt; pub const PA_CHANNEL_POSITION_MONO: c_int = 0; &gt;@@ -481,54 +502,64 @@ impl ::std::default::Default for pa_format_info { &gt; pub const PA_PROP_TYPE_INT: c_int = 0; &gt; pub const PA_PROP_TYPE_INT_RANGE: c_int = 1; &gt; pub const PA_PROP_TYPE_INT_ARRAY: c_int = 2; &gt; pub const PA_PROP_TYPE_STRING: c_int = 3; &gt; pub const PA_PROP_TYPE_STRING_ARRAY: c_int = 4; &gt; pub const PA_PROP_TYPE_INVALID: c_int = -1; &gt; pub type pa_prop_type_t = c_int; &gt; &gt;-pub enum pa_operation { } &gt;-pub type pa_operation_notify_cb_t = Option&lt;unsafe extern "C" fn(o: *mut pa_operation, userdata: *mut c_void)&gt;; &gt;+pub enum pa_operation {} &gt;+pub type pa_operation_notify_cb_t = &gt;+ Option&lt;unsafe extern "C" fn(o: *mut pa_operation, userdata: *mut c_void)&gt;; &gt; &gt;-pub enum pa_context { } &gt;-pub type pa_context_notify_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, userdata: *mut c_void)&gt;; &gt;-pub type pa_context_success_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- success: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;-pub type pa_context_event_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- name: *const c_char, &gt;- p: *mut pa_proplist, &gt;- userdata: *mut c_void)&gt;; &gt;+pub enum pa_context {} &gt;+pub type pa_context_notify_cb_t = &gt;+ Option&lt;unsafe extern "C" fn(c: *mut pa_context, userdata: *mut c_void)&gt;; &gt;+pub type pa_context_success_cb_t = &gt;+ Option&lt;unsafe extern "C" fn(c: *mut pa_context, success: c_int, userdata: *mut c_void)&gt;; &gt;+pub type pa_context_event_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ c: *mut pa_context, &gt;+ name: *const c_char, &gt;+ p: *mut pa_proplist, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt; &gt; pub type pa_volume_t = u32; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_cvolume { &gt; pub channels: u8, &gt; pub values: [pa_volume_t; 32usize], &gt; } &gt; &gt; impl ::std::default::Default for pa_cvolume { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub enum pa_stream { } &gt;-pub type pa_stream_success_cb_t = Option&lt;unsafe extern "C" fn(s: *mut pa_stream, &gt;- success: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;-pub type pa_stream_request_cb_t = Option&lt;unsafe extern "C" fn(p: *mut pa_stream, nbytes: usize, userdata: *mut c_void)&gt;; &gt;-pub type pa_stream_notify_cb_t = Option&lt;unsafe extern "C" fn(p: *mut pa_stream, userdata: *mut c_void)&gt;; &gt;-pub type pa_stream_event_cb_t = Option&lt;unsafe extern "C" fn(p: *mut pa_stream, &gt;- name: *const c_char, &gt;- pl: *mut pa_proplist, &gt;- userdata: *mut c_void)&gt;; &gt;+pub enum pa_stream {} &gt;+pub type pa_stream_success_cb_t = &gt;+ Option&lt;unsafe extern "C" fn(s: *mut pa_stream, success: c_int, userdata: *mut c_void)&gt;; &gt;+pub type pa_stream_request_cb_t = &gt;+ Option&lt;unsafe extern "C" fn(p: *mut pa_stream, nbytes: usize, userdata: *mut c_void)&gt;; &gt;+pub type pa_stream_notify_cb_t = &gt;+ Option&lt;unsafe extern "C" fn(p: *mut pa_stream, userdata: *mut c_void)&gt;; &gt;+pub type pa_stream_event_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ p: *mut pa_stream, &gt;+ name: *const c_char, &gt;+ pl: *mut pa_proplist, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_port_info { &gt; pub name: *const c_char, &gt; pub description: *const c_char, &gt; pub priority: u32, &gt; pub available: c_int, &gt;@@ -570,20 +601,24 @@ pub struct pa_sink_info { &gt; } &gt; &gt; impl ::std::default::Default for pa_sink_info { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_sink_info_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- i: *const pa_sink_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;+pub type pa_sink_info_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ c: *mut pa_context, &gt;+ i: *const pa_sink_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_source_info { &gt; pub name: *const c_char, &gt; pub index: u32, &gt; pub description: *const c_char, &gt; pub sample_spec: pa_sample_spec, &gt;@@ -610,20 +645,24 @@ pub struct pa_source_info { &gt; } &gt; &gt; impl ::std::default::Default for pa_source_info { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_source_info_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- i: *const pa_source_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;+pub type pa_source_info_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ c: *mut pa_context, &gt;+ i: *const pa_source_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_server_info { &gt; pub user_name: *const c_char, &gt; pub host_name: *const c_char, &gt; pub server_version: *const c_char, &gt; pub server_name: *const c_char, &gt;@@ -635,19 +674,19 @@ pub struct pa_server_info { &gt; } &gt; &gt; impl ::std::default::Default for pa_server_info { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_server_info_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- i: *const pa_server_info, &gt;- userdata: *mut c_void)&gt;; &gt;+pub type pa_server_info_cb_t = Option&lt; &gt;+ unsafe extern "C" fn(c: *mut pa_context, i: *const pa_server_info, userdata: *mut c_void), &gt;+&gt;; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_module_info { &gt; pub index: u32, &gt; pub name: *const c_char, &gt; pub argument: *const c_char, &gt; pub n_used: u32, &gt;@@ -656,21 +695,26 @@ pub struct pa_module_info { &gt; } &gt; &gt; impl ::std::default::Default for pa_module_info { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_module_info_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- i: *const pa_module_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;-pub type pa_context_index_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, idx: u32, userdata: *mut c_void)&gt;; &gt;+pub type pa_module_info_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ c: *mut pa_context, &gt;+ i: *const pa_module_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt;+pub type pa_context_index_cb_t = &gt;+ Option&lt;unsafe extern "C" fn(c: *mut pa_context, idx: u32, userdata: *mut c_void)&gt;; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_client_info { &gt; pub index: u32, &gt; pub name: *const c_char, &gt; pub owner_module: u32, &gt; pub driver: *const c_char, &gt;@@ -678,20 +722,24 @@ pub struct pa_client_info { &gt; } &gt; &gt; impl ::std::default::Default for pa_client_info { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_client_info_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- i: *const pa_client_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;+pub type pa_client_info_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ c: *mut pa_context, &gt;+ i: *const pa_client_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_card_profile_info { &gt; pub name: *const c_char, &gt; pub description: *const c_char, &gt; pub n_sinks: u32, &gt; pub n_sources: u32, &gt;@@ -760,20 +808,24 @@ pub struct pa_card_info { &gt; } &gt; &gt; impl ::std::default::Default for pa_card_info { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_card_info_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- i: *const pa_card_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;+pub type pa_card_info_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ c: *mut pa_context, &gt;+ i: *const pa_card_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_sink_input_info { &gt; pub index: u32, &gt; pub name: *const c_char, &gt; pub owner_module: u32, &gt; pub client: u32, &gt;@@ -794,20 +846,24 @@ pub struct pa_sink_input_info { &gt; } &gt; &gt; impl ::std::default::Default for pa_sink_input_info { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_sink_input_info_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- i: *const pa_sink_input_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;+pub type pa_sink_input_info_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ c: *mut pa_context, &gt;+ i: *const pa_sink_input_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_source_output_info { &gt; pub index: u32, &gt; pub name: *const c_char, &gt; pub owner_module: u32, &gt; pub client: u32, &gt;@@ -828,20 +884,24 @@ pub struct pa_source_output_info { &gt; } &gt; &gt; impl ::std::default::Default for pa_source_output_info { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_source_output_info_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- i: *const pa_source_output_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;+pub type pa_source_output_info_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ c: *mut pa_context, &gt;+ i: *const pa_source_output_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_stat_info { &gt; pub memblock_total: u32, &gt; pub memblock_total_size: u32, &gt; pub memblock_allocated: u32, &gt; pub memblock_allocated_size: u32, &gt;@@ -849,19 +909,18 @@ pub struct pa_stat_info { &gt; } &gt; &gt; impl ::std::default::Default for pa_stat_info { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_stat_info_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- i: *const pa_stat_info, &gt;- userdata: *mut c_void)&gt;; &gt;+pub type pa_stat_info_cb_t = &gt;+ Option&lt;unsafe extern "C" fn(c: *mut pa_context, i: *const pa_stat_info, userdata: *mut c_void)&gt;; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_sample_info { &gt; pub index: u32, &gt; pub name: *const c_char, &gt; pub volume: pa_cvolume, &gt; pub sample_spec: pa_sample_spec, &gt;@@ -874,20 +933,24 @@ pub struct pa_sample_info { &gt; } &gt; &gt; impl ::std::default::Default for pa_sample_info { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_sample_info_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- i: *const pa_sample_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;+pub type pa_sample_info_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ c: *mut pa_context, &gt;+ i: *const pa_sample_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt; &gt; pub const PA_AUTOLOAD_SINK: c_int = 0; &gt; pub const PA_AUTOLOAD_SOURCE: c_int = 1; &gt; pub type pa_autoload_type_t = c_int; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug)] &gt; pub struct pa_autoload_info { &gt;@@ -899,38 +962,48 @@ pub struct pa_autoload_info { &gt; } &gt; &gt; impl ::std::default::Default for pa_autoload_info { &gt; fn default() -&gt; Self { &gt; unsafe { ::std::mem::zeroed() } &gt; } &gt; } &gt; &gt;-pub type pa_autoload_info_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- i: *const pa_autoload_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;-pub type pa_context_subscribe_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- t: pa_subscription_event_type_t, &gt;- idx: u32, &gt;- userdata: *mut c_void)&gt;; &gt;-pub type pa_context_play_sample_cb_t = Option&lt;unsafe extern "C" fn(c: *mut pa_context, &gt;- idx: u32, &gt;- userdata: *mut c_void)&gt;; &gt;+pub type pa_autoload_info_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ c: *mut pa_context, &gt;+ i: *const pa_autoload_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt;+pub type pa_context_subscribe_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ c: *mut pa_context, &gt;+ t: pa_subscription_event_type_t, &gt;+ idx: u32, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt;+pub type pa_context_play_sample_cb_t = &gt;+ Option&lt;unsafe extern "C" fn(c: *mut pa_context, idx: u32, userdata: *mut c_void)&gt;; &gt; &gt;-pub enum pa_threaded_mainloop { } &gt;-pub enum pollfd { } &gt;-pub enum pa_mainloop { } &gt;+pub enum pa_threaded_mainloop {} &gt;+pub enum pollfd {} &gt;+pub enum pa_mainloop {} &gt; &gt;-pub type pa_poll_func = Option&lt;unsafe extern "C" fn(ufds: *mut pollfd, &gt;- nfds: c_ulong, &gt;- timeout: c_int, &gt;- userdata: *mut c_void) &gt;- -&gt; c_int&gt;; &gt;-pub enum pa_signal_event { } &gt;+pub type pa_poll_func = Option&lt; &gt;+ unsafe extern "C" fn(ufds: *mut pollfd, nfds: c_ulong, timeout: c_int, userdata: *mut c_void) &gt;+ -&gt; c_int, &gt;+&gt;; &gt;+pub enum pa_signal_event {} &gt; &gt;-pub type pa_signal_cb_t = Option&lt;unsafe extern "C" fn(api: *mut pa_mainloop_api, &gt;- e: *mut pa_signal_event, &gt;- sig: c_int, &gt;- userdata: *mut c_void)&gt;; &gt;-pub type pa_signal_destroy_cb_t = Option&lt;unsafe extern "C" fn(api: *mut pa_mainloop_api, &gt;- e: *mut pa_signal_event, &gt;- userdata: *mut c_void)&gt;; &gt;+pub type pa_signal_cb_t = Option&lt; &gt;+ unsafe extern "C" fn( &gt;+ api: *mut pa_mainloop_api, &gt;+ e: *mut pa_signal_event, &gt;+ sig: c_int, &gt;+ userdata: *mut c_void, &gt;+ ), &gt;+&gt;; &gt;+pub type pa_signal_destroy_cb_t = Option&lt; &gt;+ unsafe extern "C" fn(api: *mut pa_mainloop_api, e: *mut pa_signal_event, userdata: *mut c_void), &gt;+&gt;; &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/lib.rs b/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/lib.rs &gt;index a74152e3fc10..3264db62b7e4 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/lib.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/pulse-ffi/src/lib.rs &gt;@@ -1,14 +1,14 @@ &gt; // Required for dlopen, et al. &gt; #[cfg(feature = "dlopen")] &gt; extern crate libc; &gt; &gt;-mod ffi_types; &gt; mod ffi_funcs; &gt;+mod ffi_types; &gt; &gt;-pub use ffi_types::*; &gt; pub use ffi_funcs::*; &gt;+pub use ffi_types::*; &gt; &gt; #[cfg(feature = "dlopen")] &gt; pub unsafe fn open() -&gt; Option&lt;LibLoader&gt; { &gt; return LibLoader::open(); &gt; } &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs &gt;index c9b8a3a9609c..5b9b4a432083 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/context.rs &gt;@@ -1,19 +1,19 @@ &gt; // Copyright © 2017 Mozilla Foundation &gt; // &gt; // This program is made available under an ISC-style license. See the &gt; // accompanying file LICENSE for details. &gt; &gt;-use ::*; &gt; use ffi; &gt; use std::ffi::CStr; &gt; use std::os::raw::{c_int, c_void}; &gt; use std::ptr; &gt; use util::UnwrapCStr; &gt;+use *; &gt; &gt; // A note about `wrapped` functions &gt; // &gt; // C FFI demands `unsafe extern fn(*mut pa_context, ...) -&gt; i32`, etc, &gt; // but we want to allow such callbacks to be safe. This means no &gt; // `unsafe` or `extern`, and callbacks should be called with a safe &gt; // wrapper of `*mut pa_context`. Since the callback doesn't take &gt; // ownership, this is `&amp;Context`. `fn wrapped&lt;T&gt;(...)` defines a &gt;@@ -51,26 +51,27 @@ use util::UnwrapCStr; &gt; macro_rules! op_or_err { &gt; ($self_:ident, $e:expr) =&gt; {{ &gt; let o = unsafe { $e }; &gt; if o.is_null() { &gt; Err(ErrorCode::from_error_code($self_.errno())) &gt; } else { &gt; Ok(unsafe { operation::from_raw_ptr(o) }) &gt; } &gt;- }} &gt;+ }}; &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Debug)] &gt; pub struct Context(*mut ffi::pa_context); &gt; &gt; impl Context { &gt; pub fn new&lt;'a, OPT&gt;(api: &amp;MainloopApi, name: OPT) -&gt; Option&lt;Self&gt; &gt;- where OPT: Into&lt;Option&lt;&amp;'a CStr&gt;&gt; &gt;+ where &gt;+ OPT: Into&lt;Option&lt;&amp;'a CStr&gt;&gt;, &gt; { &gt; let ptr = unsafe { ffi::pa_context_new(api.raw_mut(), name.unwrap_cstr()) }; &gt; if ptr.is_null() { &gt; None &gt; } else { &gt; Some(Context(ptr)) &gt; } &gt; } &gt;@@ -88,23 +89,25 @@ impl Context { &gt; &gt; pub fn clear_state_callback(&amp;self) { &gt; unsafe { &gt; ffi::pa_context_set_state_callback(self.raw_mut(), None, ptr::null_mut()); &gt; } &gt; } &gt; &gt; pub fn set_state_callback&lt;CB&gt;(&amp;self, _: CB, userdata: *mut c_void) &gt;- where CB: Fn(&amp;Context, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;Context, *mut c_void), &gt; { &gt; debug_assert_eq!(::std::mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt; unsafe extern "C" fn wrapped&lt;F&gt;(c: *mut ffi::pa_context, userdata: *mut c_void) &gt;- where F: Fn(&amp;Context, *mut c_void) &gt;+ where &gt;+ F: Fn(&amp;Context, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let ctx = context::from_raw_ptr(c); &gt; let result = uninitialized::&lt;F&gt;()(&amp;ctx, userdata); &gt; forget(ctx); &gt; &gt; result &gt; } &gt;@@ -114,281 +117,362 @@ impl Context { &gt; } &gt; } &gt; &gt; pub fn errno(&amp;self) -&gt; ffi::pa_error_code_t { &gt; unsafe { ffi::pa_context_errno(self.raw_mut()) } &gt; } &gt; &gt; pub fn get_state(&amp;self) -&gt; ContextState { &gt;- ContextState::try_from(unsafe { &gt;- ffi::pa_context_get_state(self.raw_mut()) &gt;- }).expect("pa_context_get_state returned invalid ContextState") &gt;+ ContextState::try_from(unsafe { ffi::pa_context_get_state(self.raw_mut()) }) &gt;+ .expect("pa_context_get_state returned invalid ContextState") &gt; } &gt; &gt;- pub fn connect&lt;'a, OPT&gt;(&amp;self, server: OPT, flags: ContextFlags, api: *const ffi::pa_spawn_api) -&gt; Result&lt;()&gt; &gt;- where OPT: Into&lt;Option&lt;&amp;'a CStr&gt;&gt; &gt;+ pub fn connect&lt;'a, OPT&gt;( &gt;+ &amp;self, &gt;+ server: OPT, &gt;+ flags: ContextFlags, &gt;+ api: *const ffi::pa_spawn_api, &gt;+ ) -&gt; Result&lt;()&gt; &gt;+ where &gt;+ OPT: Into&lt;Option&lt;&amp;'a CStr&gt;&gt;, &gt; { &gt; let r = unsafe { &gt;- ffi::pa_context_connect(self.raw_mut(), &gt;- server.into().unwrap_cstr(), &gt;- flags.into(), &gt;- api) &gt;+ ffi::pa_context_connect( &gt;+ self.raw_mut(), &gt;+ server.into().unwrap_cstr(), &gt;+ flags.into(), &gt;+ api, &gt;+ ) &gt; }; &gt; error_result!((), r) &gt; } &gt; &gt; pub fn disconnect(&amp;self) { &gt; unsafe { &gt; ffi::pa_context_disconnect(self.raw_mut()); &gt; } &gt; } &gt; &gt;- &gt; pub fn drain&lt;CB&gt;(&amp;self, _: CB, userdata: *mut c_void) -&gt; Result&lt;Operation&gt; &gt;- where CB: Fn(&amp;Context, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;Context, *mut c_void), &gt; { &gt; debug_assert_eq!(::std::mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt; unsafe extern "C" fn wrapped&lt;F&gt;(c: *mut ffi::pa_context, userdata: *mut c_void) &gt;- where F: Fn(&amp;Context, *mut c_void) &gt;+ where &gt;+ F: Fn(&amp;Context, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let ctx = context::from_raw_ptr(c); &gt; let result = uninitialized::&lt;F&gt;()(&amp;ctx, userdata); &gt; forget(ctx); &gt; &gt; result &gt; } &gt; &gt;- op_or_err!(self, &gt;- ffi::pa_context_drain(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata)) &gt;+ op_or_err!( &gt;+ self, &gt;+ ffi::pa_context_drain(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata) &gt;+ ) &gt; } &gt; &gt;- pub fn rttime_new&lt;CB&gt;(&amp;self, usec: USec, _: CB, userdata: *mut c_void) -&gt; *mut ffi::pa_time_event &gt;- where CB: Fn(&amp;MainloopApi, *mut ffi::pa_time_event, &amp;TimeVal, *mut c_void) &gt;+ pub fn rttime_new&lt;CB&gt;( &gt;+ &amp;self, &gt;+ usec: USec, &gt;+ _: CB, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; *mut ffi::pa_time_event &gt;+ where &gt;+ CB: Fn(&amp;MainloopApi, *mut ffi::pa_time_event, &amp;TimeVal, *mut c_void), &gt; { &gt; debug_assert_eq!(::std::mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(a: *mut ffi::pa_mainloop_api, &gt;- e: *mut ffi::pa_time_event, &gt;- tv: *const TimeVal, &gt;- userdata: *mut c_void) &gt;- where F: Fn(&amp;MainloopApi, *mut ffi::pa_time_event, &amp;TimeVal, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ a: *mut ffi::pa_mainloop_api, &gt;+ e: *mut ffi::pa_time_event, &gt;+ tv: *const TimeVal, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;MainloopApi, *mut ffi::pa_time_event, &amp;TimeVal, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let api = mainloop_api::from_raw_ptr(a); &gt; let timeval = &amp;*tv; &gt; let result = uninitialized::&lt;F&gt;()(&amp;api, e, timeval, userdata); &gt; forget(api); &gt; &gt; result &gt; } &gt; &gt; unsafe { ffi::pa_context_rttime_new(self.raw_mut(), usec, Some(wrapped::&lt;CB&gt;), userdata) } &gt; } &gt; &gt; pub fn get_server_info&lt;CB&gt;(&amp;self, _: CB, userdata: *mut c_void) -&gt; Result&lt;Operation&gt; &gt;- where CB: Fn(&amp;Context, Option&lt;&amp;ServerInfo&gt;, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;Context, Option&lt;&amp;ServerInfo&gt;, *mut c_void), &gt; { &gt; debug_assert_eq!(::std::mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(c: *mut ffi::pa_context, i: *const ffi::pa_server_info, userdata: *mut c_void) &gt;- where F: Fn(&amp;Context, Option&lt;&amp;ServerInfo&gt;, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ c: *mut ffi::pa_context, &gt;+ i: *const ffi::pa_server_info, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Context, Option&lt;&amp;ServerInfo&gt;, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt;- let info = if i.is_null() { &gt;- None &gt;- } else { &gt;- Some(&amp;*i) &gt;- }; &gt;+ let info = if i.is_null() { None } else { Some(&amp;*i) }; &gt; let ctx = context::from_raw_ptr(c); &gt; let result = uninitialized::&lt;F&gt;()(&amp;ctx, info, userdata); &gt; forget(ctx); &gt; &gt; result &gt; } &gt; &gt;- op_or_err!(self, &gt;- ffi::pa_context_get_server_info(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata)) &gt;+ op_or_err!( &gt;+ self, &gt;+ ffi::pa_context_get_server_info(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata) &gt;+ ) &gt; } &gt; &gt;- pub fn get_sink_info_by_name&lt;'str, CS, CB&gt;(&amp;self, name: CS, _: CB, userdata: *mut c_void) -&gt; Result&lt;Operation&gt; &gt;+ pub fn get_sink_info_by_name&lt;'str, CS, CB&gt;( &gt;+ &amp;self, &gt;+ name: CS, &gt;+ _: CB, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; Result&lt;Operation&gt; &gt; where &gt; CB: Fn(&amp;Context, *const SinkInfo, i32, *mut c_void), &gt; CS: Into&lt;Option&lt;&amp;'str CStr&gt;&gt;, &gt; { &gt; debug_assert_eq!(::std::mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(c: *mut ffi::pa_context, &gt;- info: *const ffi::pa_sink_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void) &gt;- where F: Fn(&amp;Context, *const SinkInfo, i32, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ c: *mut ffi::pa_context, &gt;+ info: *const ffi::pa_sink_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Context, *const SinkInfo, i32, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let ctx = context::from_raw_ptr(c); &gt; let result = uninitialized::&lt;F&gt;()(&amp;ctx, info, eol, userdata); &gt; forget(ctx); &gt; &gt; result &gt; } &gt; &gt;- op_or_err!(self, &gt;- ffi::pa_context_get_sink_info_by_name(self.raw_mut(), &gt;- name.into().unwrap_cstr(), &gt;- Some(wrapped::&lt;CB&gt;), &gt;- userdata)) &gt;+ op_or_err!( &gt;+ self, &gt;+ ffi::pa_context_get_sink_info_by_name( &gt;+ self.raw_mut(), &gt;+ name.into().unwrap_cstr(), &gt;+ Some(wrapped::&lt;CB&gt;), &gt;+ userdata &gt;+ ) &gt;+ ) &gt; } &gt; &gt; pub fn get_sink_info_list&lt;CB&gt;(&amp;self, _: CB, userdata: *mut c_void) -&gt; Result&lt;Operation&gt; &gt;- where CB: Fn(&amp;Context, *const SinkInfo, i32, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;Context, *const SinkInfo, i32, *mut c_void), &gt; { &gt; debug_assert_eq!(::std::mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(c: *mut ffi::pa_context, &gt;- info: *const ffi::pa_sink_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void) &gt;- where F: Fn(&amp;Context, *const SinkInfo, i32, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ c: *mut ffi::pa_context, &gt;+ info: *const ffi::pa_sink_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Context, *const SinkInfo, i32, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let ctx = context::from_raw_ptr(c); &gt; let result = uninitialized::&lt;F&gt;()(&amp;ctx, info, eol, userdata); &gt; forget(ctx); &gt; &gt; result &gt; } &gt; &gt;- op_or_err!(self, &gt;- ffi::pa_context_get_sink_info_list(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata)) &gt;+ op_or_err!( &gt;+ self, &gt;+ ffi::pa_context_get_sink_info_list(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata) &gt;+ ) &gt; } &gt; &gt;- pub fn get_sink_input_info&lt;CB&gt;(&amp;self, idx: u32, _: CB, userdata: *mut c_void) -&gt; Result&lt;Operation&gt; &gt;- where CB: Fn(&amp;Context, *const SinkInputInfo, i32, *mut c_void) &gt;+ pub fn get_sink_input_info&lt;CB&gt;( &gt;+ &amp;self, &gt;+ idx: u32, &gt;+ _: CB, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; Result&lt;Operation&gt; &gt;+ where &gt;+ CB: Fn(&amp;Context, *const SinkInputInfo, i32, *mut c_void), &gt; { &gt; debug_assert_eq!(::std::mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(c: *mut ffi::pa_context, &gt;- info: *const ffi::pa_sink_input_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void) &gt;- where F: Fn(&amp;Context, *const SinkInputInfo, i32, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ c: *mut ffi::pa_context, &gt;+ info: *const ffi::pa_sink_input_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Context, *const SinkInputInfo, i32, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let ctx = context::from_raw_ptr(c); &gt; let result = uninitialized::&lt;F&gt;()(&amp;ctx, info, eol, userdata); &gt; forget(ctx); &gt; &gt; result &gt; } &gt; &gt;- op_or_err!(self, &gt;- ffi::pa_context_get_sink_input_info(self.raw_mut(), idx, Some(wrapped::&lt;CB&gt;), userdata)) &gt;+ op_or_err!( &gt;+ self, &gt;+ ffi::pa_context_get_sink_input_info(self.raw_mut(), idx, Some(wrapped::&lt;CB&gt;), userdata) &gt;+ ) &gt; } &gt; &gt; pub fn get_source_info_list&lt;CB&gt;(&amp;self, _: CB, userdata: *mut c_void) -&gt; Result&lt;Operation&gt; &gt;- where CB: Fn(&amp;Context, *const SourceInfo, i32, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;Context, *const SourceInfo, i32, *mut c_void), &gt; { &gt; debug_assert_eq!(::std::mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(c: *mut ffi::pa_context, &gt;- info: *const ffi::pa_source_info, &gt;- eol: c_int, &gt;- userdata: *mut c_void) &gt;- where F: Fn(&amp;Context, *const SourceInfo, i32, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ c: *mut ffi::pa_context, &gt;+ info: *const ffi::pa_source_info, &gt;+ eol: c_int, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Context, *const SourceInfo, i32, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let ctx = context::from_raw_ptr(c); &gt; let result = uninitialized::&lt;F&gt;()(&amp;ctx, info, eol, userdata); &gt; forget(ctx); &gt; &gt; result &gt; } &gt; &gt;- op_or_err!(self, &gt;- ffi::pa_context_get_source_info_list(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata)) &gt;+ op_or_err!( &gt;+ self, &gt;+ ffi::pa_context_get_source_info_list(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata) &gt;+ ) &gt; } &gt; &gt;- pub fn set_sink_input_volume&lt;CB&gt;(&amp;self, &gt;- idx: u32, &gt;- volume: &amp;CVolume, &gt;- _: CB, &gt;- userdata: *mut c_void) &gt;- -&gt; Result&lt;Operation&gt; &gt;- where CB: Fn(&amp;Context, i32, *mut c_void) &gt;+ pub fn set_sink_input_volume&lt;CB&gt;( &gt;+ &amp;self, &gt;+ idx: u32, &gt;+ volume: &amp;CVolume, &gt;+ _: CB, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; Result&lt;Operation&gt; &gt;+ where &gt;+ CB: Fn(&amp;Context, i32, *mut c_void), &gt; { &gt; debug_assert_eq!(::std::mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(c: *mut ffi::pa_context, success: c_int, userdata: *mut c_void) &gt;- where F: Fn(&amp;Context, i32, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ c: *mut ffi::pa_context, &gt;+ success: c_int, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Context, i32, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let ctx = context::from_raw_ptr(c); &gt; let result = uninitialized::&lt;F&gt;()(&amp;ctx, success, userdata); &gt; forget(ctx); &gt; &gt; result &gt; } &gt; &gt;- op_or_err!(self, &gt;- ffi::pa_context_set_sink_input_volume(self.raw_mut(), idx, volume, Some(wrapped::&lt;CB&gt;), userdata)) &gt;+ op_or_err!( &gt;+ self, &gt;+ ffi::pa_context_set_sink_input_volume( &gt;+ self.raw_mut(), &gt;+ idx, &gt;+ volume, &gt;+ Some(wrapped::&lt;CB&gt;), &gt;+ userdata &gt;+ ) &gt;+ ) &gt; } &gt; &gt;- pub fn subscribe&lt;CB&gt;(&amp;self, m: SubscriptionMask, _: CB, userdata: *mut c_void) -&gt; Result&lt;Operation&gt; &gt;- where CB: Fn(&amp;Context, i32, *mut c_void) &gt;+ pub fn subscribe&lt;CB&gt;( &gt;+ &amp;self, &gt;+ m: SubscriptionMask, &gt;+ _: CB, &gt;+ userdata: *mut c_void, &gt;+ ) -&gt; Result&lt;Operation&gt; &gt;+ where &gt;+ CB: Fn(&amp;Context, i32, *mut c_void), &gt; { &gt; debug_assert_eq!(::std::mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(c: *mut ffi::pa_context, success: c_int, userdata: *mut c_void) &gt;- where F: Fn(&amp;Context, i32, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ c: *mut ffi::pa_context, &gt;+ success: c_int, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Context, i32, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let ctx = context::from_raw_ptr(c); &gt; let result = uninitialized::&lt;F&gt;()(&amp;ctx, success, userdata); &gt; forget(ctx); &gt; &gt; result &gt; } &gt; &gt;- op_or_err!(self, &gt;- ffi::pa_context_subscribe(self.raw_mut(), m.into(), Some(wrapped::&lt;CB&gt;), userdata)) &gt;+ op_or_err!( &gt;+ self, &gt;+ ffi::pa_context_subscribe(self.raw_mut(), m.into(), Some(wrapped::&lt;CB&gt;), userdata) &gt;+ ) &gt; } &gt; &gt; pub fn clear_subscribe_callback(&amp;self) { &gt; unsafe { &gt; ffi::pa_context_set_subscribe_callback(self.raw_mut(), None, ptr::null_mut()); &gt; } &gt; } &gt; &gt; pub fn set_subscribe_callback&lt;CB&gt;(&amp;self, _: CB, userdata: *mut c_void) &gt;- where CB: Fn(&amp;Context, SubscriptionEvent, u32, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;Context, SubscriptionEvent, u32, *mut c_void), &gt; { &gt; debug_assert_eq!(::std::mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(c: *mut ffi::pa_context, &gt;- t: ffi::pa_subscription_event_type_t, &gt;- idx: u32, &gt;- userdata: *mut c_void) &gt;- where F: Fn(&amp;Context, SubscriptionEvent, u32, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ c: *mut ffi::pa_context, &gt;+ t: ffi::pa_subscription_event_type_t, &gt;+ idx: u32, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Context, SubscriptionEvent, u32, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let ctx = context::from_raw_ptr(c); &gt; let event = SubscriptionEvent::try_from(t) &gt;- .expect("pa_context_subscribe_cb_t passed invalid pa_subscription_event_type_t"); &gt;+ .expect("pa_context_subscribe_cb_t passed invalid pa_subscription_event_type_t"); &gt; let result = uninitialized::&lt;F&gt;()(&amp;ctx, event, idx, userdata); &gt; forget(ctx); &gt; &gt; result &gt; } &gt; &gt; unsafe { &gt; ffi::pa_context_set_subscribe_callback(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata); &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs &gt;index 99deae2b482d..2e6f7074f27a 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/error.rs &gt;@@ -9,17 +9,17 @@ use std::ffi::CStr; &gt; #[macro_export] &gt; macro_rules! error_result { &gt; ($t:expr, $err:expr) =&gt; { &gt; if $err &gt;= 0 { &gt; Ok($t) &gt; } else { &gt; Err(ErrorCode::from_error_result($err)) &gt; } &gt;- } &gt;+ }; &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct ErrorCode { &gt; err: ffi::pa_error_code_t, &gt; } &gt; &gt; impl ErrorCode { &gt;@@ -27,19 +27,17 @@ impl ErrorCode { &gt; debug_assert!(err &lt; 0); &gt; ErrorCode { &gt; err: (-err) as ffi::pa_error_code_t, &gt; } &gt; } &gt; &gt; pub fn from_error_code(err: ffi::pa_error_code_t) -&gt; Self { &gt; debug_assert!(err &gt; 0); &gt;- ErrorCode { &gt;- err: err, &gt;- } &gt;+ ErrorCode { err: err } &gt; } &gt; &gt; fn desc(&amp;self) -&gt; &amp;'static str { &gt; let cstr = unsafe { CStr::from_ptr(ffi::pa_strerror(self.err)) }; &gt; cstr.to_str().unwrap() &gt; } &gt; } &gt; &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs &gt;index f12f0a5bfb35..c852e5907ab2 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/lib.rs &gt;@@ -81,20 +81,20 @@ pub enum ContextState { &gt; Terminated = ffi::PA_CONTEXT_TERMINATED, &gt; } &gt; &gt; impl ContextState { &gt; // This function implements the PA_CONTENT_IS_GOOD macro from pulse/def.h &gt; // It must match the version from PA headers. &gt; pub fn is_good(self) -&gt; bool { &gt; match self { &gt;- ContextState::Connecting | &gt;- ContextState::Authorizing | &gt;- ContextState::SettingName | &gt;- ContextState::Ready =&gt; true, &gt;+ ContextState::Connecting &gt;+ | ContextState::Authorizing &gt;+ | ContextState::SettingName &gt;+ | ContextState::Ready =&gt; true, &gt; _ =&gt; false, &gt; } &gt; } &gt; &gt; pub fn try_from(x: ffi::pa_context_state_t) -&gt; Option&lt;Self&gt; { &gt; if x &gt;= ffi::PA_CONTEXT_UNCONNECTED &amp;&amp; x &lt;= ffi::PA_CONTEXT_TERMINATED { &gt; Some(unsafe { ::std::mem::transmute(x) }) &gt; } else { &gt;@@ -211,17 +211,16 @@ impl DeviceType { &gt; } &gt; &gt; impl Into&lt;ffi::pa_device_type_t&gt; for DeviceType { &gt; fn into(self) -&gt; ffi::pa_device_type_t { &gt; self as ffi::pa_device_type_t &gt; } &gt; } &gt; &gt;- &gt; #[repr(i32)] &gt; #[derive(Clone, Copy, Debug, PartialEq, Eq)] &gt; pub enum StreamDirection { &gt; NoDirection = ffi::PA_STREAM_NODIRECTION, &gt; Playback = ffi::PA_STREAM_PLAYBACK, &gt; Record = ffi::PA_STREAM_RECORD, &gt; StreamUpload = ffi::PA_STREAM_UPLOAD, &gt; } &gt;@@ -264,28 +263,39 @@ bitflags! { &gt; const FAIL_ON_SUSPEND = ffi::PA_STREAM_FAIL_ON_SUSPEND; &gt; const RELATIVE_VOLUME = ffi::PA_STREAM_RELATIVE_VOLUME; &gt; const PASSTHROUGH = ffi::PA_STREAM_PASSTHROUGH; &gt; } &gt; } &gt; &gt; impl StreamFlags { &gt; pub fn try_from(x: ffi::pa_stream_flags_t) -&gt; Option&lt;Self&gt; { &gt;- if (x &amp; &gt;- !(ffi::PA_STREAM_NOFLAGS | ffi::PA_STREAM_START_CORKED | ffi::PA_STREAM_INTERPOLATE_TIMING | &gt;- ffi::PA_STREAM_NOT_MONOTONIC | ffi::PA_STREAM_AUTO_TIMING_UPDATE | &gt;- ffi::PA_STREAM_NO_REMAP_CHANNELS | &gt;- ffi::PA_STREAM_NO_REMIX_CHANNELS | ffi::PA_STREAM_FIX_FORMAT | ffi::PA_STREAM_FIX_RATE | &gt;- ffi::PA_STREAM_FIX_CHANNELS | &gt;- ffi::PA_STREAM_DONT_MOVE | ffi::PA_STREAM_VARIABLE_RATE | ffi::PA_STREAM_PEAK_DETECT | &gt;- ffi::PA_STREAM_START_MUTED | ffi::PA_STREAM_ADJUST_LATENCY | &gt;- ffi::PA_STREAM_EARLY_REQUESTS | &gt;- ffi::PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND | &gt;- ffi::PA_STREAM_START_UNMUTED | ffi::PA_STREAM_FAIL_ON_SUSPEND | &gt;- ffi::PA_STREAM_RELATIVE_VOLUME | ffi::PA_STREAM_PASSTHROUGH)) == 0 { &gt;+ if (x &amp; !(ffi::PA_STREAM_NOFLAGS &gt;+ | ffi::PA_STREAM_START_CORKED &gt;+ | ffi::PA_STREAM_INTERPOLATE_TIMING &gt;+ | ffi::PA_STREAM_NOT_MONOTONIC &gt;+ | ffi::PA_STREAM_AUTO_TIMING_UPDATE &gt;+ | ffi::PA_STREAM_NO_REMAP_CHANNELS &gt;+ | ffi::PA_STREAM_NO_REMIX_CHANNELS &gt;+ | ffi::PA_STREAM_FIX_FORMAT &gt;+ | ffi::PA_STREAM_FIX_RATE &gt;+ | ffi::PA_STREAM_FIX_CHANNELS &gt;+ | ffi::PA_STREAM_DONT_MOVE &gt;+ | ffi::PA_STREAM_VARIABLE_RATE &gt;+ | ffi::PA_STREAM_PEAK_DETECT &gt;+ | ffi::PA_STREAM_START_MUTED &gt;+ | ffi::PA_STREAM_ADJUST_LATENCY &gt;+ | ffi::PA_STREAM_EARLY_REQUESTS &gt;+ | ffi::PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND &gt;+ | ffi::PA_STREAM_START_UNMUTED &gt;+ | ffi::PA_STREAM_FAIL_ON_SUSPEND &gt;+ | ffi::PA_STREAM_RELATIVE_VOLUME &gt;+ | ffi::PA_STREAM_PASSTHROUGH)) &gt;+ == 0 &gt;+ { &gt; Some(unsafe { ::std::mem::transmute(x) }) &gt; } else { &gt; None &gt; } &gt; } &gt; } &gt; &gt; impl Into&lt;ffi::pa_stream_flags_t&gt; for StreamFlags { &gt;@@ -353,17 +363,19 @@ pub enum SubscriptionEventType { &gt; Remove, &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, Debug, PartialEq, Eq)] &gt; pub struct SubscriptionEvent(ffi::pa_subscription_event_type_t); &gt; impl SubscriptionEvent { &gt; pub fn try_from(x: ffi::pa_subscription_event_type_t) -&gt; Option&lt;Self&gt; { &gt;- if (x &amp; !(ffi::PA_SUBSCRIPTION_EVENT_TYPE_MASK | ffi::PA_SUBSCRIPTION_EVENT_FACILITY_MASK)) == 0 { &gt;+ if (x &amp; !(ffi::PA_SUBSCRIPTION_EVENT_TYPE_MASK | ffi::PA_SUBSCRIPTION_EVENT_FACILITY_MASK)) &gt;+ == 0 &gt;+ { &gt; Some(SubscriptionEvent(x)) &gt; } else { &gt; None &gt; } &gt; } &gt; &gt; pub fn event_facility(self) -&gt; SubscriptionEventFacility { &gt; unsafe { ::std::mem::transmute(self.0 &amp; ffi::PA_SUBSCRIPTION_EVENT_FACILITY_MASK) } &gt;@@ -410,21 +422,28 @@ bitflags! { &gt; const FLAT_VOLUME = ffi::PA_SINK_FLAT_VOLUME; &gt; const DYNAMIC_LATENCY = ffi::PA_SINK_DYNAMIC_LATENCY; &gt; const SET_FORMATS = ffi::PA_SINK_SET_FORMATS; &gt; } &gt; } &gt; &gt; impl SinkFlags { &gt; pub fn try_from(x: ffi::pa_sink_flags_t) -&gt; Option&lt;SinkFlags&gt; { &gt;- if (x &amp; &gt;- !(ffi::PA_SINK_NOFLAGS | ffi::PA_SINK_HW_VOLUME_CTRL | ffi::PA_SINK_LATENCY | &gt;- ffi::PA_SINK_HARDWARE | ffi::PA_SINK_NETWORK | ffi::PA_SINK_HW_MUTE_CTRL | &gt;- ffi::PA_SINK_DECIBEL_VOLUME | ffi::PA_SINK_DYNAMIC_LATENCY | &gt;- ffi::PA_SINK_FLAT_VOLUME | ffi::PA_SINK_SET_FORMATS)) == 0 { &gt;+ if (x &amp; !(ffi::PA_SINK_NOFLAGS &gt;+ | ffi::PA_SINK_HW_VOLUME_CTRL &gt;+ | ffi::PA_SINK_LATENCY &gt;+ | ffi::PA_SINK_HARDWARE &gt;+ | ffi::PA_SINK_NETWORK &gt;+ | ffi::PA_SINK_HW_MUTE_CTRL &gt;+ | ffi::PA_SINK_DECIBEL_VOLUME &gt;+ | ffi::PA_SINK_DYNAMIC_LATENCY &gt;+ | ffi::PA_SINK_FLAT_VOLUME &gt;+ | ffi::PA_SINK_SET_FORMATS)) &gt;+ == 0 &gt;+ { &gt; Some(unsafe { ::std::mem::transmute(x) }) &gt; } else { &gt; None &gt; } &gt; } &gt; } &gt; &gt; #[repr(i32)] &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs &gt;index 1567cc461f22..4b2ad426c358 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/mainloop_api.rs &gt;@@ -2,27 +2,28 @@ &gt; // &gt; // This program is made available under an ISC-style license. See the &gt; // accompanying file LICENSE for details. &gt; &gt; use ffi; &gt; use std::mem; &gt; use std::os::raw::c_void; &gt; &gt;- &gt; #[allow(non_camel_case_types)] &gt;-type pa_once_cb_t = Option&lt;unsafe extern "C" fn(m: *mut ffi::pa_mainloop_api, &gt;- userdata: *mut c_void)&gt;; &gt;+type pa_once_cb_t = &gt;+ Option&lt;unsafe extern "C" fn(m: *mut ffi::pa_mainloop_api, userdata: *mut c_void)&gt;; &gt; fn wrap_once_cb&lt;F&gt;(_: F) -&gt; pa_once_cb_t &gt;- where F: Fn(&amp;MainloopApi, *mut c_void) &gt;+where &gt;+ F: Fn(&amp;MainloopApi, *mut c_void), &gt; { &gt; assert!(mem::size_of::&lt;F&gt;() == 0); &gt; &gt; unsafe extern "C" fn wrapped&lt;F&gt;(m: *mut ffi::pa_mainloop_api, userdata: *mut c_void) &gt;- where F: Fn(&amp;MainloopApi, *mut c_void) &gt;+ where &gt;+ F: Fn(&amp;MainloopApi, *mut c_void), &gt; { &gt; let api = from_raw_ptr(m); &gt; let result = mem::transmute::&lt;_, &amp;F&gt;(&amp;())(&amp;api, userdata); &gt; mem::forget(api); &gt; result &gt; } &gt; &gt; Some(wrapped::&lt;F&gt;) &gt;@@ -31,17 +32,18 @@ fn wrap_once_cb&lt;F&gt;(_: F) -&gt; pa_once_cb_t &gt; pub struct MainloopApi(*mut ffi::pa_mainloop_api); &gt; &gt; impl MainloopApi { &gt; pub fn raw_mut(&amp;self) -&gt; &amp;mut ffi::pa_mainloop_api { &gt; unsafe { &amp;mut *self.0 } &gt; } &gt; &gt; pub fn once&lt;CB&gt;(&amp;self, cb: CB, userdata: *mut c_void) &gt;- where CB: Fn(&amp;MainloopApi, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;MainloopApi, *mut c_void), &gt; { &gt; let wrapped = wrap_once_cb(cb); &gt; unsafe { &gt; ffi::pa_mainloop_api_once(self.raw_mut(), wrapped, userdata); &gt; } &gt; } &gt; &gt; pub fn time_free(&amp;self, e: *mut ffi::pa_time_event) { &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs &gt;index d99410c11c8a..460473f4677d 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/proplist.rs &gt;@@ -6,17 +6,18 @@ &gt; use ffi; &gt; use std::ffi::{CStr, CString}; &gt; &gt; #[derive(Debug)] &gt; pub struct Proplist(*mut ffi::pa_proplist); &gt; &gt; impl Proplist { &gt; pub fn gets&lt;T&gt;(&amp;self, key: T) -&gt; Option&lt;&amp;CStr&gt; &gt;- where T: Into&lt;Vec&lt;u8&gt;&gt; &gt;+ where &gt;+ T: Into&lt;Vec&lt;u8&gt;&gt;, &gt; { &gt; let key = match CString::new(key) { &gt; Ok(k) =&gt; k, &gt; _ =&gt; return None, &gt; }; &gt; let r = unsafe { ffi::pa_proplist_gets(self.0, key.as_ptr()) }; &gt; if r.is_null() { &gt; None &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs &gt;index 785ee1be485d..068233b2c788 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/stream.rs &gt;@@ -1,35 +1,43 @@ &gt; // Copyright © 2017 Mozilla Foundation &gt; // &gt; // This program is made available under an ISC-style license. See the &gt; // accompanying file LICENSE for details. &gt; &gt;-use ::*; &gt; use context; &gt; use ffi; &gt; use operation; &gt; use std::ffi::CStr; &gt; use std::mem; &gt; use std::os::raw::{c_int, c_void}; &gt; use std::ptr; &gt; use util::*; &gt;+use *; &gt; &gt; #[derive(Debug)] &gt; pub struct Stream(*mut ffi::pa_stream); &gt; &gt; impl Stream { &gt;- pub fn new&lt;'a, CM&gt;(c: &amp;Context, name: &amp;::std::ffi::CStr, ss: &amp;SampleSpec, map: CM) -&gt; Option&lt;Self&gt; &gt;- where CM: Into&lt;Option&lt;&amp;'a ChannelMap&gt;&gt; &gt;+ pub fn new&lt;'a, CM&gt;( &gt;+ c: &amp;Context, &gt;+ name: &amp;::std::ffi::CStr, &gt;+ ss: &amp;SampleSpec, &gt;+ map: CM, &gt;+ ) -&gt; Option&lt;Self&gt; &gt;+ where &gt;+ CM: Into&lt;Option&lt;&amp;'a ChannelMap&gt;&gt;, &gt; { &gt; let ptr = unsafe { &gt;- ffi::pa_stream_new(c.raw_mut(), &gt;- name.as_ptr(), &gt;- ss as *const _, &gt;- to_ptr(map.into())) &gt;+ ffi::pa_stream_new( &gt;+ c.raw_mut(), &gt;+ name.as_ptr(), &gt;+ ss as *const _, &gt;+ to_ptr(map.into()), &gt;+ ) &gt; }; &gt; if ptr.is_null() { &gt; None &gt; } else { &gt; Some(Stream(ptr)) &gt; } &gt; } &gt; &gt;@@ -40,19 +48,18 @@ impl Stream { &gt; &gt; pub fn unref(self) { &gt; unsafe { &gt; ffi::pa_stream_unref(self.raw_mut()); &gt; } &gt; } &gt; &gt; pub fn get_state(&amp;self) -&gt; StreamState { &gt;- StreamState::try_from(unsafe { &gt;- ffi::pa_stream_get_state(self.raw_mut()) &gt;- }).expect("pa_stream_get_state returned invalid StreamState") &gt;+ StreamState::try_from(unsafe { ffi::pa_stream_get_state(self.raw_mut()) }) &gt;+ .expect("pa_stream_get_state returned invalid StreamState") &gt; } &gt; &gt; pub fn get_context(&amp;self) -&gt; Option&lt;Context&gt; { &gt; let ptr = unsafe { ffi::pa_stream_get_context(self.raw_mut()) }; &gt; if ptr.is_null() { &gt; return None; &gt; } &gt; &gt;@@ -82,48 +89,55 @@ impl Stream { &gt; error_result!(r != 0, r) &gt; } &gt; &gt; pub fn is_corked(&amp;self) -&gt; Result&lt;bool&gt; { &gt; let r = unsafe { ffi::pa_stream_is_corked(self.raw_mut()) }; &gt; error_result!(r != 0, r) &gt; } &gt; &gt;- pub fn connect_playback&lt;'a, D, A, V, S&gt;(&amp;self, &gt;- dev: D, &gt;- attr: A, &gt;- flags: StreamFlags, &gt;- volume: V, &gt;- sync_stream: S) &gt;- -&gt; Result&lt;()&gt; &gt;- where D: Into&lt;Option&lt;&amp;'a CStr&gt;&gt;, &gt;- A: Into&lt;Option&lt;&amp;'a BufferAttr&gt;&gt;, &gt;- V: Into&lt;Option&lt;&amp;'a CVolume&gt;&gt;, &gt;- S: Into&lt;Option&lt;&amp;'a mut Stream&gt;&gt; &gt;+ pub fn connect_playback&lt;'a, D, A, V, S&gt;( &gt;+ &amp;self, &gt;+ dev: D, &gt;+ attr: A, &gt;+ flags: StreamFlags, &gt;+ volume: V, &gt;+ sync_stream: S, &gt;+ ) -&gt; Result&lt;()&gt; &gt;+ where &gt;+ D: Into&lt;Option&lt;&amp;'a CStr&gt;&gt;, &gt;+ A: Into&lt;Option&lt;&amp;'a BufferAttr&gt;&gt;, &gt;+ V: Into&lt;Option&lt;&amp;'a CVolume&gt;&gt;, &gt;+ S: Into&lt;Option&lt;&amp;'a mut Stream&gt;&gt;, &gt; { &gt; let r = unsafe { &gt;- ffi::pa_stream_connect_playback(self.raw_mut(), &gt;- str_to_ptr(dev.into()), &gt;- to_ptr(attr.into()), &gt;- flags.into(), &gt;- to_ptr(volume.into()), &gt;- map_to_mut_ptr(sync_stream.into(), |p| p.0)) &gt;+ ffi::pa_stream_connect_playback( &gt;+ self.raw_mut(), &gt;+ str_to_ptr(dev.into()), &gt;+ to_ptr(attr.into()), &gt;+ flags.into(), &gt;+ to_ptr(volume.into()), &gt;+ map_to_mut_ptr(sync_stream.into(), |p| p.0), &gt;+ ) &gt; }; &gt; error_result!((), r) &gt; } &gt; &gt; pub fn connect_record&lt;'a, D, A&gt;(&amp;self, dev: D, attr: A, flags: StreamFlags) -&gt; Result&lt;()&gt; &gt;- where D: Into&lt;Option&lt;&amp;'a CStr&gt;&gt;, &gt;- A: Into&lt;Option&lt;&amp;'a BufferAttr&gt;&gt; &gt;+ where &gt;+ D: Into&lt;Option&lt;&amp;'a CStr&gt;&gt;, &gt;+ A: Into&lt;Option&lt;&amp;'a BufferAttr&gt;&gt;, &gt; { &gt; let r = unsafe { &gt;- ffi::pa_stream_connect_record(self.raw_mut(), &gt;- str_to_ptr(dev.into()), &gt;- to_ptr(attr.into()), &gt;- flags.into()) &gt;+ ffi::pa_stream_connect_record( &gt;+ self.raw_mut(), &gt;+ str_to_ptr(dev.into()), &gt;+ to_ptr(attr.into()), &gt;+ flags.into(), &gt;+ ) &gt; }; &gt; error_result!((), r) &gt; } &gt; &gt; pub fn disconnect(&amp;self) -&gt; Result&lt;()&gt; { &gt; let r = unsafe { ffi::pa_stream_disconnect(self.raw_mut()) }; &gt; error_result!((), r) &gt; } &gt;@@ -135,18 +149,26 @@ impl Stream { &gt; error_result!((data, nbytes), r) &gt; } &gt; &gt; pub fn cancel_write(&amp;self) -&gt; Result&lt;()&gt; { &gt; let r = unsafe { ffi::pa_stream_cancel_write(self.raw_mut()) }; &gt; error_result!((), r) &gt; } &gt; &gt;- pub fn write(&amp;self, data: *const c_void, nbytes: usize, offset: i64, seek: SeekMode) -&gt; Result&lt;()&gt; { &gt;- let r = unsafe { ffi::pa_stream_write(self.raw_mut(), data, nbytes, None, offset, seek.into()) }; &gt;+ pub fn write( &gt;+ &amp;self, &gt;+ data: *const c_void, &gt;+ nbytes: usize, &gt;+ offset: i64, &gt;+ seek: SeekMode, &gt;+ ) -&gt; Result&lt;()&gt; { &gt;+ let r = unsafe { &gt;+ ffi::pa_stream_write(self.raw_mut(), data, nbytes, None, offset, seek.into()) &gt;+ }; &gt; error_result!((), r) &gt; } &gt; &gt; pub unsafe fn peek(&amp;self, data: *mut *const c_void, length: *mut usize) -&gt; Result&lt;()&gt; { &gt; let r = ffi::pa_stream_peek(self.raw_mut(), data, length); &gt; error_result!((), r) &gt; } &gt; &gt;@@ -177,33 +199,40 @@ impl Stream { &gt; ffi::PA_ERR_UNKNOWN &gt; }; &gt; return Err(ErrorCode::from_error_code(err)); &gt; } &gt; Ok(r) &gt; } &gt; &gt; pub fn update_timing_info&lt;CB&gt;(&amp;self, _: CB, userdata: *mut c_void) -&gt; Result&lt;Operation&gt; &gt;- where CB: Fn(&amp;Stream, i32, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;Stream, i32, *mut c_void), &gt; { &gt; debug_assert_eq!(mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(s: *mut ffi::pa_stream, success: c_int, userdata: *mut c_void) &gt;- where F: Fn(&amp;Stream, i32, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ s: *mut ffi::pa_stream, &gt;+ success: c_int, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Stream, i32, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let mut stm = stream::from_raw_ptr(s); &gt; let result = uninitialized::&lt;F&gt;()(&amp;mut stm, success, userdata); &gt; forget(stm); &gt; &gt; result &gt; } &gt; &gt;- let r = unsafe { ffi::pa_stream_update_timing_info(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata) }; &gt;+ let r = unsafe { &gt;+ ffi::pa_stream_update_timing_info(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata) &gt;+ }; &gt; if r.is_null() { &gt; let err = if let Some(c) = self.get_context() { &gt; c.errno() &gt; } else { &gt; ffi::PA_ERR_UNKNOWN &gt; }; &gt; return Err(ErrorCode::from_error_code(err)); &gt; } &gt;@@ -212,23 +241,25 @@ impl Stream { &gt; &gt; pub fn clear_state_callback(&amp;self) { &gt; unsafe { &gt; ffi::pa_stream_set_state_callback(self.raw_mut(), None, ptr::null_mut()); &gt; } &gt; } &gt; &gt; pub fn set_state_callback&lt;CB&gt;(&amp;self, _: CB, userdata: *mut c_void) &gt;- where CB: Fn(&amp;Stream, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;Stream, *mut c_void), &gt; { &gt; debug_assert_eq!(mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt; unsafe extern "C" fn wrapped&lt;F&gt;(s: *mut ffi::pa_stream, userdata: *mut c_void) &gt;- where F: Fn(&amp;Stream, *mut c_void) &gt;+ where &gt;+ F: Fn(&amp;Stream, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let mut stm = stream::from_raw_ptr(s); &gt; let result = uninitialized::&lt;F&gt;()(&amp;mut stm, userdata); &gt; forget(stm); &gt; &gt; result &gt; } &gt;@@ -240,23 +271,28 @@ impl Stream { &gt; &gt; pub fn clear_write_callback(&amp;self) { &gt; unsafe { &gt; ffi::pa_stream_set_write_callback(self.raw_mut(), None, ptr::null_mut()); &gt; } &gt; } &gt; &gt; pub fn set_write_callback&lt;CB&gt;(&amp;self, _: CB, userdata: *mut c_void) &gt;- where CB: Fn(&amp;Stream, usize, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;Stream, usize, *mut c_void), &gt; { &gt; debug_assert_eq!(mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(s: *mut ffi::pa_stream, nbytes: usize, userdata: *mut c_void) &gt;- where F: Fn(&amp;Stream, usize, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ s: *mut ffi::pa_stream, &gt;+ nbytes: usize, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Stream, usize, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let mut stm = stream::from_raw_ptr(s); &gt; let result = uninitialized::&lt;F&gt;()(&amp;mut stm, nbytes, userdata); &gt; forget(stm); &gt; &gt; result &gt; } &gt;@@ -268,45 +304,55 @@ impl Stream { &gt; &gt; pub fn clear_read_callback(&amp;self) { &gt; unsafe { &gt; ffi::pa_stream_set_read_callback(self.raw_mut(), None, ptr::null_mut()); &gt; } &gt; } &gt; &gt; pub fn set_read_callback&lt;CB&gt;(&amp;self, _: CB, userdata: *mut c_void) &gt;- where CB: Fn(&amp;Stream, usize, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;Stream, usize, *mut c_void), &gt; { &gt; debug_assert_eq!(mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(s: *mut ffi::pa_stream, nbytes: usize, userdata: *mut c_void) &gt;- where F: Fn(&amp;Stream, usize, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ s: *mut ffi::pa_stream, &gt;+ nbytes: usize, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Stream, usize, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let mut stm = stream::from_raw_ptr(s); &gt; let result = uninitialized::&lt;F&gt;()(&amp;mut stm, nbytes, userdata); &gt; forget(stm); &gt; &gt; result &gt; } &gt; &gt; unsafe { &gt; ffi::pa_stream_set_read_callback(self.raw_mut(), Some(wrapped::&lt;CB&gt;), userdata); &gt; } &gt; } &gt; &gt; pub fn cork&lt;CB&gt;(&amp;self, b: i32, _: CB, userdata: *mut c_void) -&gt; Result&lt;Operation&gt; &gt;- where CB: Fn(&amp;Stream, i32, *mut c_void) &gt;+ where &gt;+ CB: Fn(&amp;Stream, i32, *mut c_void), &gt; { &gt; debug_assert_eq!(mem::size_of::&lt;CB&gt;(), 0); &gt; &gt; // See: A note about `wrapped` functions &gt;- unsafe extern "C" fn wrapped&lt;F&gt;(s: *mut ffi::pa_stream, success: c_int, userdata: *mut c_void) &gt;- where F: Fn(&amp;Stream, i32, *mut c_void) &gt;+ unsafe extern "C" fn wrapped&lt;F&gt;( &gt;+ s: *mut ffi::pa_stream, &gt;+ success: c_int, &gt;+ userdata: *mut c_void, &gt;+ ) where &gt;+ F: Fn(&amp;Stream, i32, *mut c_void), &gt; { &gt; use std::mem::{forget, uninitialized}; &gt; let mut stm = stream::from_raw_ptr(s); &gt; let result = uninitialized::&lt;F&gt;()(&amp;mut stm, success, userdata); &gt; forget(stm); &gt; &gt; result &gt; } &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs &gt;index 865aaac76b21..74d2410d637c 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/threaded_mainloop.rs &gt;@@ -1,18 +1,18 @@ &gt; // Copyright © 2017 Mozilla Foundation &gt; // &gt; // This program is made available under an ISC-style license. See the &gt; // accompanying file LICENSE for details. &gt; &gt;-use ErrorCode; &gt;-use Result; &gt; use ffi; &gt; use mainloop_api; &gt; use mainloop_api::MainloopApi; &gt;+use ErrorCode; &gt;+use Result; &gt; &gt; #[derive(Debug)] &gt; pub struct ThreadedMainloop(*mut ffi::pa_threaded_mainloop); &gt; &gt; impl ThreadedMainloop { &gt; pub unsafe fn from_raw_ptr(raw: *mut ffi::pa_threaded_mainloop) -&gt; Self { &gt; ThreadedMainloop(raw) &gt; } &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs &gt;index 0723b1a186b9..8f18a49857da 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/pulse-rs/src/util.rs &gt;@@ -7,17 +7,18 @@ use std::ffi::CStr; &gt; use std::os::raw::c_char; &gt; use std::ptr; &gt; &gt; pub trait UnwrapCStr { &gt; fn unwrap_cstr(self) -&gt; *const c_char; &gt; } &gt; &gt; impl&lt;'a, U&gt; UnwrapCStr for U &gt;- where U: Into&lt;Option&lt;&amp;'a CStr&gt;&gt; &gt;+where &gt;+ U: Into&lt;Option&lt;&amp;'a CStr&gt;&gt;, &gt; { &gt; fn unwrap_cstr(self) -&gt; *const c_char { &gt; self.into().map(|o| o.as_ptr()).unwrap_or(0 as *const _) &gt; } &gt; } &gt; &gt; pub fn map_to_mut_ptr&lt;T, U, F: FnOnce(&amp;T) -&gt; *mut U&gt;(t: Option&lt;&amp;mut T&gt;, f: F) -&gt; *mut U { &gt; match t { &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs b/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs &gt;index 088651f8cc86..effc32e700b3 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs &gt;@@ -1,16 +1,18 @@ &gt; // Copyright © 2017-2018 Mozilla Foundation &gt; // &gt; // This program is made available under an ISC-style license. See the &gt; // accompanying file LICENSE for details. &gt; &gt; use backend::*; &gt;-use cubeb_backend::{ffi, log_enabled, Context, ContextOps, DeviceCollectionRef, DeviceId, &gt;- DeviceType, Error, Ops, Result, Stream, StreamParams, StreamParamsRef}; &gt;+use cubeb_backend::{ &gt;+ ffi, log_enabled, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceType, Error, Ops, &gt;+ Result, Stream, StreamParams, StreamParamsRef, &gt;+}; &gt; use pulse::{self, ProplistExt}; &gt; use pulse_ffi::*; &gt; use semver; &gt; use std::cell::RefCell; &gt; use std::default::Default; &gt; use std::ffi::{CStr, CString}; &gt; use std::mem; &gt; use std::os::raw::c_void; &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs b/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs &gt;index 8e067e6caecb..9255be83af08 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs &gt;@@ -1,17 +1,17 @@ &gt; // Copyright © 2017-2018 Mozilla Foundation &gt; // &gt; // This program is made available under an ISC-style license. See the &gt; // accompanying file LICENSE for details. &gt; &gt; mod context; &gt; mod cork_state; &gt;-mod stream; &gt; mod intern; &gt;+mod stream; &gt; &gt; pub use self::context::PulseContext; &gt; use self::intern::Intern; &gt; pub use self::stream::Device; &gt; pub use self::stream::PulseStream; &gt; use std::ffi::CStr; &gt; use std::os::raw::c_char; &gt; &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs b/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs &gt;index 96bee058f0b6..b314fa3dc7a3 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs &gt;@@ -1,22 +1,24 @@ &gt; // Copyright © 2017-2018 Mozilla Foundation &gt; // &gt; // This program is made available under an ISC-style license. See the &gt; // accompanying file LICENSE for details. &gt; &gt;-use backend::*; &gt; use backend::cork_state::CorkState; &gt;-use cubeb_backend::{ffi, log_enabled, ChannelLayout, DeviceId, DeviceRef, Error, Result, &gt;- SampleFormat, StreamOps, StreamParamsRef, StreamPrefs}; &gt;+use backend::*; &gt;+use cubeb_backend::{ &gt;+ ffi, log_enabled, ChannelLayout, DeviceId, DeviceRef, Error, Result, SampleFormat, StreamOps, &gt;+ StreamParamsRef, StreamPrefs, &gt;+}; &gt; use pulse::{self, CVolumeExt, ChannelMapExt, SampleSpecExt, StreamLatency, USecExt}; &gt; use pulse_ffi::*; &gt;-use std::{mem, ptr}; &gt; use std::ffi::{CStr, CString}; &gt; use std::os::raw::{c_long, c_void}; &gt;+use std::{mem, ptr}; &gt; &gt; const PULSE_NO_GAIN: f32 = -1.0; &gt; &gt; /// Iterator interface to `ChannelLayout`. &gt; /// &gt; /// Iterates each channel in the set represented by `ChannelLayout`. &gt; struct ChannelLayoutIter { &gt; /// The layout set being iterated &gt;@@ -375,17 +377,18 @@ impl&lt;'ctx&gt; Drop for PulseStream&lt;'ctx&gt; { &gt; } &gt; } &gt; &gt; impl&lt;'ctx&gt; StreamOps for PulseStream&lt;'ctx&gt; { &gt; fn start(&amp;mut self) -&gt; Result&lt;()&gt; { &gt; fn output_preroll(_: &amp;pulse::MainloopApi, u: *mut c_void) { &gt; let stm = unsafe { &amp;mut *(u as *mut PulseStream) }; &gt; if !stm.shutdown { &gt;- let size = stm.output_stream &gt;+ let size = stm &gt;+ .output_stream &gt; .as_ref() &gt; .map_or(0, |s| s.writable_size().unwrap_or(0)); &gt; stm.trigger_user_callback(ptr::null_mut(), size); &gt; } &gt; } &gt; &gt; self.shutdown = false; &gt; self.cork(CorkState::uncork() | CorkState::notify()); &gt;@@ -940,19 +943,19 @@ fn invalid_format() -&gt; Error { &gt; } &gt; &gt; fn not_supported() -&gt; Error { &gt; unsafe { Error::from_raw(ffi::CUBEB_ERROR_NOT_SUPPORTED) } &gt; } &gt; &gt; #[cfg(all(test, not(feature = "pulse-dlopen")))] &gt; mod test { &gt;+ use super::layout_to_channel_map; &gt; use cubeb_backend::ChannelLayout; &gt; use pulse_ffi::*; &gt;- use super::layout_to_channel_map; &gt; &gt; macro_rules! channel_tests { &gt; {$($name: ident, $layout: ident =&gt; [ $($channels: ident),* ]),+} =&gt; { &gt; $( &gt; #[test] &gt; fn $name() { &gt; let layout = ChannelLayout::$layout; &gt; let mut iter = super::channel_layout_iter(layout); &gt;diff --git a/media/libcubeb/cubeb-pulse-rs/src/lib.rs b/media/libcubeb/cubeb-pulse-rs/src/lib.rs &gt;index 7b73322aa29b..1aac80e3eae7 100644 &gt;--- a/media/libcubeb/cubeb-pulse-rs/src/lib.rs &gt;+++ b/media/libcubeb/cubeb-pulse-rs/src/lib.rs &gt;@@ -6,12 +6,12 @@ &gt; // accompanying file LICENSE for details. &gt; &gt; #[macro_use] &gt; extern crate cubeb_backend; &gt; extern crate pulse; &gt; extern crate pulse_ffi; &gt; extern crate semver; &gt; &gt;-mod capi; &gt; mod backend; &gt;+mod capi; &gt; &gt; pub use capi::pulse_rust_init; &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs b/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs &gt;index ec92c952206a..a59792957b12 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/attribute_type.rs &gt;@@ -1,50 +1,50 @@ &gt;-use std::net::IpAddr; &gt;-use std::str::FromStr; &gt; use std::fmt; &gt; use std::iter; &gt;+use std::net::IpAddr; &gt;+use std::str::FromStr; &gt; &gt;-use SdpType; &gt; use error::SdpParserInternalError; &gt;-use network::{parse_nettype, parse_addrtype, parse_unicast_addr}; &gt;+use network::{parse_addrtype, parse_nettype, parse_unicast_addr}; &gt;+use SdpType; &gt; &gt; #[derive(Debug, Clone, PartialEq)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;-pub enum SdpSingleDirection{ &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt;+pub enum SdpSingleDirection { &gt; // This is explicitly 1 and 2 to match the defines in the C++ glue code. &gt; Send = 1, &gt; Recv = 2, &gt; } &gt; &gt; #[derive(Debug, PartialEq, Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributePayloadType { &gt; PayloadType(u8), &gt; Wildcard, // Wildcard means "*", &gt; } &gt; &gt; #[derive(Debug, Clone, PartialEq)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeCandidateTransport { &gt; Udp, &gt; Tcp, &gt; } &gt; &gt; impl ToString for SdpAttributeCandidateTransport { &gt; fn to_string(&amp;self) -&gt; String { &gt; match *self { &gt; SdpAttributeCandidateTransport::Udp =&gt; "UDP".to_string(), &gt; SdpAttributeCandidateTransport::Tcp =&gt; "TCP".to_string(), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug, Clone, PartialEq)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeCandidateType { &gt; Host, &gt; Srflx, &gt; Prflx, &gt; Relay, &gt; } &gt; &gt; impl ToString for SdpAttributeCandidateType { &gt;@@ -54,17 +54,17 @@ impl ToString for SdpAttributeCandidateType { &gt; SdpAttributeCandidateType::Srflx =&gt; "srflx".to_string(), &gt; SdpAttributeCandidateType::Prflx =&gt; "prflx".to_string(), &gt; SdpAttributeCandidateType::Relay =&gt; "relay".to_string(), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug, Clone, PartialEq)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeCandidateTcpType { &gt; Active, &gt; Passive, &gt; Simultaneous, &gt; } &gt; &gt; impl ToString for SdpAttributeCandidateTcpType { &gt; fn to_string(&amp;self) -&gt; String { &gt;@@ -72,17 +72,17 @@ impl ToString for SdpAttributeCandidateTcpType { &gt; SdpAttributeCandidateTcpType::Active =&gt; "active".to_string(), &gt; SdpAttributeCandidateTcpType::Passive =&gt; "passive".to_string(), &gt; SdpAttributeCandidateTcpType::Simultaneous =&gt; "so".to_string(), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeCandidate { &gt; pub foundation: String, &gt; pub component: u32, &gt; pub transport: SdpAttributeCandidateTransport, &gt; pub priority: u64, &gt; pub address: IpAddr, &gt; pub port: u32, &gt; pub c_type: SdpAttributeCandidateType, &gt;@@ -90,24 +90,25 @@ pub struct SdpAttributeCandidate { &gt; pub rport: Option&lt;u32&gt;, &gt; pub tcp_type: Option&lt;SdpAttributeCandidateTcpType&gt;, &gt; pub generation: Option&lt;u32&gt;, &gt; pub ufrag: Option&lt;String&gt;, &gt; pub networkcost: Option&lt;u32&gt;, &gt; } &gt; &gt; impl SdpAttributeCandidate { &gt;- pub fn new(foundation: String, &gt;- component: u32, &gt;- transport: SdpAttributeCandidateTransport, &gt;- priority: u64, &gt;- address: IpAddr, &gt;- port: u32, &gt;- c_type: SdpAttributeCandidateType) &gt;- -&gt; SdpAttributeCandidate { &gt;+ pub fn new( &gt;+ foundation: String, &gt;+ component: u32, &gt;+ transport: SdpAttributeCandidateTransport, &gt;+ priority: u64, &gt;+ address: IpAddr, &gt;+ port: u32, &gt;+ c_type: SdpAttributeCandidateType, &gt;+ ) -&gt; SdpAttributeCandidate { &gt; SdpAttributeCandidate { &gt; foundation, &gt; component, &gt; transport, &gt; priority, &gt; address, &gt; port, &gt; c_type, &gt;@@ -146,57 +147,59 @@ impl SdpAttributeCandidate { &gt; } &gt; &gt; impl ToString for SdpAttributeCandidate { &gt; fn to_string(&amp;self) -&gt; String { &gt; macro_rules! option_to_string { &gt; ($fmt_str:expr, $opt:expr) =&gt; { &gt; match $opt { &gt; Some(ref x) =&gt; format!($fmt_str, x.to_string()), &gt;- None =&gt; "".to_string() &gt;+ None =&gt; "".to_string(), &gt; } &gt; }; &gt; } &gt; &gt;- format!("candidate:{foundation} {component_id} {transport} {priority} \ &gt;- {connection_address} {port} typ {cand_type}\ &gt;- {rel_addr}{rel_port}{tcp_type}{generation}{ufrag}{network_cost}", &gt;- foundation = self.foundation, &gt;- component_id = self.component.to_string(), &gt;- transport = self.transport.to_string(), &gt;- priority = self.priority.to_string(), &gt;- connection_address = self.address.to_string(), &gt;- port = self.port.to_string(), &gt;- cand_type = self.c_type.to_string(), &gt;- rel_addr = option_to_string!(" raddr {}", self.raddr), &gt;- rel_port = option_to_string!(" rport {}", self.rport), &gt;- tcp_type = option_to_string!(" tcptype {}", self.tcp_type), &gt;- generation = option_to_string!(" generation {}", self.generation), &gt;- ufrag = option_to_string!(" ufrag {}", self.ufrag), &gt;- network_cost = option_to_string!(" network-cost {}", self.networkcost)) &gt;+ format!( &gt;+ "candidate:{foundation} {component_id} {transport} {priority} \ &gt;+ {connection_address} {port} typ {cand_type}\ &gt;+ {rel_addr}{rel_port}{tcp_type}{generation}{ufrag}{network_cost}", &gt;+ foundation = self.foundation, &gt;+ component_id = self.component.to_string(), &gt;+ transport = self.transport.to_string(), &gt;+ priority = self.priority.to_string(), &gt;+ connection_address = self.address.to_string(), &gt;+ port = self.port.to_string(), &gt;+ cand_type = self.c_type.to_string(), &gt;+ rel_addr = option_to_string!(" raddr {}", self.raddr), &gt;+ rel_port = option_to_string!(" rport {}", self.rport), &gt;+ tcp_type = option_to_string!(" tcptype {}", self.tcp_type), &gt;+ generation = option_to_string!(" generation {}", self.generation), &gt;+ ufrag = option_to_string!(" ufrag {}", self.ufrag), &gt;+ network_cost = option_to_string!(" network-cost {}", self.networkcost) &gt;+ ) &gt; } &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeDtlsMessage { &gt; Client(String), &gt; Server(String), &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeRemoteCandidate { &gt; pub component: u32, &gt; pub address: IpAddr, &gt; pub port: u32, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeSimulcastId { &gt; pub id: String, &gt; pub paused: bool, &gt; } &gt; &gt; impl SdpAttributeSimulcastId { &gt; pub fn new(idstr: &amp;str) -&gt; SdpAttributeSimulcastId { &gt; if idstr.starts_with('~') { &gt;@@ -210,41 +213,41 @@ impl SdpAttributeSimulcastId { &gt; paused: false, &gt; } &gt; } &gt; } &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeSimulcastVersion { &gt; pub ids: Vec&lt;SdpAttributeSimulcastId&gt;, &gt; } &gt; &gt; impl SdpAttributeSimulcastVersion { &gt; pub fn new(idlist: &amp;str) -&gt; SdpAttributeSimulcastVersion { &gt; SdpAttributeSimulcastVersion { &gt; ids: idlist &gt; .split(',') &gt; .map(SdpAttributeSimulcastId::new) &gt; .collect(), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeSimulcast { &gt; pub send: Vec&lt;SdpAttributeSimulcastVersion&gt;, &gt; pub receive: Vec&lt;SdpAttributeSimulcastVersion&gt;, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeRtcp { &gt; pub port: u16, &gt; pub unicast_addr: Option&lt;IpAddr&gt;, &gt; } &gt; &gt; impl SdpAttributeRtcp { &gt; pub fn new(port: u16) -&gt; SdpAttributeRtcp { &gt; SdpAttributeRtcp { &gt;@@ -254,56 +257,56 @@ impl SdpAttributeRtcp { &gt; } &gt; &gt; fn set_addr(&amp;mut self, addr: IpAddr) { &gt; self.unicast_addr = Some(addr) &gt; } &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeRtcpFbType { &gt; Ack = 0, &gt; Ccm = 2, // This is explicitly 2 to make the conversion to the &gt;- // enum used in the glue-code possible. The glue code has "app" &gt;- // in the place of 1 &gt;+ // enum used in the glue-code possible. The glue code has "app" &gt;+ // in the place of 1 &gt; Nack, &gt; TrrInt, &gt; Remb, &gt;- TransCC &gt;+ TransCC, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeRtcpFb { &gt; pub payload_type: SdpAttributePayloadType, &gt; pub feedback_type: SdpAttributeRtcpFbType, &gt; pub parameter: String, &gt; pub extra: String, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeDirection { &gt; Recvonly, &gt; Sendonly, &gt; Sendrecv, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeExtmap { &gt; pub id: u16, &gt; pub direction: Option&lt;SdpAttributeDirection&gt;, &gt; pub url: String, &gt; pub extension_attributes: Option&lt;String&gt;, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeFmtpParameters { &gt; // H264 &gt; // TODO(bug 1466859): Support sprop-parameter-sets &gt; // pub static const max_sprop_len: u32 = 128, &gt; // pub sprop_parameter_sets: [u8, max_sprop_len], &gt; pub packetization_mode: u32, &gt; pub level_asymmetry_allowed: bool, &gt; pub profile_level_id: u32, &gt;@@ -329,152 +332,151 @@ pub struct SdpAttributeFmtpParameters { &gt; &gt; // telephone-event &gt; pub dtmf_tones: String, &gt; &gt; // Unknown &gt; pub unknown_tokens: Vec&lt;String&gt;, &gt; } &gt; &gt;- &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeFmtp { &gt; pub payload_type: u8, &gt; pub parameters: SdpAttributeFmtpParameters, &gt; } &gt; &gt; #[derive(Clone, Copy)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeFingerprintHashType { &gt; Sha1, &gt; Sha224, &gt; Sha256, &gt; Sha384, &gt; Sha512, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeFingerprint { &gt; pub hash_algorithm: SdpAttributeFingerprintHashType, &gt;- pub fingerprint: Vec&lt;u8&gt; &gt;+ pub fingerprint: Vec&lt;u8&gt;, &gt; } &gt; &gt; #[derive(Debug, PartialEq, Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeImageAttrXYRange { &gt;- Range(u32,u32,Option&lt;u32&gt;), // min, max, step &gt;+ Range(u32, u32, Option&lt;u32&gt;), // min, max, step &gt; DiscreteValues(Vec&lt;u32&gt;), &gt; } &gt; &gt; #[derive(Debug, PartialEq, Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeImageAttrSRange { &gt;- Range(f32,f32), // min, max &gt;+ Range(f32, f32), // min, max &gt; DiscreteValues(Vec&lt;f32&gt;), &gt; } &gt; &gt; #[derive(Debug, PartialEq, Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeImageAttrPRange { &gt; pub min: f32, &gt; pub max: f32, &gt; } &gt; &gt; #[derive(Debug, PartialEq, Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeImageAttrSet { &gt; pub x: SdpAttributeImageAttrXYRange, &gt; pub y: SdpAttributeImageAttrXYRange, &gt; pub sar: Option&lt;SdpAttributeImageAttrSRange&gt;, &gt; pub par: Option&lt;SdpAttributeImageAttrPRange&gt;, &gt; pub q: Option&lt;f32&gt;, &gt; } &gt; &gt; #[derive(Debug, PartialEq, Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeImageAttrSetList { &gt; Sets(Vec&lt;SdpAttributeImageAttrSet&gt;), &gt; Wildcard, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeImageAttr { &gt; pub pt: SdpAttributePayloadType, &gt; pub send: SdpAttributeImageAttrSetList, &gt; pub recv: SdpAttributeImageAttrSetList, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeSctpmap { &gt; pub port: u16, &gt; pub channels: u32, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeGroupSemantic { &gt; LipSynchronization, &gt; FlowIdentification, &gt; SingleReservationFlow, &gt; AlternateNetworkAddressType, &gt; ForwardErrorCorrection, &gt; DecodingDependency, &gt; Bundle, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeGroup { &gt; pub semantics: SdpAttributeGroupSemantic, &gt; pub tags: Vec&lt;String&gt;, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeMsid { &gt; pub id: String, &gt; pub appdata: Option&lt;String&gt;, &gt; } &gt; &gt; #[derive(Clone, Debug)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeMsidSemantic { &gt; pub semantic: String, &gt; pub msids: Vec&lt;String&gt;, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;-pub struct SdpAttributeRidParameters{ &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt;+pub struct SdpAttributeRidParameters { &gt; pub max_width: u32, &gt; pub max_height: u32, &gt; pub max_fps: u32, &gt; pub max_fs: u32, &gt; pub max_br: u32, &gt; pub max_pps: u32, &gt; &gt;- pub unknown: Vec&lt;String&gt; &gt;+ pub unknown: Vec&lt;String&gt;, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeRid { &gt; pub id: String, &gt; pub direction: SdpSingleDirection, &gt; pub formats: Vec&lt;u16&gt;, &gt; pub params: SdpAttributeRidParameters, &gt;- pub depends: Vec&lt;String&gt; &gt;+ pub depends: Vec&lt;String&gt;, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeRtpmap { &gt; pub payload_type: u8, &gt; pub codec_name: String, &gt; pub frequency: u32, &gt; pub channels: Option&lt;u32&gt;, &gt; } &gt; &gt; impl SdpAttributeRtpmap { &gt;@@ -488,26 +490,26 @@ impl SdpAttributeRtpmap { &gt; } &gt; &gt; fn set_channels(&amp;mut self, c: u32) { &gt; self.channels = Some(c) &gt; } &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttributeSetup { &gt; Active, &gt; Actpass, &gt; Holdconn, &gt; Passive, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpAttributeSsrc { &gt; pub id: u32, &gt; pub attribute: Option&lt;String&gt;, &gt; pub value: Option&lt;String&gt;, &gt; } &gt; &gt; impl SdpAttributeSsrc { &gt; pub fn new(id: u32) -&gt; SdpAttributeSsrc { &gt;@@ -525,17 +527,17 @@ impl SdpAttributeSsrc { &gt; let v: Vec&lt;&amp;str&gt; = a.splitn(2, ':').collect(); &gt; self.attribute = Some(v[0].to_string()); &gt; self.value = Some(v[1].to_string()); &gt; } &gt; } &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpAttribute { &gt; BundleOnly, &gt; Candidate(SdpAttributeCandidate), &gt; DtlsMessage(SdpAttributeDtlsMessage), &gt; EndOfCandidates, &gt; Extmap(SdpAttributeExtmap), &gt; Fingerprint(SdpAttributeFingerprint), &gt; Fmtp(SdpAttributeFmtp), &gt;@@ -571,111 +573,111 @@ pub enum SdpAttribute { &gt; Simulcast(SdpAttributeSimulcast), &gt; Ssrc(SdpAttributeSsrc), &gt; SsrcGroup(String), &gt; } &gt; &gt; impl SdpAttribute { &gt; pub fn allowed_at_session_level(&amp;self) -&gt; bool { &gt; match *self { &gt;- SdpAttribute::BundleOnly | &gt;- SdpAttribute::Candidate(..) | &gt;- SdpAttribute::Fmtp(..) | &gt;- SdpAttribute::IceMismatch | &gt;- SdpAttribute::ImageAttr(..) | &gt;- SdpAttribute::Label(..) | &gt;- SdpAttribute::MaxMessageSize(..) | &gt;- SdpAttribute::MaxPtime(..) | &gt;- SdpAttribute::Mid(..) | &gt;- SdpAttribute::Msid(..) | &gt;- SdpAttribute::Ptime(..) | &gt;- SdpAttribute::Rid(..) | &gt;- SdpAttribute::RemoteCandidate(..) | &gt;- SdpAttribute::Rtpmap(..) | &gt;- SdpAttribute::Rtcp(..) | &gt;- SdpAttribute::Rtcpfb(..) | &gt;- SdpAttribute::RtcpMux | &gt;- SdpAttribute::RtcpRsize | &gt;- SdpAttribute::Sctpmap(..) | &gt;- SdpAttribute::SctpPort(..) | &gt;- SdpAttribute::Simulcast(..) | &gt;- SdpAttribute::Ssrc(..) | &gt;- SdpAttribute::SsrcGroup(..) =&gt; false, &gt;+ SdpAttribute::BundleOnly &gt;+ | SdpAttribute::Candidate(..) &gt;+ | SdpAttribute::Fmtp(..) &gt;+ | SdpAttribute::IceMismatch &gt;+ | SdpAttribute::ImageAttr(..) &gt;+ | SdpAttribute::Label(..) &gt;+ | SdpAttribute::MaxMessageSize(..) &gt;+ | SdpAttribute::MaxPtime(..) &gt;+ | SdpAttribute::Mid(..) &gt;+ | SdpAttribute::Msid(..) &gt;+ | SdpAttribute::Ptime(..) &gt;+ | SdpAttribute::Rid(..) &gt;+ | SdpAttribute::RemoteCandidate(..) &gt;+ | SdpAttribute::Rtpmap(..) &gt;+ | SdpAttribute::Rtcp(..) &gt;+ | SdpAttribute::Rtcpfb(..) &gt;+ | SdpAttribute::RtcpMux &gt;+ | SdpAttribute::RtcpRsize &gt;+ | SdpAttribute::Sctpmap(..) &gt;+ | SdpAttribute::SctpPort(..) &gt;+ | SdpAttribute::Simulcast(..) &gt;+ | SdpAttribute::Ssrc(..) &gt;+ | SdpAttribute::SsrcGroup(..) =&gt; false, &gt; &gt;- SdpAttribute::DtlsMessage{..} | &gt;- SdpAttribute::EndOfCandidates | &gt;- SdpAttribute::Extmap(..) | &gt;- SdpAttribute::Fingerprint(..) | &gt;- SdpAttribute::Group(..) | &gt;- SdpAttribute::IceLite | &gt;- SdpAttribute::IceOptions(..) | &gt;- SdpAttribute::IcePwd(..) | &gt;- SdpAttribute::IceUfrag(..) | &gt;- SdpAttribute::Identity(..) | &gt;- SdpAttribute::Inactive | &gt;- SdpAttribute::MsidSemantic(..) | &gt;- SdpAttribute::Recvonly | &gt;- SdpAttribute::Sendonly | &gt;- SdpAttribute::Sendrecv | &gt;- SdpAttribute::Setup(..) =&gt; true, &gt;+ SdpAttribute::DtlsMessage { .. } &gt;+ | SdpAttribute::EndOfCandidates &gt;+ | SdpAttribute::Extmap(..) &gt;+ | SdpAttribute::Fingerprint(..) &gt;+ | SdpAttribute::Group(..) &gt;+ | SdpAttribute::IceLite &gt;+ | SdpAttribute::IceOptions(..) &gt;+ | SdpAttribute::IcePwd(..) &gt;+ | SdpAttribute::IceUfrag(..) &gt;+ | SdpAttribute::Identity(..) &gt;+ | SdpAttribute::Inactive &gt;+ | SdpAttribute::MsidSemantic(..) &gt;+ | SdpAttribute::Recvonly &gt;+ | SdpAttribute::Sendonly &gt;+ | SdpAttribute::Sendrecv &gt;+ | SdpAttribute::Setup(..) =&gt; true, &gt; } &gt; } &gt; &gt; pub fn allowed_at_media_level(&amp;self) -&gt; bool { &gt; match *self { &gt;- SdpAttribute::DtlsMessage{..} | &gt;- SdpAttribute::Group(..) | &gt;- SdpAttribute::IceLite | &gt;- SdpAttribute::Identity(..) | &gt;- SdpAttribute::MsidSemantic(..) =&gt; false, &gt;+ SdpAttribute::DtlsMessage { .. } &gt;+ | SdpAttribute::Group(..) &gt;+ | SdpAttribute::IceLite &gt;+ | SdpAttribute::Identity(..) &gt;+ | SdpAttribute::MsidSemantic(..) =&gt; false, &gt; &gt;- SdpAttribute::BundleOnly | &gt;- SdpAttribute::Candidate(..) | &gt;- SdpAttribute::EndOfCandidates | &gt;- SdpAttribute::Extmap(..) | &gt;- SdpAttribute::Fingerprint(..) | &gt;- SdpAttribute::Fmtp(..) | &gt;- SdpAttribute::IceMismatch | &gt;- SdpAttribute::IceOptions(..) | &gt;- SdpAttribute::IcePwd(..) | &gt;- SdpAttribute::IceUfrag(..) | &gt;- SdpAttribute::ImageAttr(..) | &gt;- SdpAttribute::Inactive | &gt;- SdpAttribute::Label(..) | &gt;- SdpAttribute::MaxMessageSize(..) | &gt;- SdpAttribute::MaxPtime(..) | &gt;- SdpAttribute::Mid(..) | &gt;- SdpAttribute::Msid(..) | &gt;- SdpAttribute::Ptime(..) | &gt;- SdpAttribute::Rid(..) | &gt;- SdpAttribute::Recvonly | &gt;- SdpAttribute::RemoteCandidate(..) | &gt;- SdpAttribute::Rtpmap(..) | &gt;- SdpAttribute::Rtcp(..) | &gt;- SdpAttribute::Rtcpfb(..) | &gt;- SdpAttribute::RtcpMux | &gt;- SdpAttribute::RtcpRsize | &gt;- SdpAttribute::Sctpmap(..) | &gt;- SdpAttribute::SctpPort(..) | &gt;- SdpAttribute::Sendonly | &gt;- SdpAttribute::Sendrecv | &gt;- SdpAttribute::Setup(..) | &gt;- SdpAttribute::Simulcast(..) | &gt;- SdpAttribute::Ssrc(..) | &gt;- SdpAttribute::SsrcGroup(..) =&gt; true, &gt;+ SdpAttribute::BundleOnly &gt;+ | SdpAttribute::Candidate(..) &gt;+ | SdpAttribute::EndOfCandidates &gt;+ | SdpAttribute::Extmap(..) &gt;+ | SdpAttribute::Fingerprint(..) &gt;+ | SdpAttribute::Fmtp(..) &gt;+ | SdpAttribute::IceMismatch &gt;+ | SdpAttribute::IceOptions(..) &gt;+ | SdpAttribute::IcePwd(..) &gt;+ | SdpAttribute::IceUfrag(..) &gt;+ | SdpAttribute::ImageAttr(..) &gt;+ | SdpAttribute::Inactive &gt;+ | SdpAttribute::Label(..) &gt;+ | SdpAttribute::MaxMessageSize(..) &gt;+ | SdpAttribute::MaxPtime(..) &gt;+ | SdpAttribute::Mid(..) &gt;+ | SdpAttribute::Msid(..) &gt;+ | SdpAttribute::Ptime(..) &gt;+ | SdpAttribute::Rid(..) &gt;+ | SdpAttribute::Recvonly &gt;+ | SdpAttribute::RemoteCandidate(..) &gt;+ | SdpAttribute::Rtpmap(..) &gt;+ | SdpAttribute::Rtcp(..) &gt;+ | SdpAttribute::Rtcpfb(..) &gt;+ | SdpAttribute::RtcpMux &gt;+ | SdpAttribute::RtcpRsize &gt;+ | SdpAttribute::Sctpmap(..) &gt;+ | SdpAttribute::SctpPort(..) &gt;+ | SdpAttribute::Sendonly &gt;+ | SdpAttribute::Sendrecv &gt;+ | SdpAttribute::Setup(..) &gt;+ | SdpAttribute::Simulcast(..) &gt;+ | SdpAttribute::Ssrc(..) &gt;+ | SdpAttribute::SsrcGroup(..) =&gt; true, &gt; } &gt; } &gt; } &gt; &gt; impl fmt::Display for SdpAttribute { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; let printable = match *self { &gt; SdpAttribute::BundleOnly =&gt; "bundle-only", &gt; SdpAttribute::Candidate(..) =&gt; "candidate", &gt;- SdpAttribute::DtlsMessage{..} =&gt; "dtls-message", &gt;+ SdpAttribute::DtlsMessage { .. } =&gt; "dtls-message", &gt; SdpAttribute::EndOfCandidates =&gt; "end-of-candidates", &gt; SdpAttribute::Extmap(..) =&gt; "extmap", &gt; SdpAttribute::Fingerprint(..) =&gt; "fingerprint", &gt; SdpAttribute::Fmtp(..) =&gt; "fmtp", &gt; SdpAttribute::Group(..) =&gt; "group", &gt; SdpAttribute::IceLite =&gt; "ice-lite", &gt; SdpAttribute::IceMismatch =&gt; "ice-mismatch", &gt; SdpAttribute::IceOptions(..) =&gt; "ice-options", &gt;@@ -718,28 +720,22 @@ impl FromStr for SdpAttribute { &gt; let tokens: Vec&lt;_&gt; = line.splitn(2, ':').collect(); &gt; let name = tokens[0].to_lowercase(); &gt; let val = match tokens.get(1) { &gt; Some(x) =&gt; x.trim(), &gt; None =&gt; "", &gt; }; &gt; if tokens.len() &gt; 1 { &gt; match name.as_str() { &gt;- "bundle-only" | &gt;- "end-of-candidates" | &gt;- "ice-lite" | &gt;- "ice-mismatch" | &gt;- "inactive" | &gt;- "recvonly" | &gt;- "rtcp-mux" | &gt;- "rtcp-rsize" | &gt;- "sendonly" | &gt;- "sendrecv" =&gt; { &gt;- return Err(SdpParserInternalError::Generic(format!("{} attribute is not allowed to have a value", &gt;- name))); &gt;+ "bundle-only" | "end-of-candidates" | "ice-lite" | "ice-mismatch" | "inactive" &gt;+ | "recvonly" | "rtcp-mux" | "rtcp-rsize" | "sendonly" | "sendrecv" =&gt; { &gt;+ return Err(SdpParserInternalError::Generic(format!( &gt;+ "{} attribute is not allowed to have a value", &gt;+ name &gt;+ ))); &gt; } &gt; _ =&gt; (), &gt; } &gt; } &gt; match name.as_str() { &gt; "bundle-only" =&gt; Ok(SdpAttribute::BundleOnly), &gt; "dtls-message" =&gt; parse_dtls_message(val), &gt; "end-of-candidates" =&gt; Ok(SdpAttribute::EndOfCandidates), &gt;@@ -751,17 +747,17 @@ impl FromStr for SdpAttribute { &gt; "imageattr" =&gt; parse_image_attr(val), &gt; "inactive" =&gt; Ok(SdpAttribute::Inactive), &gt; "label" =&gt; Ok(SdpAttribute::Label(string_or_empty(val)?)), &gt; "max-message-size" =&gt; Ok(SdpAttribute::MaxMessageSize(val.parse()?)), &gt; "maxptime" =&gt; Ok(SdpAttribute::MaxPtime(val.parse()?)), &gt; "mid" =&gt; Ok(SdpAttribute::Mid(string_or_empty(val)?)), &gt; "msid-semantic" =&gt; parse_msid_semantic(val), &gt; "ptime" =&gt; Ok(SdpAttribute::Ptime(val.parse()?)), &gt;- "rid" =&gt; parse_rid(val), &gt;+ "rid" =&gt; parse_rid(val), &gt; "recvonly" =&gt; Ok(SdpAttribute::Recvonly), &gt; "rtcp-mux" =&gt; Ok(SdpAttribute::RtcpMux), &gt; "rtcp-rsize" =&gt; Ok(SdpAttribute::RtcpRsize), &gt; "sendonly" =&gt; Ok(SdpAttribute::Sendonly), &gt; "sendrecv" =&gt; Ok(SdpAttribute::Sendrecv), &gt; "ssrc-group" =&gt; Ok(SdpAttribute::SsrcGroup(string_or_empty(val)?)), &gt; "sctp-port" =&gt; parse_sctp_port(val), &gt; "candidate" =&gt; parse_candidate(val), &gt;@@ -774,19 +770,20 @@ impl FromStr for SdpAttribute { &gt; "remote-candidates" =&gt; parse_remote_candidates(val), &gt; "rtpmap" =&gt; parse_rtpmap(val), &gt; "rtcp" =&gt; parse_rtcp(val), &gt; "rtcp-fb" =&gt; parse_rtcp_fb(val), &gt; "sctpmap" =&gt; parse_sctpmap(val), &gt; "setup" =&gt; parse_setup(val), &gt; "simulcast" =&gt; parse_simulcast(val), &gt; "ssrc" =&gt; parse_ssrc(val), &gt;- _ =&gt; { &gt;- Err(SdpParserInternalError::Unsupported(format!("Unknown attribute type {}", name))) &gt;- } &gt;+ _ =&gt; Err(SdpParserInternalError::Unsupported(format!( &gt;+ "Unknown attribute type {}", &gt;+ name &gt;+ ))), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Clone, PartialEq)] &gt; pub enum SdpAttributeType { &gt; BundleOnly, &gt; Candidate, &gt;@@ -827,138 +824,150 @@ pub enum SdpAttributeType { &gt; Simulcast, &gt; Ssrc, &gt; SsrcGroup, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttribute&gt; for SdpAttributeType { &gt; fn from(other: &amp;SdpAttribute) -&gt; Self { &gt; match *other { &gt;- SdpAttribute::BundleOnly{..} =&gt; SdpAttributeType::BundleOnly, &gt;- SdpAttribute::Candidate{..} =&gt; SdpAttributeType::Candidate, &gt;- SdpAttribute::DtlsMessage{..} =&gt; SdpAttributeType::DtlsMessage, &gt;- SdpAttribute::EndOfCandidates{..} =&gt; SdpAttributeType::EndOfCandidates, &gt;- SdpAttribute::Extmap{..} =&gt; SdpAttributeType::Extmap, &gt;- SdpAttribute::Fingerprint{..} =&gt; SdpAttributeType::Fingerprint, &gt;- SdpAttribute::Fmtp{..} =&gt; SdpAttributeType::Fmtp, &gt;- SdpAttribute::Group{..} =&gt; SdpAttributeType::Group, &gt;- SdpAttribute::IceLite{..} =&gt; SdpAttributeType::IceLite, &gt;- SdpAttribute::IceMismatch{..} =&gt; SdpAttributeType::IceMismatch, &gt;- SdpAttribute::IceOptions{..} =&gt; SdpAttributeType::IceOptions, &gt;- SdpAttribute::IcePwd{..} =&gt; SdpAttributeType::IcePwd, &gt;- SdpAttribute::IceUfrag{..} =&gt; SdpAttributeType::IceUfrag, &gt;- SdpAttribute::Identity{..} =&gt; SdpAttributeType::Identity, &gt;- SdpAttribute::ImageAttr{..} =&gt; SdpAttributeType::ImageAttr, &gt;- SdpAttribute::Inactive{..} =&gt; SdpAttributeType::Inactive, &gt;- SdpAttribute::Label{..} =&gt; SdpAttributeType::Label, &gt;- SdpAttribute::MaxMessageSize{..} =&gt; SdpAttributeType::MaxMessageSize, &gt;- SdpAttribute::MaxPtime{..} =&gt; SdpAttributeType::MaxPtime, &gt;- SdpAttribute::Mid{..} =&gt; SdpAttributeType::Mid, &gt;- SdpAttribute::Msid{..} =&gt; SdpAttributeType::Msid, &gt;- SdpAttribute::MsidSemantic{..} =&gt; SdpAttributeType::MsidSemantic, &gt;- SdpAttribute::Ptime{..} =&gt; SdpAttributeType::Ptime, &gt;- SdpAttribute::Rid{..} =&gt; SdpAttributeType::Rid, &gt;- SdpAttribute::Recvonly{..} =&gt; SdpAttributeType::Recvonly, &gt;- SdpAttribute::RemoteCandidate{..} =&gt; SdpAttributeType::RemoteCandidate, &gt;- SdpAttribute::Rtcp{..} =&gt; SdpAttributeType::Rtcp, &gt;- SdpAttribute::Rtcpfb{..} =&gt; SdpAttributeType::Rtcpfb, &gt;- SdpAttribute::RtcpMux{..} =&gt; SdpAttributeType::RtcpMux, &gt;- SdpAttribute::RtcpRsize{..} =&gt; SdpAttributeType::RtcpRsize, &gt;- SdpAttribute::Rtpmap{..} =&gt; SdpAttributeType::Rtpmap, &gt;- SdpAttribute::Sctpmap{..} =&gt; SdpAttributeType::Sctpmap, &gt;- SdpAttribute::SctpPort{..} =&gt; SdpAttributeType::SctpPort, &gt;- SdpAttribute::Sendonly{..} =&gt; SdpAttributeType::Sendonly, &gt;- SdpAttribute::Sendrecv{..} =&gt; SdpAttributeType::Sendrecv, &gt;- SdpAttribute::Setup{..} =&gt; SdpAttributeType::Setup, &gt;- SdpAttribute::Simulcast{..} =&gt; SdpAttributeType::Simulcast, &gt;- SdpAttribute::Ssrc{..} =&gt; SdpAttributeType::Ssrc, &gt;- SdpAttribute::SsrcGroup{..} =&gt; SdpAttributeType::SsrcGroup &gt;+ SdpAttribute::BundleOnly { .. } =&gt; SdpAttributeType::BundleOnly, &gt;+ SdpAttribute::Candidate { .. } =&gt; SdpAttributeType::Candidate, &gt;+ SdpAttribute::DtlsMessage { .. } =&gt; SdpAttributeType::DtlsMessage, &gt;+ SdpAttribute::EndOfCandidates { .. } =&gt; SdpAttributeType::EndOfCandidates, &gt;+ SdpAttribute::Extmap { .. } =&gt; SdpAttributeType::Extmap, &gt;+ SdpAttribute::Fingerprint { .. } =&gt; SdpAttributeType::Fingerprint, &gt;+ SdpAttribute::Fmtp { .. } =&gt; SdpAttributeType::Fmtp, &gt;+ SdpAttribute::Group { .. } =&gt; SdpAttributeType::Group, &gt;+ SdpAttribute::IceLite { .. } =&gt; SdpAttributeType::IceLite, &gt;+ SdpAttribute::IceMismatch { .. } =&gt; SdpAttributeType::IceMismatch, &gt;+ SdpAttribute::IceOptions { .. } =&gt; SdpAttributeType::IceOptions, &gt;+ SdpAttribute::IcePwd { .. } =&gt; SdpAttributeType::IcePwd, &gt;+ SdpAttribute::IceUfrag { .. } =&gt; SdpAttributeType::IceUfrag, &gt;+ SdpAttribute::Identity { .. } =&gt; SdpAttributeType::Identity, &gt;+ SdpAttribute::ImageAttr { .. } =&gt; SdpAttributeType::ImageAttr, &gt;+ SdpAttribute::Inactive { .. } =&gt; SdpAttributeType::Inactive, &gt;+ SdpAttribute::Label { .. } =&gt; SdpAttributeType::Label, &gt;+ SdpAttribute::MaxMessageSize { .. } =&gt; SdpAttributeType::MaxMessageSize, &gt;+ SdpAttribute::MaxPtime { .. } =&gt; SdpAttributeType::MaxPtime, &gt;+ SdpAttribute::Mid { .. } =&gt; SdpAttributeType::Mid, &gt;+ SdpAttribute::Msid { .. } =&gt; SdpAttributeType::Msid, &gt;+ SdpAttribute::MsidSemantic { .. } =&gt; SdpAttributeType::MsidSemantic, &gt;+ SdpAttribute::Ptime { .. } =&gt; SdpAttributeType::Ptime, &gt;+ SdpAttribute::Rid { .. } =&gt; SdpAttributeType::Rid, &gt;+ SdpAttribute::Recvonly { .. } =&gt; SdpAttributeType::Recvonly, &gt;+ SdpAttribute::RemoteCandidate { .. } =&gt; SdpAttributeType::RemoteCandidate, &gt;+ SdpAttribute::Rtcp { .. } =&gt; SdpAttributeType::Rtcp, &gt;+ SdpAttribute::Rtcpfb { .. } =&gt; SdpAttributeType::Rtcpfb, &gt;+ SdpAttribute::RtcpMux { .. } =&gt; SdpAttributeType::RtcpMux, &gt;+ SdpAttribute::RtcpRsize { .. } =&gt; SdpAttributeType::RtcpRsize, &gt;+ SdpAttribute::Rtpmap { .. } =&gt; SdpAttributeType::Rtpmap, &gt;+ SdpAttribute::Sctpmap { .. } =&gt; SdpAttributeType::Sctpmap, &gt;+ SdpAttribute::SctpPort { .. } =&gt; SdpAttributeType::SctpPort, &gt;+ SdpAttribute::Sendonly { .. } =&gt; SdpAttributeType::Sendonly, &gt;+ SdpAttribute::Sendrecv { .. } =&gt; SdpAttributeType::Sendrecv, &gt;+ SdpAttribute::Setup { .. } =&gt; SdpAttributeType::Setup, &gt;+ SdpAttribute::Simulcast { .. } =&gt; SdpAttributeType::Simulcast, &gt;+ SdpAttribute::Ssrc { .. } =&gt; SdpAttributeType::Ssrc, &gt;+ SdpAttribute::SsrcGroup { .. } =&gt; SdpAttributeType::SsrcGroup, &gt; } &gt; } &gt; } &gt; &gt;- &gt; fn string_or_empty(to_parse: &amp;str) -&gt; Result&lt;String, SdpParserInternalError&gt; { &gt; if to_parse.is_empty() { &gt;- Err(SdpParserInternalError::Generic("This attribute is required to have a value" &gt;- .to_string())) &gt;+ Err(SdpParserInternalError::Generic( &gt;+ "This attribute is required to have a value".to_string(), &gt;+ )) &gt; } else { &gt; Ok(to_parse.to_string()) &gt; } &gt; } &gt; &gt;-fn parse_payload_type(to_parse: &amp;str) -&gt; Result&lt;SdpAttributePayloadType, SdpParserInternalError&gt; &gt;-{ &gt;+fn parse_payload_type(to_parse: &amp;str) -&gt; Result&lt;SdpAttributePayloadType, SdpParserInternalError&gt; { &gt; Ok(match to_parse { &gt;- "*" =&gt; SdpAttributePayloadType::Wildcard, &gt;- _ =&gt; SdpAttributePayloadType::PayloadType(to_parse.parse::&lt;u8&gt;()?) &gt;- }) &gt;+ "*" =&gt; SdpAttributePayloadType::Wildcard, &gt;+ _ =&gt; SdpAttributePayloadType::PayloadType(to_parse.parse::&lt;u8&gt;()?), &gt;+ }) &gt; } &gt; &gt; fn parse_single_direction(to_parse: &amp;str) -&gt; Result&lt;SdpSingleDirection, SdpParserInternalError&gt; { &gt; match to_parse { &gt; "send" =&gt; Ok(SdpSingleDirection::Send), &gt; "recv" =&gt; Ok(SdpSingleDirection::Recv), &gt; x @ _ =&gt; Err(SdpParserInternalError::Generic( &gt;- format!("Unknown direction description found: '{:}'",x).to_string() &gt;- )) &gt;+ format!("Unknown direction description found: '{:}'", x).to_string(), &gt;+ )), &gt; } &gt; } &gt; &gt; fn parse_sctp_port(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let port = to_parse.parse()?; &gt; if port &gt; 65535 { &gt;- return Err(SdpParserInternalError::Generic(format!("Sctpport port {} can only be a bit 16bit number", &gt;- port))); &gt;+ return Err(SdpParserInternalError::Generic(format!( &gt;+ "Sctpport port {} can only be a bit 16bit number", &gt;+ port &gt;+ ))); &gt; } &gt; Ok(SdpAttribute::SctpPort(port)) &gt; } &gt; &gt; fn parse_candidate(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let tokens: Vec&lt;&amp;str&gt; = to_parse.split_whitespace().collect(); &gt; if tokens.len() &lt; 8 { &gt;- return Err(SdpParserInternalError::Generic("Candidate needs to have minimum eigth tokens" &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Candidate needs to have minimum eigth tokens".to_string(), &gt;+ )); &gt; } &gt; let component = tokens[1].parse::&lt;u32&gt;()?; &gt; let transport = match tokens[2].to_lowercase().as_ref() { &gt; "udp" =&gt; SdpAttributeCandidateTransport::Udp, &gt; "tcp" =&gt; SdpAttributeCandidateTransport::Tcp, &gt; _ =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Unknonw candidate transport value" &gt;- .to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Unknonw candidate transport value".to_string(), &gt;+ )) &gt; } &gt; }; &gt; let priority = tokens[3].parse::&lt;u64&gt;()?; &gt; let address = parse_unicast_addr(tokens[4])?; &gt; let port = tokens[5].parse::&lt;u32&gt;()?; &gt; if port &gt; 65535 { &gt;- return Err(SdpParserInternalError::Generic("ICE candidate port can only be a bit 16bit number".to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "ICE candidate port can only be a bit 16bit number".to_string(), &gt;+ )); &gt; } &gt; match tokens[6].to_lowercase().as_ref() { &gt; "typ" =&gt; (), &gt; _ =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Candidate attribute token must be 'typ'" &gt;- .to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Candidate attribute token must be 'typ'".to_string(), &gt;+ )) &gt; } &gt; }; &gt; let cand_type = match tokens[7].to_lowercase().as_ref() { &gt; "host" =&gt; SdpAttributeCandidateType::Host, &gt; "srflx" =&gt; SdpAttributeCandidateType::Srflx, &gt; "prflx" =&gt; SdpAttributeCandidateType::Prflx, &gt; "relay" =&gt; SdpAttributeCandidateType::Relay, &gt;- _ =&gt; return Err(SdpParserInternalError::Generic("Unknow candidate type value".to_string())), &gt;+ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Unknow candidate type value".to_string(), &gt;+ )) &gt;+ } &gt; }; &gt;- let mut cand = SdpAttributeCandidate::new(tokens[0].to_string(), &gt;- component, &gt;- transport, &gt;- priority, &gt;- address, &gt;- port, &gt;- cand_type); &gt;+ let mut cand = SdpAttributeCandidate::new( &gt;+ tokens[0].to_string(), &gt;+ component, &gt;+ transport, &gt;+ priority, &gt;+ address, &gt;+ port, &gt;+ cand_type, &gt;+ ); &gt; if tokens.len() &gt; 8 { &gt; let mut index = 8; &gt; while tokens.len() &gt; index + 1 { &gt; match tokens[index].to_lowercase().as_ref() { &gt; "generation" =&gt; { &gt; let generation = tokens[index + 1].parse::&lt;u32&gt;()?; &gt; cand.set_generation(generation); &gt; index += 2; &gt;@@ -971,183 +980,193 @@ fn parse_candidate(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalErro &gt; "raddr" =&gt; { &gt; let addr = parse_unicast_addr(tokens[index + 1])?; &gt; cand.set_remote_address(addr); &gt; index += 2; &gt; } &gt; "rport" =&gt; { &gt; let port = tokens[index + 1].parse::&lt;u32&gt;()?; &gt; if port &gt; 65535 { &gt;- return Err(SdpParserInternalError::Generic( "ICE candidate rport can only be a bit 16bit number".to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "ICE candidate rport can only be a bit 16bit number".to_string(), &gt;+ )); &gt; } &gt; cand.set_remote_port(port); &gt; index += 2; &gt; } &gt; "tcptype" =&gt; { &gt; cand.set_tcp_type(match tokens[index + 1].to_lowercase().as_ref() { &gt;- "active" =&gt; SdpAttributeCandidateTcpType::Active, &gt;- "passive" =&gt; SdpAttributeCandidateTcpType::Passive, &gt;- "so" =&gt; SdpAttributeCandidateTcpType::Simultaneous, &gt;- _ =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Unknown tcptype value in candidate line".to_string())) &gt;+ "active" =&gt; SdpAttributeCandidateTcpType::Active, &gt;+ "passive" =&gt; SdpAttributeCandidateTcpType::Passive, &gt;+ "so" =&gt; SdpAttributeCandidateTcpType::Simultaneous, &gt;+ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Unknown tcptype value in candidate line".to_string(), &gt;+ )) &gt; } &gt;- }); &gt;+ }); &gt; index += 2; &gt; } &gt; "ufrag" =&gt; { &gt; let ufrag = tokens[index + 1]; &gt; cand.set_ufrag(ufrag.to_string()); &gt; index += 2; &gt; } &gt; _ =&gt; { &gt;- return Err(SdpParserInternalError::Unsupported("Uknown candidate extension name" &gt;- .to_string())) &gt;+ return Err(SdpParserInternalError::Unsupported( &gt;+ "Uknown candidate extension name".to_string(), &gt;+ )) &gt; } &gt; }; &gt; } &gt; } &gt; Ok(SdpAttribute::Candidate(cand)) &gt; } &gt; &gt; fn parse_dtls_message(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt;- let tokens:Vec&lt;&amp;str&gt; = to_parse.split(" ").collect(); &gt;+ let tokens: Vec&lt;&amp;str&gt; = to_parse.split(" ").collect(); &gt; &gt; if tokens.len() != 2 { &gt; return Err(SdpParserInternalError::Generic( &gt;- "dtls-message must have a role token and a value token.".to_string() &gt;+ "dtls-message must have a role token and a value token.".to_string(), &gt; )); &gt; } &gt; &gt; Ok(SdpAttribute::DtlsMessage(match tokens[0] { &gt; "client" =&gt; SdpAttributeDtlsMessage::Client(tokens[1].to_string()), &gt; "server" =&gt; SdpAttributeDtlsMessage::Server(tokens[1].to_string()), &gt; e @ _ =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- format!("dtls-message has unknown role token '{}'",e).to_string() &gt;+ format!("dtls-message has unknown role token '{}'", e).to_string(), &gt; )); &gt; } &gt; })) &gt; } &gt; &gt; // ABNF for extmap is defined in RFC 5285 &gt; // https://tools.ietf.org/html/rfc5285#section-7 &gt; fn parse_extmap(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let tokens: Vec&lt;&amp;str&gt; = to_parse.split_whitespace().collect(); &gt; if tokens.len() &lt; 2 { &gt;- return Err(SdpParserInternalError::Generic("Extmap needs to have at least two tokens" &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Extmap needs to have at least two tokens".to_string(), &gt;+ )); &gt; } &gt; let id: u16; &gt; let mut direction: Option&lt;SdpAttributeDirection&gt; = None; &gt; if tokens[0].find('/') == None { &gt; id = tokens[0].parse::&lt;u16&gt;()?; &gt; } else { &gt; let id_dir: Vec&lt;&amp;str&gt; = tokens[0].splitn(2, '/').collect(); &gt; id = id_dir[0].parse::&lt;u16&gt;()?; &gt; direction = Some(match id_dir[1].to_lowercase().as_ref() { &gt;- "recvonly" =&gt; SdpAttributeDirection::Recvonly, &gt;- "sendonly" =&gt; SdpAttributeDirection::Sendonly, &gt;- "sendrecv" =&gt; SdpAttributeDirection::Sendrecv, &gt;- _ =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Unsupported direction in extmap value".to_string())) &gt;- } &gt;- }) &gt;+ "recvonly" =&gt; SdpAttributeDirection::Recvonly, &gt;+ "sendonly" =&gt; SdpAttributeDirection::Sendonly, &gt;+ "sendrecv" =&gt; SdpAttributeDirection::Sendrecv, &gt;+ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Unsupported direction in extmap value".to_string(), &gt;+ )) &gt;+ } &gt;+ }) &gt; } &gt; // Consider replacing to_parse.split_whitespace() above with splitn on space. Would we want the pattern to split on any amout of any kind of whitespace? &gt; let extension_attributes = if tokens.len() == 2 { &gt; None &gt; } else { &gt; let ext_string: String = tokens[2..].join(" "); &gt; if !valid_byte_string(&amp;ext_string) { &gt;- return Err(SdpParserInternalError::Generic("Illegal character in extmap extension attributes".to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Illegal character in extmap extension attributes".to_string(), &gt;+ )); &gt; } &gt; Some(ext_string) &gt; }; &gt; Ok(SdpAttribute::Extmap(SdpAttributeExtmap { &gt;- id, &gt;- direction, &gt;- url: tokens[1].to_string(), &gt;- extension_attributes: extension_attributes, &gt;- })) &gt;+ id, &gt;+ direction, &gt;+ url: tokens[1].to_string(), &gt;+ extension_attributes: extension_attributes, &gt;+ })) &gt; } &gt; &gt; fn parse_fingerprint(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let tokens: Vec&lt;&amp;str&gt; = to_parse.split_whitespace().collect(); &gt; if tokens.len() != 2 { &gt;- return Err(SdpParserInternalError::Generic("Fingerprint needs to have two tokens" &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Fingerprint needs to have two tokens".to_string(), &gt;+ )); &gt; } &gt; &gt; let fingerprint_token = tokens[1].to_string(); &gt;- let parse_tokens = |expected_len| -&gt; Result&lt;Vec&lt;u8&gt;, SdpParserInternalError&gt;{ &gt;- let bytes = fingerprint_token.split(":") &gt;- .map(|byte_token| { &gt;- if byte_token.len() != 2 { &gt;- return Err(SdpParserInternalError::Generic( &gt;- "fingerpint's byte tokens must have 2 hexdigits" &gt;- .to_string() &gt;- )) &gt;- } &gt;- Ok(u8::from_str_radix(byte_token, 16)?) &gt;- }) &gt;- .collect::&lt;Result&lt;Vec&lt;u8&gt;,_&gt;&gt;()?; &gt;+ let parse_tokens = |expected_len| -&gt; Result&lt;Vec&lt;u8&gt;, SdpParserInternalError&gt; { &gt;+ let bytes = fingerprint_token &gt;+ .split(":") &gt;+ .map(|byte_token| { &gt;+ if byte_token.len() != 2 { &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "fingerpint's byte tokens must have 2 hexdigits".to_string(), &gt;+ )); &gt;+ } &gt;+ Ok(u8::from_str_radix(byte_token, 16)?) &gt;+ }).collect::&lt;Result&lt;Vec&lt;u8&gt;, _&gt;&gt;()?; &gt; &gt; if bytes.len() != expected_len { &gt;- return Err(SdpParserInternalError::Generic( &gt;- format!("fingerprint has {} bytes but should have {} bytes", &gt;- bytes.len(), expected_len) &gt;- )) &gt;+ return Err(SdpParserInternalError::Generic(format!( &gt;+ "fingerprint has {} bytes but should have {} bytes", &gt;+ bytes.len(), &gt;+ expected_len &gt;+ ))); &gt; } &gt; &gt; Ok(bytes) &gt; }; &gt; &gt;- &gt; let hash_algorithm = match tokens[0] { &gt; "sha-1" =&gt; SdpAttributeFingerprintHashType::Sha1, &gt; "sha-224" =&gt; SdpAttributeFingerprintHashType::Sha224, &gt; "sha-256" =&gt; SdpAttributeFingerprintHashType::Sha256, &gt; "sha-384" =&gt; SdpAttributeFingerprintHashType::Sha384, &gt; "sha-512" =&gt; SdpAttributeFingerprintHashType::Sha512, &gt; unknown =&gt; { &gt;- return Err(SdpParserInternalError::Unsupported( &gt;- format!("fingerprint contains an unsupported hash algorithm '{}'", unknown) &gt;- )) &gt;+ return Err(SdpParserInternalError::Unsupported(format!( &gt;+ "fingerprint contains an unsupported hash algorithm '{}'", &gt;+ unknown &gt;+ ))) &gt; } &gt; }; &gt; &gt; let fingerprint = match hash_algorithm { &gt; SdpAttributeFingerprintHashType::Sha1 =&gt; parse_tokens(20)?, &gt; SdpAttributeFingerprintHashType::Sha224 =&gt; parse_tokens(28)?, &gt; SdpAttributeFingerprintHashType::Sha256 =&gt; parse_tokens(32)?, &gt; SdpAttributeFingerprintHashType::Sha384 =&gt; parse_tokens(48)?, &gt; SdpAttributeFingerprintHashType::Sha512 =&gt; parse_tokens(64)?, &gt; }; &gt; &gt; Ok(SdpAttribute::Fingerprint(SdpAttributeFingerprint { &gt;- hash_algorithm, &gt;- fingerprint, &gt;- })) &gt;+ hash_algorithm, &gt;+ fingerprint, &gt;+ })) &gt; } &gt; &gt; fn parse_fmtp(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt;- let tokens: Vec&lt;&amp;str&gt; = to_parse.splitn(2," ").collect(); &gt;+ let tokens: Vec&lt;&amp;str&gt; = to_parse.splitn(2, " ").collect(); &gt; &gt; if tokens.len() != 2 { &gt; return Err(SdpParserInternalError::Unsupported( &gt;- "Fmtp attributes require a payload type and a parameter block.".to_string() &gt;+ "Fmtp attributes require a payload type and a parameter block.".to_string(), &gt; )); &gt; } &gt; &gt; let payload_token = tokens[0]; &gt; let parameter_token = tokens[1]; &gt; &gt;- &gt; // Default initiliaze SdpAttributeFmtpParameters &gt;- let mut parameters = SdpAttributeFmtpParameters{ &gt;+ let mut parameters = SdpAttributeFmtpParameters { &gt; packetization_mode: 0, &gt; level_asymmetry_allowed: false, &gt; profile_level_id: 0x420010, &gt; max_fs: 0, &gt; max_cpb: 0, &gt; max_dpb: 0, &gt; max_br: 0, &gt; max_mbps: 0, &gt;@@ -1161,198 +1180,214 @@ fn parse_fmtp(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; dtmf_tones: "".to_string(), &gt; unknown_tokens: Vec::new(), &gt; }; &gt; &gt; if parameter_token.contains("=") { &gt; let parameter_tokens: Vec&lt;&amp;str&gt; = parameter_token.split(";").collect(); &gt; &gt; for parameter_token in parameter_tokens.iter() { &gt;- let name_value_pair: Vec&lt;&amp;str&gt; = parameter_token.splitn(2,"=").collect(); &gt;+ let name_value_pair: Vec&lt;&amp;str&gt; = parameter_token.splitn(2, "=").collect(); &gt; &gt; if name_value_pair.len() != 2 { &gt; return Err(SdpParserInternalError::Generic( &gt; "A fmtp parameter must be either a telephone event, a parameter list or &gt;- a red codec list".to_string() &gt;- )) &gt;+ a red codec list" &gt;+ .to_string(), &gt;+ )); &gt; } &gt; &gt;- let parse_bool = |val: &amp;str, param_name: &amp;str| -&gt; Result&lt;bool,SdpParserInternalError&gt; { &gt;- match val.parse::&lt;u8&gt;()? { &gt;- 0 =&gt; Ok(false), &gt;- 1 =&gt; Ok(true), &gt;- _ =&gt; return Err(SdpParserInternalError::Generic( &gt;- format!("The fmtp parameter '{:}' must be 0 or 1", param_name) &gt;- .to_string() &gt;- )) &gt;- } &gt;- }; &gt;+ let parse_bool = &gt;+ |val: &amp;str, param_name: &amp;str| -&gt; Result&lt;bool, SdpParserInternalError&gt; { &gt;+ match val.parse::&lt;u8&gt;()? { &gt;+ 0 =&gt; Ok(false), &gt;+ 1 =&gt; Ok(true), &gt;+ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ format!("The fmtp parameter '{:}' must be 0 or 1", param_name) &gt;+ .to_string(), &gt;+ )) &gt;+ } &gt;+ } &gt;+ }; &gt; &gt; let parameter_name = name_value_pair[0]; &gt; let parameter_val = name_value_pair[1]; &gt; &gt; match parameter_name.to_uppercase().as_str() { &gt; // H264 &gt;- "PROFILE-LEVEL-ID" =&gt; parameters.profile_level_id = &gt;- match u32::from_str_radix(parameter_val,16)? { &gt;- x @ 0 ... 0xffffff =&gt; x, &gt;- _ =&gt; return Err(SdpParserInternalError::Generic( &gt;- "The fmtp parameter 'profile-level-id' must be in range [0,0xffffff]" &gt;- .to_string() &gt;- )) &gt;- }, &gt;- "PACKETIZATION-MODE" =&gt; parameters.packetization_mode = &gt;- match parameter_val.parse::&lt;u32&gt;()? { &gt;- x @ 0...2 =&gt; x, &gt;- _ =&gt; return Err(SdpParserInternalError::Generic( &gt;- "The fmtp parameter 'packetization-mode' must be 0,1 or 2" &gt;- .to_string() &gt;- )) &gt;- }, &gt;- "LEVEL-ASYMMETRY-ALLOWED" =&gt; parameters.level_asymmetry_allowed = &gt;- parse_bool(parameter_val,"level-asymmetry-allowed")?, &gt;+ "PROFILE-LEVEL-ID" =&gt; { &gt;+ parameters.profile_level_id = match u32::from_str_radix(parameter_val, 16)? { &gt;+ x @ 0...0xffffff =&gt; x, &gt;+ _ =&gt; return Err(SdpParserInternalError::Generic( &gt;+ "The fmtp parameter 'profile-level-id' must be in range [0,0xffffff]" &gt;+ .to_string(), &gt;+ )), &gt;+ } &gt;+ } &gt;+ "PACKETIZATION-MODE" =&gt; { &gt;+ parameters.packetization_mode = match parameter_val.parse::&lt;u32&gt;()? { &gt;+ x @ 0...2 =&gt; x, &gt;+ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "The fmtp parameter 'packetization-mode' must be 0,1 or 2" &gt;+ .to_string(), &gt;+ )) &gt;+ } &gt;+ } &gt;+ } &gt;+ "LEVEL-ASYMMETRY-ALLOWED" =&gt; { &gt;+ parameters.level_asymmetry_allowed = &gt;+ parse_bool(parameter_val, "level-asymmetry-allowed")? &gt;+ } &gt; "MAX-MBPS" =&gt; parameters.max_mbps = parameter_val.parse::&lt;u32&gt;()?, &gt; "MAX-FS" =&gt; parameters.max_fs = parameter_val.parse::&lt;u32&gt;()?, &gt; "MAX-CPB" =&gt; parameters.max_cpb = parameter_val.parse::&lt;u32&gt;()?, &gt; "MAX-DPB" =&gt; parameters.max_dpb = parameter_val.parse::&lt;u32&gt;()?, &gt; "MAX-BR" =&gt; parameters.max_br = parameter_val.parse::&lt;u32&gt;()?, &gt; &gt; // VP8 and VP9 &gt; "MAX-FR" =&gt; parameters.max_fr = parameter_val.parse::&lt;u32&gt;()?, &gt; &gt; //Opus &gt; "MAXPLAYBACKRATE" =&gt; parameters.maxplaybackrate = parameter_val.parse::&lt;u32&gt;()?, &gt;- "USEDTX" =&gt; parameters.usedtx = parse_bool(parameter_val,"usedtx")?, &gt;- "STEREO" =&gt; parameters.stereo = parse_bool(parameter_val,"stereo")?, &gt;- "USEINBANDFEC" =&gt; parameters.useinbandfec = &gt;- parse_bool(parameter_val,"useinbandfec")?, &gt;- "CBR" =&gt; parameters.cbr = parse_bool(parameter_val,"cbr")?, &gt;- _ =&gt; { &gt;- parameters.unknown_tokens.push(parameter_token.to_string()) &gt;+ "USEDTX" =&gt; parameters.usedtx = parse_bool(parameter_val, "usedtx")?, &gt;+ "STEREO" =&gt; parameters.stereo = parse_bool(parameter_val, "stereo")?, &gt;+ "USEINBANDFEC" =&gt; { &gt;+ parameters.useinbandfec = parse_bool(parameter_val, "useinbandfec")? &gt; } &gt;+ "CBR" =&gt; parameters.cbr = parse_bool(parameter_val, "cbr")?, &gt;+ _ =&gt; parameters.unknown_tokens.push(parameter_token.to_string()), &gt; } &gt; } &gt; } else { &gt; if parameter_token.contains("/") { &gt; let encodings: Vec&lt;&amp;str&gt; = parameter_token.split("/").collect(); &gt; &gt; for encoding in encodings { &gt; match encoding.parse::&lt;u8&gt;()? { &gt; x @ 0...128 =&gt; parameters.encodings.push(x), &gt;- _ =&gt; return Err(SdpParserInternalError::Generic( &gt;- "Red codec must be in range [0,128]".to_string() &gt;- )) &gt;+ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Red codec must be in range [0,128]".to_string(), &gt;+ )) &gt;+ } &gt; } &gt; } &gt;- } else { // This is the case for the 'telephone-event' codec &gt;+ } else { &gt;+ // This is the case for the 'telephone-event' codec &gt; let dtmf_tones: Vec&lt;&amp;str&gt; = parameter_token.split(",").collect(); &gt; let mut dtmf_tone_is_ok = true; &gt; &gt; // This closure verifies the output of some_number_as_string.parse::&lt;u8&gt;().ok() like calls &gt;- let validate_digits = |digit_option: Option&lt;u8&gt; | -&gt; Option&lt;u8&gt; { &gt;- match digit_option{ &gt;+ let validate_digits = |digit_option: Option&lt;u8&gt;| -&gt; Option&lt;u8&gt; { &gt;+ match digit_option { &gt; Some(x) =&gt; match x { &gt; 0...100 =&gt; Some(x), &gt; _ =&gt; None, &gt; }, &gt; None =&gt; None, &gt; } &gt; }; &gt; &gt; // This loop does some sanity checking on the passed dtmf tones &gt; for dtmf_tone in dtmf_tones { &gt;- let dtmf_tone_range: Vec&lt;&amp;str&gt; = dtmf_tone.splitn(2,"-").collect(); &gt;+ let dtmf_tone_range: Vec&lt;&amp;str&gt; = dtmf_tone.splitn(2, "-").collect(); &gt; &gt; dtmf_tone_is_ok = match dtmf_tone_range.len() { &gt; // In this case the dtmf tone is a range &gt; 2 =&gt; { &gt; match validate_digits(dtmf_tone_range[0].parse::&lt;u8&gt;().ok()) { &gt;- Some(l) =&gt; match validate_digits(dtmf_tone_range[1].parse::&lt;u8&gt;().ok()) { &gt;+ Some(l) =&gt; match validate_digits(dtmf_tone_range[1].parse::&lt;u8&gt;().ok()) &gt;+ { &gt; Some(u) =&gt; { &gt; // Check that the first part of the range is smaller than the second part &gt; l &lt; u &gt;- }, &gt;- None =&gt; false &gt;+ } &gt;+ None =&gt; false, &gt; }, &gt; None =&gt; false, &gt; } &gt;- }, &gt;- // In this case the dtmf tone is a single tone &gt;+ } &gt;+ // In this case the dtmf tone is a single tone &gt; 1 =&gt; validate_digits(dtmf_tone.parse::&lt;u8&gt;().ok()).is_some(), &gt;- _ =&gt; false &gt;+ _ =&gt; false, &gt; }; &gt; &gt; if !dtmf_tone_is_ok { &gt;- break ; &gt;+ break; &gt; } &gt; } &gt; &gt; // Set the parsed dtmf tones or in case the parsing was insuccessfull, set it to the default "0-15" &gt;- parameters.dtmf_tones = match dtmf_tone_is_ok{ &gt;+ parameters.dtmf_tones = match dtmf_tone_is_ok { &gt; true =&gt; parameter_token.to_string(), &gt;- false =&gt; "0-15".to_string() &gt;+ false =&gt; "0-15".to_string(), &gt; } &gt; } &gt; } &gt; &gt; Ok(SdpAttribute::Fmtp(SdpAttributeFmtp { &gt;- payload_type: payload_token.parse::&lt;u8&gt;()?, &gt;- parameters: parameters, &gt;- })) &gt;+ payload_type: payload_token.parse::&lt;u8&gt;()?, &gt;+ parameters: parameters, &gt;+ })) &gt; } &gt; &gt; fn parse_group(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let mut tokens = to_parse.split_whitespace(); &gt; let semantics = match tokens.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Group attribute is missing semantics token" &gt;- .to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Group attribute is missing semantics token".to_string(), &gt;+ )) &gt; } &gt;- Some(x) =&gt; { &gt;- match x.to_uppercase().as_ref() { &gt;- "LS" =&gt; SdpAttributeGroupSemantic::LipSynchronization, &gt;- "FID" =&gt; SdpAttributeGroupSemantic::FlowIdentification, &gt;- "SRF" =&gt; SdpAttributeGroupSemantic::SingleReservationFlow, &gt;- "ANAT" =&gt; SdpAttributeGroupSemantic::AlternateNetworkAddressType, &gt;- "FEC" =&gt; SdpAttributeGroupSemantic::ForwardErrorCorrection, &gt;- "DDP" =&gt; SdpAttributeGroupSemantic::DecodingDependency, &gt;- "BUNDLE" =&gt; SdpAttributeGroupSemantic::Bundle, &gt;- unknown @ _ =&gt; { &gt;- return Err(SdpParserInternalError::Unsupported( &gt;- format!("Unknown group semantic '{:?}' found", unknown) &gt;- )) &gt;- } &gt;+ Some(x) =&gt; match x.to_uppercase().as_ref() { &gt;+ "LS" =&gt; SdpAttributeGroupSemantic::LipSynchronization, &gt;+ "FID" =&gt; SdpAttributeGroupSemantic::FlowIdentification, &gt;+ "SRF" =&gt; SdpAttributeGroupSemantic::SingleReservationFlow, &gt;+ "ANAT" =&gt; SdpAttributeGroupSemantic::AlternateNetworkAddressType, &gt;+ "FEC" =&gt; SdpAttributeGroupSemantic::ForwardErrorCorrection, &gt;+ "DDP" =&gt; SdpAttributeGroupSemantic::DecodingDependency, &gt;+ "BUNDLE" =&gt; SdpAttributeGroupSemantic::Bundle, &gt;+ unknown @ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Unsupported(format!( &gt;+ "Unknown group semantic '{:?}' found", &gt;+ unknown &gt;+ ))) &gt; } &gt;- } &gt;+ }, &gt; }; &gt; Ok(SdpAttribute::Group(SdpAttributeGroup { &gt;- semantics, &gt;- tags: tokens.map(|x| x.to_string()).collect(), &gt;- })) &gt;+ semantics, &gt;+ tags: tokens.map(|x| x.to_string()).collect(), &gt;+ })) &gt; } &gt; &gt; fn parse_ice_options(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; if to_parse.is_empty() { &gt;- return Err(SdpParserInternalError::Generic("ice-options is required to have a value" &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "ice-options is required to have a value".to_string(), &gt;+ )); &gt; } &gt;- Ok(SdpAttribute::IceOptions(to_parse.split_whitespace().map(|x| x.to_string()).collect())) &gt;+ Ok(SdpAttribute::IceOptions( &gt;+ to_parse.split_whitespace().map(|x| x.to_string()).collect(), &gt;+ )) &gt; } &gt; &gt; fn parse_imageattr_tokens(to_parse: &amp;str, separator: char) -&gt; Vec&lt;String&gt; { &gt; let mut tokens = Vec::new(); &gt; let mut open_braces_counter = 0; &gt; let mut current_tokens = Vec::new(); &gt; &gt; for token in to_parse.split(separator) { &gt; if token.contains("[") { &gt;- open_braces_counter+=1; &gt;+ open_braces_counter += 1; &gt; } &gt; if token.contains("]") { &gt;- open_braces_counter-=1; &gt;+ open_braces_counter -= 1; &gt; } &gt; &gt; current_tokens.push(token.to_string()); &gt; &gt; if open_braces_counter == 0 { &gt; tokens.push(current_tokens.join(&amp;separator.to_string())); &gt; current_tokens = Vec::new(); &gt; } &gt;@@ -1361,209 +1396,213 @@ fn parse_imageattr_tokens(to_parse: &amp;str, separator: char) -&gt; Vec&lt;String&gt; { &gt; tokens &gt; } &gt; &gt; fn parse_imagettr_braced_token(to_parse: &amp;str) -&gt; Option&lt;&amp;str&gt; { &gt; if !to_parse.ends_with("]") { &gt; return None; &gt; } &gt; &gt;- Some(&amp;to_parse[1..to_parse.len()-1]) &gt;+ Some(&amp;to_parse[1..to_parse.len() - 1]) &gt; } &gt; &gt;-fn parse_image_attr_xyrange(to_parse: &amp;str) -&gt; Result&lt;SdpAttributeImageAttrXYRange, &gt;- SdpParserInternalError&gt; { &gt;+fn parse_image_attr_xyrange( &gt;+ to_parse: &amp;str, &gt;+) -&gt; Result&lt;SdpAttributeImageAttrXYRange, SdpParserInternalError&gt; { &gt; if to_parse.starts_with("[") { &gt;- let value_tokens = parse_imagettr_braced_token(to_parse).ok_or( &gt;- SdpParserInternalError::Generic( &gt;- "imageattr's xyrange has no closing tag ']'".to_string() &gt;- ) &gt;- )?; &gt;+ let value_tokens = &gt;+ parse_imagettr_braced_token(to_parse).ok_or(SdpParserInternalError::Generic( &gt;+ "imageattr's xyrange has no closing tag ']'".to_string(), &gt;+ ))?; &gt; &gt; if to_parse.contains(":") { &gt; // Range values &gt;- let range_tokens:Vec&lt;&amp;str&gt; = value_tokens.split(":").collect(); &gt;+ let range_tokens: Vec&lt;&amp;str&gt; = value_tokens.split(":").collect(); &gt; &gt; if range_tokens.len() == 3 { &gt; Ok(SdpAttributeImageAttrXYRange::Range( &gt; range_tokens[0].parse::&lt;u32&gt;()?, &gt; range_tokens[2].parse::&lt;u32&gt;()?, &gt; Some(range_tokens[1].parse::&lt;u32&gt;()?), &gt; )) &gt; } else if range_tokens.len() == 2 { &gt; Ok(SdpAttributeImageAttrXYRange::Range( &gt; range_tokens[0].parse::&lt;u32&gt;()?, &gt; range_tokens[1].parse::&lt;u32&gt;()?, &gt;- None &gt;+ None, &gt; )) &gt; } else { &gt; return Err(SdpParserInternalError::Generic( &gt;- "imageattr's xyrange must contain 2 or 3 fields".to_string() &gt;- )) &gt;+ "imageattr's xyrange must contain 2 or 3 fields".to_string(), &gt;+ )); &gt; } &gt; } else { &gt; // Discrete values &gt;- let values = value_tokens.split(",") &gt;- .map(|x| x.parse::&lt;u32&gt;()) &gt;- .collect::&lt;Result&lt;Vec&lt;u32&gt;, _&gt;&gt;()?; &gt;+ let values = value_tokens &gt;+ .split(",") &gt;+ .map(|x| x.parse::&lt;u32&gt;()) &gt;+ .collect::&lt;Result&lt;Vec&lt;u32&gt;, _&gt;&gt;()?; &gt; &gt; if values.len() &lt; 2 { &gt; return Err(SdpParserInternalError::Generic( &gt;- "imageattr's discrete value list must have at least two elements".to_string() &gt;- )) &gt;+ "imageattr's discrete value list must have at least two elements".to_string(), &gt;+ )); &gt; } &gt; &gt; Ok(SdpAttributeImageAttrXYRange::DiscreteValues(values)) &gt; } &gt;- &gt; } else { &gt;- Ok(SdpAttributeImageAttrXYRange::DiscreteValues(vec![to_parse.parse::&lt;u32&gt;()?])) &gt;+ Ok(SdpAttributeImageAttrXYRange::DiscreteValues(vec![ &gt;+ to_parse.parse::&lt;u32&gt;()?, &gt;+ ])) &gt; } &gt; } &gt; &gt;-fn parse_image_attr_set(to_parse: &amp;str) -&gt; Result&lt;SdpAttributeImageAttrSet, &gt;- SdpParserInternalError&gt; { &gt;+fn parse_image_attr_set( &gt;+ to_parse: &amp;str, &gt;+) -&gt; Result&lt;SdpAttributeImageAttrSet, SdpParserInternalError&gt; { &gt; let mut tokens = parse_imageattr_tokens(to_parse, ',').into_iter(); &gt; &gt; let x_token = tokens.next().ok_or(SdpParserInternalError::Generic( &gt;- "imageattr set is missing the 'x=' token".to_string() &gt;+ "imageattr set is missing the 'x=' token".to_string(), &gt; ))?; &gt; if !x_token.starts_with("x=") { &gt; return Err(SdpParserInternalError::Generic( &gt;- "The first token in an imageattr set must begin with 'x='".to_string() &gt;- )) &gt;+ "The first token in an imageattr set must begin with 'x='".to_string(), &gt;+ )); &gt; } &gt; let x = parse_image_attr_xyrange(&amp;x_token[2..])?; &gt; &gt;- &gt; let y_token = tokens.next().ok_or(SdpParserInternalError::Generic( &gt;- "imageattr set is missing the 'y=' token".to_string() &gt;+ "imageattr set is missing the 'y=' token".to_string(), &gt; ))?; &gt; if !y_token.starts_with("y=") { &gt; return Err(SdpParserInternalError::Generic( &gt;- "The second token in an imageattr set must begin with 'y='".to_string() &gt;- )) &gt;+ "The second token in an imageattr set must begin with 'y='".to_string(), &gt;+ )); &gt; } &gt; let y = parse_image_attr_xyrange(&amp;y_token[2..])?; &gt; &gt; let mut sar = None; &gt; let mut par = None; &gt; let mut q = None; &gt; &gt; let parse_ps_range = |resolution_range: &amp;str| -&gt; Result&lt;(f32, f32), SdpParserInternalError&gt; { &gt;- let minmax_pair:Vec&lt;&amp;str&gt; = resolution_range.split("-").collect(); &gt;+ let minmax_pair: Vec&lt;&amp;str&gt; = resolution_range.split("-").collect(); &gt; &gt; if minmax_pair.len() != 2 { &gt; return Err(SdpParserInternalError::Generic( &gt;- "imageattr's par and sar ranges must have two components".to_string() &gt;- )) &gt;+ "imageattr's par and sar ranges must have two components".to_string(), &gt;+ )); &gt; } &gt; &gt; let min = minmax_pair[0].parse::&lt;f32&gt;()?; &gt; let max = minmax_pair[1].parse::&lt;f32&gt;()?; &gt; &gt; if min &gt;= max { &gt; return Err(SdpParserInternalError::Generic( &gt;- "In imageattr's par and sar ranges, first must be &lt; than the second".to_string() &gt;- )) &gt;+ "In imageattr's par and sar ranges, first must be &lt; than the second".to_string(), &gt;+ )); &gt; } &gt; &gt;- Ok((min,max)) &gt;+ Ok((min, max)) &gt; }; &gt; &gt; while let Some(current_token) = tokens.next() { &gt; if current_token.starts_with("sar=") { &gt; let value_token = &amp;current_token[4..]; &gt; if value_token.starts_with("[") { &gt; let sar_values = parse_imagettr_braced_token(value_token).ok_or( &gt; SdpParserInternalError::Generic( &gt;- "imageattr's sar value is missing closing tag ']'".to_string() &gt;- ) &gt;+ "imageattr's sar value is missing closing tag ']'".to_string(), &gt;+ ), &gt; )?; &gt; &gt; if value_token.contains("-") { &gt; // Range &gt; let range = parse_ps_range(sar_values)?; &gt;- sar = Some(SdpAttributeImageAttrSRange::Range(range.0,range.1)) &gt;+ sar = Some(SdpAttributeImageAttrSRange::Range(range.0, range.1)) &gt; } else if value_token.contains(",") { &gt; // Discrete values &gt;- let values = sar_values.split(",") &gt;- .map(|x| x.parse::&lt;f32&gt;()) &gt;- .collect::&lt;Result&lt;Vec&lt;f32&gt;, _&gt;&gt;()?; &gt;+ let values = sar_values &gt;+ .split(",") &gt;+ .map(|x| x.parse::&lt;f32&gt;()) &gt;+ .collect::&lt;Result&lt;Vec&lt;f32&gt;, _&gt;&gt;()?; &gt; &gt; if values.len() &lt; 2 { &gt; return Err(SdpParserInternalError::Generic( &gt; "imageattr's sar discrete value list must have at least two values" &gt;- .to_string() &gt;- )) &gt;+ .to_string(), &gt;+ )); &gt; } &gt; &gt; // Check that all the values are ascending &gt; let mut last_value = 0.0; &gt; for value in &amp;values { &gt; if last_value &gt;= *value { &gt; return Err(SdpParserInternalError::Generic( &gt; "imageattr's sar discrete value list must contain ascending values" &gt;- .to_string() &gt;- )) &gt;+ .to_string(), &gt;+ )); &gt; } &gt; last_value = *value; &gt; } &gt; sar = Some(SdpAttributeImageAttrSRange::DiscreteValues(values)) &gt; } &gt; } else { &gt;- sar = Some(SdpAttributeImageAttrSRange::DiscreteValues( &gt;- vec![value_token.parse::&lt;f32&gt;()?]) &gt;- ) &gt;+ sar = Some(SdpAttributeImageAttrSRange::DiscreteValues(vec![ &gt;+ value_token.parse::&lt;f32&gt;()?, &gt;+ ])) &gt; } &gt; } else if current_token.starts_with("par=") { &gt; let braced_value_token = &amp;current_token[4..]; &gt; if !braced_value_token.starts_with("[") { &gt; return Err(SdpParserInternalError::Generic( &gt;- "imageattr's par value must start with '['".to_string() &gt;- )) &gt;+ "imageattr's par value must start with '['".to_string(), &gt;+ )); &gt; } &gt; &gt; let par_values = parse_imagettr_braced_token(braced_value_token).ok_or( &gt; SdpParserInternalError::Generic( &gt;- "imageattr's par value must be enclosed with ']'".to_string() &gt;- ) &gt;+ "imageattr's par value must be enclosed with ']'".to_string(), &gt;+ ), &gt; )?; &gt; let range = parse_ps_range(par_values)?; &gt; par = Some(SdpAttributeImageAttrPRange { &gt; min: range.0, &gt; max: range.1, &gt; }) &gt; } else if current_token.starts_with("q=") { &gt; q = Some(current_token[2..].parse::&lt;f32&gt;()?); &gt; } &gt; } &gt; &gt;- Ok(SdpAttributeImageAttrSet { &gt;- x, &gt;- y, &gt;- sar, &gt;- par, &gt;- q &gt;- }) &gt;+ Ok(SdpAttributeImageAttrSet { x, y, sar, par, q }) &gt; } &gt; &gt;-fn parse_image_attr_set_list&lt;I&gt;(tokens: &amp;mut iter::Peekable&lt;I&gt;) &gt;- -&gt; Result&lt;SdpAttributeImageAttrSetList, SdpParserInternalError&gt; &gt;- where I: Iterator&lt;Item = String&gt; + Clone { &gt;- let parse_set = |set_token:&amp;str| -&gt; Result&lt;SdpAttributeImageAttrSet, SdpParserInternalError&gt; { &gt;- Ok(parse_image_attr_set(parse_imagettr_braced_token(set_token).ok_or( &gt;- SdpParserInternalError::Generic( &gt;- "imageattr sets must be enclosed by ']'".to_string() &gt;- ))?)?) &gt;+fn parse_image_attr_set_list&lt;I&gt;( &gt;+ tokens: &amp;mut iter::Peekable&lt;I&gt;, &gt;+) -&gt; Result&lt;SdpAttributeImageAttrSetList, SdpParserInternalError&gt; &gt;+where &gt;+ I: Iterator&lt;Item = String&gt; + Clone, &gt;+{ &gt;+ let parse_set = |set_token: &amp;str| -&gt; Result&lt;SdpAttributeImageAttrSet, SdpParserInternalError&gt; { &gt;+ Ok(parse_image_attr_set( &gt;+ parse_imagettr_braced_token(set_token).ok_or(SdpParserInternalError::Generic( &gt;+ "imageattr sets must be enclosed by ']'".to_string(), &gt;+ ))?, &gt;+ )?) &gt; }; &gt; &gt;- match tokens.next().ok_or(SdpParserInternalError::Generic( &gt;- "imageattr must have a parameter set after a direction token".to_string() &gt;- ))?.as_str() { &gt;+ match tokens &gt;+ .next() &gt;+ .ok_or(SdpParserInternalError::Generic( &gt;+ "imageattr must have a parameter set after a direction token".to_string(), &gt;+ ))?.as_str() &gt;+ { &gt; "*" =&gt; Ok(SdpAttributeImageAttrSetList::Wildcard), &gt; x =&gt; { &gt; let mut sets = vec![parse_set(x)?]; &gt; while let Some(set_str) = tokens.clone().peek() { &gt; if set_str.starts_with("[") { &gt; sets.push(parse_set(&amp;tokens.next().unwrap())?); &gt; } else { &gt; break; &gt;@@ -1573,116 +1612,121 @@ fn parse_image_attr_set_list&lt;I&gt;(tokens: &amp;mut iter::Peekable&lt;I&gt;) &gt; Ok(SdpAttributeImageAttrSetList::Sets(sets)) &gt; } &gt; } &gt; } &gt; &gt; fn parse_image_attr(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let mut tokens = parse_imageattr_tokens(to_parse, ' ').into_iter().peekable(); &gt; &gt;- let pt = parse_payload_type(tokens.next().ok_or(SdpParserInternalError::Generic( &gt;- "imageattr requires a payload token".to_string() &gt;- ))?.as_str())?; &gt;- let first_direction = parse_single_direction(tokens.next().ok_or( &gt;- SdpParserInternalError::Generic( &gt;- "imageattr's second token must be a direction token".to_string() &gt;- ))?.as_str())?; &gt;+ let pt = parse_payload_type( &gt;+ tokens &gt;+ .next() &gt;+ .ok_or(SdpParserInternalError::Generic( &gt;+ "imageattr requires a payload token".to_string(), &gt;+ ))?.as_str(), &gt;+ )?; &gt;+ let first_direction = parse_single_direction( &gt;+ tokens &gt;+ .next() &gt;+ .ok_or(SdpParserInternalError::Generic( &gt;+ "imageattr's second token must be a direction token".to_string(), &gt;+ ))?.as_str(), &gt;+ )?; &gt; &gt; let first_set_list = parse_image_attr_set_list(&amp;mut tokens)?; &gt; &gt; let mut second_set_list = SdpAttributeImageAttrSetList::Sets(Vec::new()); &gt; &gt; // Check if there is a second direction defined &gt; if let Some(direction_token) = tokens.next() { &gt; if parse_single_direction(direction_token.as_str())? == first_direction { &gt; return Err(SdpParserInternalError::Generic( &gt; "imageattr's second direction token must be different from the first one" &gt;- .to_string() &gt;- )) &gt;+ .to_string(), &gt;+ )); &gt; } &gt; &gt; second_set_list = parse_image_attr_set_list(&amp;mut tokens)?; &gt; } &gt; &gt; if let Some(_) = tokens.next() { &gt; return Err(SdpParserInternalError::Generic( &gt;- "imageattr must not contain any token after the second set list".to_string() &gt;- )) &gt;+ "imageattr must not contain any token after the second set list".to_string(), &gt;+ )); &gt; } &gt; &gt; Ok(SdpAttribute::ImageAttr(match first_direction { &gt;- SdpSingleDirection::Send =&gt; &gt;- SdpAttributeImageAttr { &gt;- pt, &gt;- send: first_set_list, &gt;- recv: second_set_list, &gt;- }, &gt;- SdpSingleDirection::Recv =&gt; &gt;- SdpAttributeImageAttr { &gt;- pt, &gt;- send: second_set_list, &gt;- recv: first_set_list, &gt;- } &gt;+ SdpSingleDirection::Send =&gt; SdpAttributeImageAttr { &gt;+ pt, &gt;+ send: first_set_list, &gt;+ recv: second_set_list, &gt;+ }, &gt;+ SdpSingleDirection::Recv =&gt; SdpAttributeImageAttr { &gt;+ pt, &gt;+ send: second_set_list, &gt;+ recv: first_set_list, &gt;+ }, &gt; })) &gt; } &gt; &gt; fn parse_msid(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let mut tokens = to_parse.split_whitespace(); &gt; let id = match tokens.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Msid attribute is missing msid-id token" &gt;- .to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Msid attribute is missing msid-id token".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; x.to_string(), &gt; }; &gt; let appdata = match tokens.next() { &gt; None =&gt; None, &gt; Some(x) =&gt; Some(x.to_string()), &gt; }; &gt; Ok(SdpAttribute::Msid(SdpAttributeMsid { id, appdata })) &gt;- &gt; } &gt; &gt; fn parse_msid_semantic(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let tokens: Vec&lt;_&gt; = to_parse.split_whitespace().collect(); &gt; if tokens.len() &lt; 1 { &gt;- return Err(SdpParserInternalError::Generic("Msid-semantic attribute is missing msid-semantic token" &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Msid-semantic attribute is missing msid-semantic token".to_string(), &gt;+ )); &gt; } &gt; // TODO: Should msids be checked to ensure they are non empty? &gt; let semantic = SdpAttributeMsidSemantic { &gt; semantic: tokens[0].to_string(), &gt; msids: tokens[1..].iter().map(|x| x.to_string()).collect(), &gt; }; &gt; Ok(SdpAttribute::MsidSemantic(semantic)) &gt; } &gt; &gt; fn parse_rid(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let tokens: Vec&lt;&amp;str&gt; = to_parse.splitn(3, " ").collect(); &gt; &gt; if tokens.len() &lt; 2 { &gt; return Err(SdpParserInternalError::Generic( &gt;- "A rid attribute must at least have an id and a direction token.".to_string() &gt;+ "A rid attribute must at least have an id and a direction token.".to_string(), &gt; )); &gt; } &gt; &gt; // Default initilize &gt; let mut params = SdpAttributeRidParameters { &gt; max_width: 0, &gt; max_height: 0, &gt; max_fps: 0, &gt; max_fs: 0, &gt; max_br: 0, &gt; max_pps: 0, &gt; unknown: Vec::new(), &gt; }; &gt; let mut formats: Vec&lt;u16&gt; = Vec::new(); &gt; let mut depends: Vec&lt;String&gt; = Vec::new(); &gt; &gt;- &gt; if let Some(param_token) = tokens.get(2) { &gt; let mut parameters = param_token.split(";").peekable(); &gt; &gt; // The 'pt' parameter must be the first parameter if present, so it &gt; // cannot be checked along with the other parameters below &gt; if let Some(maybe_fmt_parameter) = parameters.clone().peek() { &gt; if maybe_fmt_parameter.starts_with("pt=") { &gt; let fmt_list = maybe_fmt_parameter[3..].split(","); &gt;@@ -1691,388 +1735,403 @@ fn parse_rid(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; } &gt; &gt; parameters.next(); &gt; } &gt; } &gt; &gt; for param in parameters { &gt; // TODO: Bug 1225877. Add support for params without '=' &gt;- let param_value_pair: Vec&lt;&amp;str&gt; = param.splitn(2,"=").collect(); &gt;+ let param_value_pair: Vec&lt;&amp;str&gt; = param.splitn(2, "=").collect(); &gt; if param_value_pair.len() != 2 { &gt; return Err(SdpParserInternalError::Generic( &gt;- "A rid parameter needs to be of form 'param=value'".to_string() &gt;+ "A rid parameter needs to be of form 'param=value'".to_string(), &gt; )); &gt; } &gt; &gt; match param_value_pair[0] { &gt; "max-width" =&gt; params.max_width = param_value_pair[1].parse::&lt;u32&gt;()?, &gt; "max-height" =&gt; params.max_height = param_value_pair[1].parse::&lt;u32&gt;()?, &gt; "max-fps" =&gt; params.max_fps = param_value_pair[1].parse::&lt;u32&gt;()?, &gt; "max-fs" =&gt; params.max_fs = param_value_pair[1].parse::&lt;u32&gt;()?, &gt; "max-br" =&gt; params.max_br = param_value_pair[1].parse::&lt;u32&gt;()?, &gt; "max-pps" =&gt; params.max_pps = param_value_pair[1].parse::&lt;u32&gt;()?, &gt; "depends" =&gt; { &gt; depends.extend(param_value_pair[1].split(",").map(|x| x.to_string())); &gt;- }, &gt;+ } &gt; _ =&gt; params.unknown.push(param.to_string()), &gt; } &gt; } &gt; } &gt; &gt;- Ok(SdpAttribute::Rid(SdpAttributeRid{ &gt;+ Ok(SdpAttribute::Rid(SdpAttributeRid { &gt; id: tokens[0].to_string(), &gt; direction: parse_single_direction(tokens[1])?, &gt; formats: formats, &gt; params: params, &gt; depends: depends, &gt; })) &gt; } &gt; &gt; fn parse_remote_candidates(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let mut tokens = to_parse.split_whitespace(); &gt; let component = match tokens.next() { &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Remote-candidate attribute is missing component ID" &gt;- .to_string(), &gt;- )) &gt;+ "Remote-candidate attribute is missing component ID".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; x.parse::&lt;u32&gt;()?, &gt; }; &gt; let address = match tokens.next() { &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Remote-candidate attribute is missing connection address" &gt;- .to_string(), &gt;- )) &gt;+ "Remote-candidate attribute is missing connection address".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; parse_unicast_addr(x)?, &gt; }; &gt; let port = match tokens.next() { &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Remote-candidate attribute is missing port number".to_string(), &gt;- )) &gt;+ "Remote-candidate attribute is missing port number".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; x.parse::&lt;u32&gt;()?, &gt; }; &gt; if port &gt; 65535 { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Remote-candidate port can only be a bit 16bit number".to_string(), &gt;- )); &gt;+ "Remote-candidate port can only be a bit 16bit number".to_string(), &gt;+ )); &gt; }; &gt; Ok(SdpAttribute::RemoteCandidate(SdpAttributeRemoteCandidate { &gt;- component, &gt;- address, &gt;- port, &gt;- })) &gt;+ component, &gt;+ address, &gt;+ port, &gt;+ })) &gt; } &gt; &gt; fn parse_rtpmap(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let mut tokens = to_parse.split_whitespace(); &gt; let payload_type: u8 = match tokens.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Rtpmap missing payload type".to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Rtpmap missing payload type".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; { &gt; let pt = x.parse::&lt;u8&gt;()?; &gt; if pt &gt; 127 { &gt;- return Err(SdpParserInternalError::Generic("Rtpmap payload type must be less then 127".to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Rtpmap payload type must be less then 127".to_string(), &gt;+ )); &gt; }; &gt; pt &gt; } &gt; }; &gt; let mut parameters = match tokens.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Rtpmap missing payload type".to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Rtpmap missing payload type".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; x.split('/'), &gt; }; &gt; let name = match parameters.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Rtpmap missing codec name".to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Rtpmap missing codec name".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; x.to_string(), &gt; }; &gt; let frequency = match parameters.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Rtpmap missing codec name".to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Rtpmap missing codec name".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; x.parse::&lt;u32&gt;()?, &gt; }; &gt; let mut rtpmap = SdpAttributeRtpmap::new(payload_type, name, frequency); &gt; match parameters.next() { &gt; Some(x) =&gt; rtpmap.set_channels(x.parse::&lt;u32&gt;()?), &gt; None =&gt; (), &gt; }; &gt; Ok(SdpAttribute::Rtpmap(rtpmap)) &gt; } &gt; &gt; fn parse_rtcp(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let mut tokens = to_parse.split_whitespace(); &gt; let port = match tokens.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Rtcp attribute is missing port number" &gt;- .to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Rtcp attribute is missing port number".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; x.parse::&lt;u16&gt;()?, &gt; }; &gt; let mut rtcp = SdpAttributeRtcp::new(port); &gt; match tokens.next() { &gt; None =&gt; (), &gt; Some(x) =&gt; { &gt; parse_nettype(x)?; &gt; match tokens.next() { &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Rtcp attribute is missing address type token" &gt;- .to_string(), &gt;- )) &gt;+ "Rtcp attribute is missing address type token".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; { &gt; let addrtype = parse_addrtype(x)?; &gt; let addr = match tokens.next() { &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Rtcp attribute is missing ip address token" &gt;- .to_string(), &gt;- )) &gt;+ "Rtcp attribute is missing ip address token".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; { &gt; let addr = parse_unicast_addr(x)?; &gt; if !addrtype.same_protocol(&amp;addr) { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Failed to parse unicast address attribute.\ &gt;- addrtype does not match address." &gt;- .to_string(), &gt;- )); &gt;+ "Failed to parse unicast address attribute.\ &gt;+ addrtype does not match address." &gt;+ .to_string(), &gt;+ )); &gt; } &gt; addr &gt; } &gt; }; &gt; rtcp.set_addr(addr); &gt; } &gt; }; &gt; } &gt; }; &gt; Ok(SdpAttribute::Rtcp(rtcp)) &gt; } &gt; &gt; fn parse_rtcp_fb(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt;- let tokens: Vec&lt;&amp;str&gt; = to_parse.splitn(4,' ').collect(); &gt;+ let tokens: Vec&lt;&amp;str&gt; = to_parse.splitn(4, ' ').collect(); &gt; &gt; // Parse this in advance to use it later in the parameter switch &gt; let feedback_type = match tokens.get(1) { &gt;- Some(x) =&gt; match x.as_ref(){ &gt;+ Some(x) =&gt; match x.as_ref() { &gt; "ack" =&gt; SdpAttributeRtcpFbType::Ack, &gt; "ccm" =&gt; SdpAttributeRtcpFbType::Ccm, &gt; "nack" =&gt; SdpAttributeRtcpFbType::Nack, &gt; "trr-int" =&gt; SdpAttributeRtcpFbType::TrrInt, &gt; "goog-remb" =&gt; SdpAttributeRtcpFbType::Remb, &gt; "transport-cc" =&gt; SdpAttributeRtcpFbType::TransCC, &gt; _ =&gt; { &gt; return Err(SdpParserInternalError::Unsupported( &gt;- format!("Unknown rtcpfb feedback type: {:?}",x).to_string() &gt;+ format!("Unknown rtcpfb feedback type: {:?}", x).to_string(), &gt; )) &gt; } &gt; }, &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Error parsing rtcpfb: no feedback type".to_string(), &gt;- )) &gt;+ "Error parsing rtcpfb: no feedback type".to_string(), &gt;+ )) &gt; } &gt; }; &gt; &gt; // Parse this in advance to make the initilization block below better readable &gt; let parameter = match &amp;feedback_type { &gt; &amp;SdpAttributeRtcpFbType::Ack =&gt; match tokens.get(2) { &gt; Some(x) =&gt; match x.as_ref() { &gt;- "rpsi" | "app" =&gt; x.to_string(), &gt;+ "rpsi" | "app" =&gt; x.to_string(), &gt; _ =&gt; { &gt; return Err(SdpParserInternalError::Unsupported( &gt;- format!("Unknown rtcpfb ack parameter: {:?}",x).to_string() &gt;+ format!("Unknown rtcpfb ack parameter: {:?}", x).to_string(), &gt; )) &gt;- }, &gt;+ } &gt; }, &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Unsupported( &gt;- format!("The rtcpfb ack feeback type needs a parameter:").to_string() &gt;+ format!("The rtcpfb ack feeback type needs a parameter:").to_string(), &gt; )) &gt; } &gt; }, &gt; &amp;SdpAttributeRtcpFbType::Ccm =&gt; match tokens.get(2) { &gt; Some(x) =&gt; match x.as_ref() { &gt;- "fir" | "tmmbr" | "tstr" | "vbcm" =&gt; x.to_string(), &gt;+ "fir" | "tmmbr" | "tstr" | "vbcm" =&gt; x.to_string(), &gt; _ =&gt; { &gt; return Err(SdpParserInternalError::Unsupported( &gt;- format!("Unknown rtcpfb ccm parameter: {:?}",x).to_string() &gt;+ format!("Unknown rtcpfb ccm parameter: {:?}", x).to_string(), &gt; )) &gt;- }, &gt;+ } &gt; }, &gt; None =&gt; "".to_string(), &gt; }, &gt; &amp;SdpAttributeRtcpFbType::Nack =&gt; match tokens.get(2) { &gt; Some(x) =&gt; match x.as_ref() { &gt;- "sli" | "pli" | "rpsi" | "app" =&gt; x.to_string(), &gt;+ "sli" | "pli" | "rpsi" | "app" =&gt; x.to_string(), &gt; _ =&gt; { &gt; return Err(SdpParserInternalError::Unsupported( &gt;- format!("Unknown rtcpfb nack parameter: {:?}",x).to_string() &gt;+ format!("Unknown rtcpfb nack parameter: {:?}", x).to_string(), &gt; )) &gt;- }, &gt;+ } &gt; }, &gt; None =&gt; "".to_string(), &gt; }, &gt; &amp;SdpAttributeRtcpFbType::TrrInt =&gt; match tokens.get(2) { &gt; Some(x) =&gt; match x { &gt; _ if x.parse::&lt;u32&gt;().is_ok() =&gt; x.to_string(), &gt; _ =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- format!("Unknown rtcpfb trr-int parameter: {:?}",x).to_string() &gt;+ format!("Unknown rtcpfb trr-int parameter: {:?}", x).to_string(), &gt; )) &gt;- }, &gt;+ } &gt; }, &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic( &gt;- format!("The rtcpfb trr-int feedback type needs a parameter").to_string() &gt;- )) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ format!("The rtcpfb trr-int feedback type needs a parameter").to_string(), &gt;+ )) &gt; } &gt; }, &gt; &amp;SdpAttributeRtcpFbType::Remb =&gt; match tokens.get(2) { &gt; Some(x) =&gt; match x { &gt; _ =&gt; { &gt; return Err(SdpParserInternalError::Unsupported( &gt;- format!("Unknown rtcpfb remb parameter: {:?}",x).to_string() &gt;+ format!("Unknown rtcpfb remb parameter: {:?}", x).to_string(), &gt; )) &gt;- }, &gt;+ } &gt; }, &gt; None =&gt; "".to_string(), &gt; }, &gt; &amp;SdpAttributeRtcpFbType::TransCC =&gt; match tokens.get(2) { &gt; Some(x) =&gt; match x { &gt; _ =&gt; { &gt; return Err(SdpParserInternalError::Unsupported( &gt;- format!("Unknown rtcpfb transport-cc parameter: {:?}",x).to_string() &gt;+ format!("Unknown rtcpfb transport-cc parameter: {:?}", x).to_string(), &gt; )) &gt;- }, &gt;+ } &gt; }, &gt; None =&gt; "".to_string(), &gt;- } &gt;+ }, &gt; }; &gt; &gt;- &gt; Ok(SdpAttribute::Rtcpfb(SdpAttributeRtcpFb { &gt;- payload_type: parse_payload_type(tokens[0])?, &gt;+ payload_type: parse_payload_type(tokens[0])?, &gt; &gt;- feedback_type: feedback_type, &gt;+ feedback_type: feedback_type, &gt; &gt;- parameter: parameter, &gt;+ parameter: parameter, &gt; &gt;- extra: match tokens.get(3) { &gt;- Some(x) =&gt; x.to_string(), &gt;- None =&gt; "".to_string(), &gt;- }, &gt;- })) &gt;+ extra: match tokens.get(3) { &gt;+ Some(x) =&gt; x.to_string(), &gt;+ None =&gt; "".to_string(), &gt;+ }, &gt;+ })) &gt; } &gt; &gt; fn parse_sctpmap(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; let tokens: Vec&lt;&amp;str&gt; = to_parse.split_whitespace().collect(); &gt; if tokens.len() != 3 { &gt;- return Err(SdpParserInternalError::Generic("Sctpmap needs to have three tokens" &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Sctpmap needs to have three tokens".to_string(), &gt;+ )); &gt; } &gt; let port = tokens[0].parse::&lt;u16&gt;()?; &gt; if tokens[1].to_lowercase() != "webrtc-datachannel" { &gt;- return Err(SdpParserInternalError::Generic("Unsupported sctpmap type token".to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Unsupported sctpmap type token".to_string(), &gt;+ )); &gt; } &gt; Ok(SdpAttribute::Sctpmap(SdpAttributeSctpmap { &gt;- port, &gt;- channels: tokens[2].parse::&lt;u32&gt;()?, &gt;- })) &gt;+ port, &gt;+ channels: tokens[2].parse::&lt;u32&gt;()?, &gt;+ })) &gt; } &gt; &gt; fn parse_setup(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt;- Ok(SdpAttribute::Setup(match to_parse.to_lowercase().as_ref() { &gt;- "active" =&gt; SdpAttributeSetup::Active, &gt;- "actpass" =&gt; SdpAttributeSetup::Actpass, &gt;- "holdconn" =&gt; SdpAttributeSetup::Holdconn, &gt;- "passive" =&gt; SdpAttributeSetup::Passive, &gt;- _ =&gt; { &gt;- return Err(SdpParserInternalError::Generic( &gt;- "Unsupported setup value".to_string(), &gt;- )) &gt;- } &gt;- })) &gt;+ Ok(SdpAttribute::Setup( &gt;+ match to_parse.to_lowercase().as_ref() { &gt;+ "active" =&gt; SdpAttributeSetup::Active, &gt;+ "actpass" =&gt; SdpAttributeSetup::Actpass, &gt;+ "holdconn" =&gt; SdpAttributeSetup::Holdconn, &gt;+ "passive" =&gt; SdpAttributeSetup::Passive, &gt;+ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Unsupported setup value".to_string(), &gt;+ )) &gt;+ } &gt;+ }, &gt;+ )) &gt; } &gt; &gt;-fn parse_simulcast_version_list(to_parse: &amp;str) -&gt; Result&lt;Vec&lt;SdpAttributeSimulcastVersion&gt;, &gt;- SdpParserInternalError&gt; { &gt;+fn parse_simulcast_version_list( &gt;+ to_parse: &amp;str, &gt;+) -&gt; Result&lt;Vec&lt;SdpAttributeSimulcastVersion&gt;, SdpParserInternalError&gt; { &gt; let make_version_list = |to_parse: &amp;str| { &gt;- to_parse.split(';').map(SdpAttributeSimulcastVersion::new).collect() &gt;+ to_parse &gt;+ .split(';') &gt;+ .map(SdpAttributeSimulcastVersion::new) &gt;+ .collect() &gt; }; &gt; if to_parse.contains("=") { &gt;- let mut descriptor_versionlist_pair = to_parse.splitn(2,"="); &gt;- match descriptor_versionlist_pair.next().unwrap() { &gt;- // TODO Bug 1470568 &gt;- "rid" =&gt; Ok(make_version_list(descriptor_versionlist_pair.next().unwrap())), &gt;- descriptor @ _ =&gt; { &gt;- return Err(SdpParserInternalError::Generic( &gt;- format!("Simulcast attribute has unknown list descriptor '{:?}'", &gt;- descriptor) &gt;- .to_string() &gt;- )) &gt;- } &gt;- } &gt;+ let mut descriptor_versionlist_pair = to_parse.splitn(2, "="); &gt;+ match descriptor_versionlist_pair.next().unwrap() { &gt;+ // TODO Bug 1470568 &gt;+ "rid" =&gt; Ok(make_version_list( &gt;+ descriptor_versionlist_pair.next().unwrap(), &gt;+ )), &gt;+ descriptor @ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ format!( &gt;+ "Simulcast attribute has unknown list descriptor '{:?}'", &gt;+ descriptor &gt;+ ).to_string(), &gt;+ )) &gt;+ } &gt;+ } &gt; } else { &gt;- Ok(make_version_list(to_parse)) &gt;+ Ok(make_version_list(to_parse)) &gt; } &gt; } &gt; &gt; fn parse_simulcast(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt; // TODO: Bug 1225877: Stop accepting all kinds of whitespace here, and only accept SP &gt; let mut tokens = to_parse.trim().split_whitespace(); &gt; let first_direction = match tokens.next() { &gt; Some(x) =&gt; parse_single_direction(x)?, &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Simulcast attribute is missing send/recv value".to_string(), &gt;- )) &gt;+ "Simulcast attribute is missing send/recv value".to_string(), &gt;+ )) &gt; } &gt; }; &gt; &gt; let first_version_list = match tokens.next() { &gt;- Some(x) =&gt; { &gt;- parse_simulcast_version_list(x)? &gt;- }, &gt;+ Some(x) =&gt; parse_simulcast_version_list(x)?, &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Simulcast attribute must have an alternatives list after the direction token" &gt;+ "Simulcast attribute must have an alternatives list after the direction token" &gt; .to_string(), &gt; )); &gt; } &gt; }; &gt; &gt; let mut second_version_list = Vec::new(); &gt; if let Some(x) = tokens.next() { &gt; if parse_single_direction(x)? == first_direction { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Simulcast attribute has defined two times the same direction".to_string() &gt;+ "Simulcast attribute has defined two times the same direction".to_string(), &gt; )); &gt; } &gt; &gt; second_version_list = match tokens.next() { &gt;- Some(x) =&gt; { &gt;- parse_simulcast_version_list(x)? &gt;- }, &gt;+ Some(x) =&gt; parse_simulcast_version_list(x)?, &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- format!("{:?}{:?}", &gt;- "Simulcast has defined a second direction but", &gt;- "no second list of simulcast stream versions") &gt;- .to_string() &gt;+ format!( &gt;+ "{:?}{:?}", &gt;+ "Simulcast has defined a second direction but", &gt;+ "no second list of simulcast stream versions" &gt;+ ).to_string(), &gt; )); &gt; } &gt; } &gt; } &gt; &gt; Ok(SdpAttribute::Simulcast(match first_direction { &gt; SdpSingleDirection::Send =&gt; SdpAttributeSimulcast { &gt; send: first_version_list, &gt;@@ -2081,48 +2140,48 @@ fn parse_simulcast(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalErro &gt; SdpSingleDirection::Recv =&gt; SdpAttributeSimulcast { &gt; send: second_version_list, &gt; receive: first_version_list, &gt; }, &gt; })) &gt; } &gt; &gt; fn parse_ssrc(to_parse: &amp;str) -&gt; Result&lt;SdpAttribute, SdpParserInternalError&gt; { &gt;- let mut tokens = to_parse.splitn(2,' '); &gt;+ let mut tokens = to_parse.splitn(2, ' '); &gt; let ssrc_id = match tokens.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Ssrc attribute is missing ssrc-id value" &gt;- .to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Ssrc attribute is missing ssrc-id value".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; x.parse::&lt;u32&gt;()?, &gt; }; &gt; let mut ssrc = SdpAttributeSsrc::new(ssrc_id); &gt; match tokens.next() { &gt; None =&gt; (), &gt; Some(x) =&gt; ssrc.set_attribute(x), &gt; }; &gt; Ok(SdpAttribute::Ssrc(ssrc)) &gt; } &gt; &gt; pub fn parse_attribute(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; Ok(SdpType::Attribute(value.trim().parse()?)) &gt; } &gt; &gt;- &gt; #[cfg(test)] &gt; macro_rules! make_check_parse { &gt; ($attr_type:ty, $attr_kind:path) =&gt; { &gt; |attr_str: &amp;str| -&gt; $attr_type { &gt; if let Ok(SdpType::Attribute($attr_kind(attr))) = parse_attribute(attr_str) { &gt; attr &gt; } else { &gt; unreachable!(); &gt; } &gt; } &gt;- } &gt;+ }; &gt; } &gt; &gt; #[test] &gt; fn test_parse_attribute_candidate() { &gt; let check_parse = make_check_parse!(SdpAttributeCandidate, SdpAttribute::Candidate); &gt; &gt; let check_parse_and_serialize = |attr_str| { &gt; let parsed = check_parse(attr_str); &gt;@@ -2131,53 +2190,75 @@ fn test_parse_attribute_candidate() { &gt; &gt; check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ host"); &gt; check_parse_and_serialize("candidate:foo 1 UDP 2122252543 172.16.156.106 49760 typ host"); &gt; check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host"); &gt; check_parse_and_serialize("candidate:0 1 TCP 2122252543 ::1 49760 typ host"); &gt; check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ srflx"); &gt; check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ prflx"); &gt; check_parse_and_serialize("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ relay"); &gt;- check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype active"); &gt;- check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype passive"); &gt;- check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype so"); &gt;- check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host ufrag foobar"); &gt;- check_parse_and_serialize("candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host network-cost 50"); &gt;+ check_parse_and_serialize( &gt;+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype active", &gt;+ ); &gt;+ check_parse_and_serialize( &gt;+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype passive", &gt;+ ); &gt;+ check_parse_and_serialize( &gt;+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host tcptype so", &gt;+ ); &gt;+ check_parse_and_serialize( &gt;+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host ufrag foobar", &gt;+ ); &gt;+ check_parse_and_serialize( &gt;+ "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host network-cost 50", &gt;+ ); &gt; check_parse_and_serialize("candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 generation 0"); &gt;- check_parse_and_serialize("candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665"); &gt;+ check_parse_and_serialize( &gt;+ "candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665", &gt;+ ); &gt; check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive"); &gt; check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1"); &gt; check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd"); &gt; check_parse_and_serialize("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd network-cost 1"); &gt; &gt; let candidate = check_parse("candidate:1 1 TCP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 tcptype passive generation 1 ufrag +DGd network-cost 1"); &gt; assert_eq!(candidate.foundation, "1".to_string()); &gt; assert_eq!(candidate.component, 1); &gt; assert_eq!(candidate.transport, SdpAttributeCandidateTransport::Tcp); &gt; assert_eq!(candidate.priority, 1685987071); &gt;- assert_eq!(candidate.address, IpAddr::from_str("24.23.204.141").unwrap()); &gt;+ assert_eq!( &gt;+ candidate.address, &gt;+ IpAddr::from_str("24.23.204.141").unwrap() &gt;+ ); &gt; assert_eq!(candidate.port, 54609); &gt; assert_eq!(candidate.c_type, SdpAttributeCandidateType::Srflx); &gt;- assert_eq!(candidate.raddr, Some(IpAddr::from_str("192.168.1.4").unwrap())); &gt;+ assert_eq!( &gt;+ candidate.raddr, &gt;+ Some(IpAddr::from_str("192.168.1.4").unwrap()) &gt;+ ); &gt; assert_eq!(candidate.rport, Some(61665)); &gt;- assert_eq!(candidate.tcp_type, Some(SdpAttributeCandidateTcpType::Passive)); &gt;+ assert_eq!( &gt;+ candidate.tcp_type, &gt;+ Some(SdpAttributeCandidateTcpType::Passive) &gt;+ ); &gt; assert_eq!(candidate.generation, Some(1)); &gt; assert_eq!(candidate.ufrag, Some("+DGd".to_string())); &gt; assert_eq!(candidate.networkcost, Some(1)); &gt; &gt;- &gt; assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ").is_err()); &gt;- assert!(parse_attribute("candidate:0 foo UDP 2122252543 172.16.156.106 49760 typ host") &gt;- .is_err()); &gt;+ assert!( &gt;+ parse_attribute("candidate:0 foo UDP 2122252543 172.16.156.106 49760 typ host").is_err() &gt;+ ); &gt; assert!(parse_attribute("candidate:0 1 FOO 2122252543 172.16.156.106 49760 typ host").is_err()); &gt; assert!(parse_attribute("candidate:0 1 UDP foo 172.16.156.106 49760 typ host").is_err()); &gt; assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156 49760 typ host").is_err()); &gt; assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 70000 typ host").is_err()); &gt;- assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 type host") &gt;- .is_err()); &gt;+ assert!( &gt;+ parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 type host").is_err() &gt;+ ); &gt; assert!(parse_attribute("candidate:0 1 UDP 2122252543 172.16.156.106 49760 typ fost").is_err()); &gt; // FIXME this should fail without the extra 'foobar' at the end &gt; assert!( &gt; parse_attribute( &gt; "candidate:0 1 TCP 2122252543 172.16.156.106 49760 typ host unsupported foobar" &gt; ).is_err() &gt; ); &gt; assert!(parse_attribute("candidate:1 1 UDP 1685987071 24.23.204.141 54609 typ srflx raddr 192.168.1.4 rport 61665 generation B").is_err()); &gt;@@ -2211,94 +2292,172 @@ fn test_parse_dtls_message() { &gt; x &gt; } else { &gt; unreachable!(); &gt; } &gt; }; &gt; &gt; assert!(parse_attribute("dtls-message:client SGVsbG8gV29ybGQ=").is_ok()); &gt; assert!(parse_attribute("dtls-message:server SGVsbG8gV29ybGQ=").is_ok()); &gt;- assert!(parse_attribute("dtls-message:client IGlzdCBl/W4gUeiBtaXQg+JSB1bmQCAkJJkSNEQ=").is_ok()); &gt;- assert!(parse_attribute("dtls-message:server IGlzdCBl/W4gUeiBtaXQg+JSB1bmQCAkJJkSNEQ=").is_ok()); &gt;+ assert!( &gt;+ parse_attribute("dtls-message:client IGlzdCBl/W4gUeiBtaXQg+JSB1bmQCAkJJkSNEQ=").is_ok() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute("dtls-message:server IGlzdCBl/W4gUeiBtaXQg+JSB1bmQCAkJJkSNEQ=").is_ok() &gt;+ ); &gt; &gt; let mut dtls_message = check_parse("dtls-message:client SGVsbG8gV29ybGQ="); &gt; match dtls_message { &gt; SdpAttributeDtlsMessage::Client(x) =&gt; { &gt; assert_eq!(x, "SGVsbG8gV29ybGQ="); &gt;- }, &gt;- _ =&gt; { unreachable!(); } &gt;+ } &gt;+ _ =&gt; { &gt;+ unreachable!(); &gt;+ } &gt; } &gt; &gt; dtls_message = check_parse("dtls-message:server SGVsbG8gV29ybGQ="); &gt; match dtls_message { &gt; SdpAttributeDtlsMessage::Server(x) =&gt; { &gt; assert_eq!(x, "SGVsbG8gV29ybGQ="); &gt;- }, &gt;- _ =&gt; { unreachable!(); } &gt;+ } &gt;+ _ =&gt; { &gt;+ unreachable!(); &gt;+ } &gt; } &gt; &gt;- &gt; assert!(parse_attribute("dtls-message:client").is_err()); &gt; assert!(parse_attribute("dtls-message:server").is_err()); &gt; } &gt; &gt; #[test] &gt; fn test_parse_attribute_end_of_candidates() { &gt; assert!(parse_attribute("end-of-candidates").is_ok()); &gt; assert!(parse_attribute("end-of-candidates foobar").is_err()); &gt; } &gt; &gt; #[test] &gt; fn test_parse_attribute_extmap() { &gt;- assert!(parse_attribute("extmap:1/sendonly urn:ietf:params:rtp-hdrext:ssrc-audio-level") &gt;- .is_ok()); &gt;- assert!(parse_attribute("extmap:2/sendrecv urn:ietf:params:rtp-hdrext:ssrc-audio-level") &gt;- .is_ok()); &gt;- assert!(parse_attribute("extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time") &gt;- .is_ok()); &gt;+ assert!( &gt;+ parse_attribute("extmap:1/sendonly urn:ietf:params:rtp-hdrext:ssrc-audio-level").is_ok() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute("extmap:2/sendrecv urn:ietf:params:rtp-hdrext:ssrc-audio-level").is_ok() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute("extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time") &gt;+ .is_ok() &gt;+ ); &gt; &gt;- assert!(parse_attribute("extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time ext_attributes") &gt;- .is_ok()); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time ext_attributes" &gt;+ ).is_ok() &gt;+ ); &gt; &gt;- assert!(parse_attribute("extmap:a/sendrecv urn:ietf:params:rtp-hdrext:ssrc-audio-level") &gt;- .is_err()); &gt;- assert!(parse_attribute("extmap:4/unsupported urn:ietf:params:rtp-hdrext:ssrc-audio-level") &gt;- .is_err()); &gt;+ assert!( &gt;+ parse_attribute("extmap:a/sendrecv urn:ietf:params:rtp-hdrext:ssrc-audio-level").is_err() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute("extmap:4/unsupported urn:ietf:params:rtp-hdrext:ssrc-audio-level") &gt;+ .is_err() &gt;+ ); &gt; &gt;- let mut bad_char = String::from("extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time ",); &gt;+ let mut bad_char = &gt;+ String::from("extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time "); &gt; bad_char.push(0x00 as char); &gt; assert!(parse_attribute(&amp;bad_char).is_err()); &gt; } &gt; &gt; #[test] &gt; fn test_parse_attribute_fingerprint() { &gt;- assert!(parse_attribute("fingerprint:sha-1 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC").is_ok()); &gt;- assert!(parse_attribute("fingerprint:sha-224 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\ &gt;- 27:97:EB:0B:23:73:AC:BC").is_ok()); &gt;- assert!(parse_attribute("fingerprint:sha-256 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\ &gt;- 27:97:EB:0B:23:73:AC:BC:CD:34:D1:62").is_ok()); &gt;- assert!(parse_attribute("fingerprint:sha-384 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\ &gt;- 27:97:EB:0B:23:73:AC:BC:CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:\ &gt;- 27:97:EB:0B:23:73:AC:BC").is_ok()); &gt;- assert!(parse_attribute("fingerprint:sha-512 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\ &gt;- 97:EB:0B:23:73:AC:BC:CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:\ &gt;- EB:0B:23:73:AC:BC:27:97:EB:0B:23:73:AC:BC:27:97:EB:0B:23:73:\ &gt;- BC:EB:0B:23").is_ok()); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-1 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC" &gt;+ ).is_ok() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-224 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\ &gt;+ 27:97:EB:0B:23:73:AC:BC" &gt;+ ).is_ok() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-256 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\ &gt;+ 27:97:EB:0B:23:73:AC:BC:CD:34:D1:62" &gt;+ ).is_ok() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-384 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\ &gt;+ 27:97:EB:0B:23:73:AC:BC:CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:\ &gt;+ 27:97:EB:0B:23:73:AC:BC" &gt;+ ).is_ok() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-512 CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC:\ &gt;+ 97:EB:0B:23:73:AC:BC:CD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:\ &gt;+ EB:0B:23:73:AC:BC:27:97:EB:0B:23:73:AC:BC:27:97:EB:0B:23:73:\ &gt;+ BC:EB:0B:23" &gt;+ ).is_ok() &gt;+ ); &gt; &gt;- assert!(parse_attribute("fingerprint:sha-1 CX:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:BC").is_err()); &gt;- assert!(parse_attribute("fingerprint:sha-1 CDA:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:BC").is_err()); &gt;- assert!(parse_attribute("fingerprint:sha-1 CD:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:").is_err()); &gt;- assert!(parse_attribute("fingerprint:sha-1 CD:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC").is_err()); &gt;- assert!(parse_attribute("fingerprint:sha-1 CX:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:BC").is_err()); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-1 CX:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:BC" &gt;+ ).is_err() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-1 CDA:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:BC" &gt;+ ).is_err() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-1 CD:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:" &gt;+ ).is_err() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-1 CD:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC" &gt;+ ).is_err() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-1 CX:34:D1:62:16:95:7B:B7:EB:74:E1:39:27:97:EB:0B:23:73:AC:BC" &gt;+ ).is_err() &gt;+ ); &gt; &gt;- assert!(parse_attribute("fingerprint:sha-1 0xCD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC").is_err()); &gt;- assert!(parse_attribute("fingerprint:sha-1 CD:0x34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC").is_err()); &gt;- assert!(parse_attribute("fingerprint:sha-1 CD::D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC").is_err()); &gt;- assert!(parse_attribute("fingerprint:sha-1 CD:0000A:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC").is_err()); &gt;- assert!(parse_attribute("fingerprint:sha-1 CD:B:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC").is_err()); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-1 0xCD:34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC" &gt;+ ).is_err() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-1 CD:0x34:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC" &gt;+ ).is_err() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-1 CD::D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC" &gt;+ ).is_err() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-1 CD:0000A:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC" &gt;+ ).is_err() &gt;+ ); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "fingerprint:sha-1 CD:B:D1:62:16:95:7B:B7:EB:74:E2:39:27:97:EB:0B:23:73:AC:BC" &gt;+ ).is_err() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn test_parse_attribute_fmtp() { &gt; assert!(parse_attribute("fmtp:109 maxplaybackrate=48000;stereo=1;useinbandfec=1").is_ok()); &gt; assert!(parse_attribute("fmtp:66 0-15").is_ok()); &gt; assert!(parse_attribute("fmtp:109 0-15,66").is_ok()); &gt; assert!(parse_attribute("fmtp:66 111/115").is_ok()); &gt;@@ -2316,17 +2475,17 @@ fn test_parse_attribute_fmtp() { &gt; fn test_parse_attribute_group() { &gt; assert!(parse_attribute("group:LS").is_ok()); &gt; assert!(parse_attribute("group:LS 1 2").is_ok()); &gt; assert!(parse_attribute("group:BUNDLE sdparta_0 sdparta_1 sdparta_2").is_ok()); &gt; &gt; assert!(parse_attribute("group:").is_err()); &gt; assert!(match parse_attribute("group:NEVER_SUPPORTED_SEMANTICS") { &gt; Err(SdpParserInternalError::Unsupported(_)) =&gt; true, &gt;- _ =&gt; false &gt;+ _ =&gt; false, &gt; }) &gt; } &gt; &gt; #[test] &gt; fn test_parse_attribute_bundle_only() { &gt; assert!(parse_attribute("bundle-only").is_ok()); &gt; assert!(parse_attribute("bundle-only foobar").is_err()); &gt; } &gt;@@ -2380,74 +2539,120 @@ fn test_parse_attribute_imageattr() { &gt; x &gt; } else { &gt; unreachable!(); &gt; } &gt; }; &gt; &gt; assert!(parse_attribute("imageattr:120 send * recv *").is_ok()); &gt; assert!(parse_attribute("imageattr:99 send [x=320,y=240] recv [x=320,y=240]").is_ok()); &gt;- assert!(parse_attribute("imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]").is_ok()); &gt;+ assert!( &gt;+ parse_attribute( &gt;+ "imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]" &gt;+ ).is_ok() &gt;+ ); &gt; assert!(parse_attribute("imageattr:97 recv [x=800,y=640,sar=1.1] send [x=330,y=250]").is_ok()); &gt; assert!(parse_attribute("imageattr:97 send [x=[480:16:800],y=[320:16:640],par=[1.2-1.3],q=0.6] [x=[176:8:208],y=[144:8:176],par=[1.2-1.3]] recv *").is_ok()); &gt; &gt;- let mut imageattr = check_parse("imageattr:* recv [x=800,y=[50,80,30],sar=1.1] send [x=330,y=250,sar=[1.1,1.3,1.9],q=0.1]"); &gt;+ let mut imageattr = check_parse( &gt;+ "imageattr:* recv [x=800,y=[50,80,30],sar=1.1] send [x=330,y=250,sar=[1.1,1.3,1.9],q=0.1]", &gt;+ ); &gt; assert_eq!(imageattr.pt, SdpAttributePayloadType::Wildcard); &gt; match imageattr.recv { &gt; SdpAttributeImageAttrSetList::Sets(sets) =&gt; { &gt; assert_eq!(sets.len(), 1); &gt; &gt; let set = &amp;sets[0]; &gt;- assert_eq!(set.x, SdpAttributeImageAttrXYRange::DiscreteValues(vec![800])); &gt;- assert_eq!(set.y, SdpAttributeImageAttrXYRange::DiscreteValues(vec![50,80,30])); &gt;+ assert_eq!( &gt;+ set.x, &gt;+ SdpAttributeImageAttrXYRange::DiscreteValues(vec![800]) &gt;+ ); &gt;+ assert_eq!( &gt;+ set.y, &gt;+ SdpAttributeImageAttrXYRange::DiscreteValues(vec![50, 80, 30]) &gt;+ ); &gt; assert_eq!(set.par, None); &gt;- assert_eq!(set.sar, Some(SdpAttributeImageAttrSRange::DiscreteValues(vec![1.1]))); &gt;+ assert_eq!( &gt;+ set.sar, &gt;+ Some(SdpAttributeImageAttrSRange::DiscreteValues(vec![1.1])) &gt;+ ); &gt; assert_eq!(set.q, None); &gt;- &gt;- }, &gt;- _ =&gt; { unreachable!(); } &gt;+ } &gt;+ _ =&gt; { &gt;+ unreachable!(); &gt;+ } &gt; } &gt; match imageattr.send { &gt; SdpAttributeImageAttrSetList::Sets(sets) =&gt; { &gt; assert_eq!(sets.len(), 1); &gt; &gt; let set = &amp;sets[0]; &gt;- assert_eq!(set.x, SdpAttributeImageAttrXYRange::DiscreteValues(vec![330])); &gt;- assert_eq!(set.y, SdpAttributeImageAttrXYRange::DiscreteValues(vec![250])); &gt;+ assert_eq!( &gt;+ set.x, &gt;+ SdpAttributeImageAttrXYRange::DiscreteValues(vec![330]) &gt;+ ); &gt;+ assert_eq!( &gt;+ set.y, &gt;+ SdpAttributeImageAttrXYRange::DiscreteValues(vec![250]) &gt;+ ); &gt; assert_eq!(set.par, None); &gt;- assert_eq!(set.sar, Some(SdpAttributeImageAttrSRange::DiscreteValues(vec![1.1,1.3,1.9]))); &gt;+ assert_eq!( &gt;+ set.sar, &gt;+ Some(SdpAttributeImageAttrSRange::DiscreteValues(vec![ &gt;+ 1.1, 1.3, 1.9 &gt;+ ])) &gt;+ ); &gt; assert_eq!(set.q, Some(0.1)); &gt;- }, &gt;- _ =&gt; { unreachable!(); } &gt;+ } &gt;+ _ =&gt; { &gt;+ unreachable!(); &gt;+ } &gt; } &gt; &gt; imageattr = check_parse("imageattr:97 send [x=[480:16:800],y=[100,200,300],par=[1.2-1.3],q=0.6] [x=1080,y=[144:176],sar=[0.5-0.7]] recv *"); &gt; assert_eq!(imageattr.pt, SdpAttributePayloadType::PayloadType(97)); &gt; match imageattr.send { &gt; SdpAttributeImageAttrSetList::Sets(sets) =&gt; { &gt; assert_eq!(sets.len(), 2); &gt; &gt; let first_set = &amp;sets[0]; &gt;- assert_eq!(first_set.x, SdpAttributeImageAttrXYRange::Range(480, 800, Some(16))); &gt;- assert_eq!(first_set.y, SdpAttributeImageAttrXYRange::DiscreteValues(vec![100, 200, 300])); &gt;- assert_eq!(first_set.par, Some(SdpAttributeImageAttrPRange { &gt;- min: 1.2, &gt;- max: 1.3 &gt;- })); &gt;+ assert_eq!( &gt;+ first_set.x, &gt;+ SdpAttributeImageAttrXYRange::Range(480, 800, Some(16)) &gt;+ ); &gt;+ assert_eq!( &gt;+ first_set.y, &gt;+ SdpAttributeImageAttrXYRange::DiscreteValues(vec![100, 200, 300]) &gt;+ ); &gt;+ assert_eq!( &gt;+ first_set.par, &gt;+ Some(SdpAttributeImageAttrPRange { min: 1.2, max: 1.3 }) &gt;+ ); &gt; assert_eq!(first_set.sar, None); &gt; assert_eq!(first_set.q, Some(0.6)); &gt; &gt; let second_set = &amp;sets[1]; &gt;- assert_eq!(second_set.x, SdpAttributeImageAttrXYRange::DiscreteValues(vec![1080])); &gt;- assert_eq!(second_set.y, SdpAttributeImageAttrXYRange::Range(144, 176, None)); &gt;+ assert_eq!( &gt;+ second_set.x, &gt;+ SdpAttributeImageAttrXYRange::DiscreteValues(vec![1080]) &gt;+ ); &gt;+ assert_eq!( &gt;+ second_set.y, &gt;+ SdpAttributeImageAttrXYRange::Range(144, 176, None) &gt;+ ); &gt; assert_eq!(second_set.par, None); &gt;- assert_eq!(second_set.sar, Some(SdpAttributeImageAttrSRange::Range(0.5, 0.7))); &gt;+ assert_eq!( &gt;+ second_set.sar, &gt;+ Some(SdpAttributeImageAttrSRange::Range(0.5, 0.7)) &gt;+ ); &gt; assert_eq!(second_set.q, None); &gt;- }, &gt;- _ =&gt; { unreachable!(); } &gt;+ } &gt;+ _ =&gt; { &gt;+ unreachable!(); &gt;+ } &gt; } &gt; assert_eq!(imageattr.recv, SdpAttributeImageAttrSetList::Wildcard); &gt; &gt; assert!(parse_attribute("imageattr:99 send [x=320,y=240]").is_ok()); &gt; assert!(parse_attribute("imageattr:100 recv [x=320,y=240]").is_ok()); &gt; assert!(parse_attribute("imageattr:97 recv [x=800,y=640,sar=1.1,foo=[123,456],q=0.5] send [x=330,y=250,bar=foo,sar=[20-40]]").is_ok()); &gt; assert!(parse_attribute("imageattr:97 recv [x=800,y=640,sar=1.1,foo=abc xyz,q=0.5] send [x=330,y=250,bar=foo,sar=[20-40]]").is_ok()); &gt; &gt;@@ -2508,52 +2713,52 @@ fn test_parse_attribute_msid_semantics() { &gt; fn test_parse_attribute_ptime() { &gt; assert!(parse_attribute("ptime:30").is_ok()); &gt; &gt; assert!(parse_attribute("ptime:").is_err()); &gt; } &gt; &gt; #[test] &gt; fn test_parse_attribute_rid() { &gt;- &gt; let check_parse = |x| -&gt; SdpAttributeRid { &gt; if let Ok(SdpType::Attribute(SdpAttribute::Rid(x))) = parse_attribute(x) { &gt; x &gt; } else { &gt; unreachable!(); &gt; } &gt; }; &gt; &gt; // assert!(parse_attribute("rid:foo send").is_ok()); &gt; let mut rid = check_parse("rid:foo send"); &gt; assert_eq!(rid.id, "foo"); &gt; assert_eq!(rid.direction, SdpSingleDirection::Send); &gt; &gt;- &gt; // assert!(parse_attribute("rid:110 send pt=9").is_ok()); &gt; rid = check_parse("rid:110 send pt=9"); &gt; assert_eq!(rid.id, "110"); &gt; assert_eq!(rid.direction, SdpSingleDirection::Send); &gt; assert_eq!(rid.formats, vec![9]); &gt; &gt; assert!(parse_attribute("rid:foo send pt=10").is_ok()); &gt; assert!(parse_attribute("rid:110 send pt=9,10").is_ok()); &gt; assert!(parse_attribute("rid:110 send pt=9,10;max-fs=10").is_ok()); &gt; assert!(parse_attribute("rid:110 send pt=9,10;max-width=10;depends=1,2,3").is_ok()); &gt; &gt; // assert!(parse_attribute("rid:110 send pt=9,10;max-fs=10;UNKNOWN=100;depends=1,2,3").is_ok()); &gt; rid = check_parse("rid:110 send pt=9,10;max-fs=10;UNKNOWN=100;depends=1,2,3"); &gt; assert_eq!(rid.id, "110"); &gt; assert_eq!(rid.direction, SdpSingleDirection::Send); &gt;- assert_eq!(rid.formats, vec![9,10]); &gt;+ assert_eq!(rid.formats, vec![9, 10]); &gt; assert_eq!(rid.params.max_fs, 10); &gt; assert_eq!(rid.params.unknown, vec!["UNKNOWN=100"]); &gt;- assert_eq!(rid.depends, vec!["1","2","3"]); &gt;+ assert_eq!(rid.depends, vec!["1", "2", "3"]); &gt; &gt;- assert!(parse_attribute("rid:110 send pt=9, 10;max-fs=10;UNKNOWN=100; depends=1, 2, 3").is_ok()); &gt;+ assert!( &gt;+ parse_attribute("rid:110 send pt=9, 10;max-fs=10;UNKNOWN=100; depends=1, 2, 3").is_ok() &gt;+ ); &gt; assert!(parse_attribute("rid:110 send max-fs=10").is_ok()); &gt; assert!(parse_attribute("rid:110 recv max-width=1920;max-height=1080").is_ok()); &gt; &gt; // assert!(parse_attribute("rid:110 recv max-fps=42;max-fs=10;max-br=3;max-pps=1000").is_ok()); &gt; rid = check_parse("rid:110 recv max-fps=42;max-fs=10;max-br=3;max-pps=1000"); &gt; assert_eq!(rid.id, "110"); &gt; assert_eq!(rid.direction, SdpSingleDirection::Recv); &gt; assert_eq!(rid.params.max_fps, 42); &gt;@@ -2725,18 +2930,19 @@ fn test_parse_attribute_simulcast() { &gt; // old draft 03 notation used by Firefox 55 &gt; assert!(parse_attribute("simulcast: send foo=8;10").is_err()); &gt; } &gt; &gt; #[test] &gt; fn test_parse_attribute_ssrc() { &gt; assert!(parse_attribute("ssrc:2655508255").is_ok()); &gt; assert!(parse_attribute("ssrc:2655508255 foo").is_ok()); &gt;- assert!(parse_attribute("ssrc:2655508255 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}") &gt;- .is_ok()); &gt;+ assert!( &gt;+ parse_attribute("ssrc:2655508255 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}").is_ok() &gt;+ ); &gt; assert!(parse_attribute("ssrc:2082260239 msid:1d0cdb4e-5934-4f0f-9f88-40392cb60d31 315b086a-5cb6-4221-89de-caf0b038c79d") &gt; .is_ok()); &gt; &gt; assert!(parse_attribute("ssrc:").is_err()); &gt; assert!(parse_attribute("ssrc:foo").is_err()); &gt; } &gt; &gt; #[test] &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa/src/bin/file_parser.rs b/media/webrtc/signaling/src/sdp/rsdparsa/src/bin/file_parser.rs &gt;index 04ba61c81c9d..81caa1c31265 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/bin/file_parser.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/bin/file_parser.rs &gt;@@ -1,35 +1,31 @@ &gt;+use std::env; &gt; use std::error::Error; &gt;-use std::io::prelude::*; &gt; use std::fs::File; &gt;+use std::io::prelude::*; &gt; use std::path::Path; &gt;-use std::env; &gt; extern crate rsdparsa; &gt; &gt; fn main() { &gt; let filename = match env::args().nth(1) { &gt; None =&gt; { &gt; println!("Missing file name argument!"); &gt; return; &gt;- }, &gt;+ } &gt; Some(x) =&gt; x, &gt; }; &gt; let path = Path::new(filename.as_str()); &gt; let display = path.display(); &gt; &gt; let mut file = match File::open(&amp;path) { &gt;- Err(why) =&gt; panic!("Failed to open {}: {}", &gt;- display, &gt;- why.description()), &gt;- Ok(file) =&gt; file &gt;+ Err(why) =&gt; panic!("Failed to open {}: {}", display, why.description()), &gt;+ Ok(file) =&gt; file, &gt; }; &gt; &gt; let mut s = String::new(); &gt; match file.read_to_string(&amp;mut s) { &gt;- Err(why) =&gt; panic!("couldn't read {}: {}", &gt;- display, &gt;- why.description()), &gt;- Ok(s) =&gt; s &gt;+ Err(why) =&gt; panic!("couldn't read {}: {}", display, why.description()), &gt;+ Ok(s) =&gt; s, &gt; }; &gt; &gt; rsdparsa::parse_sdp(&amp;s, true).is_ok(); &gt; } &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa/src/error.rs b/media/webrtc/signaling/src/sdp/rsdparsa/src/error.rs &gt;index 9adea091f49d..66b71ff735b5 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/error.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/error.rs &gt;@@ -1,17 +1,16 @@ &gt;-use std::num::ParseIntError; &gt;-use std::num::ParseFloatError; &gt;-use std::net::AddrParseError; &gt;-use std::fmt; &gt;+#[cfg(feature = "serialize")] &gt;+use serde::ser::{Serialize, SerializeStruct, Serializer}; &gt; use std::error; &gt; use std::error::Error; &gt;-#[cfg(feature = "serialize")] &gt;-use serde::ser::{Serializer, Serialize, SerializeStruct}; &gt;- &gt;+use std::fmt; &gt;+use std::net::AddrParseError; &gt;+use std::num::ParseFloatError; &gt;+use std::num::ParseIntError; &gt; &gt; #[derive(Debug, Clone)] &gt; pub enum SdpParserInternalError { &gt; Generic(String), &gt; Unsupported(String), &gt; Integer(ParseIntError), &gt; Float(ParseFloatError), &gt; Address(AddrParseError), &gt;@@ -37,18 +36,18 @@ impl fmt::Display for SdpParserInternalError { &gt; } &gt; } &gt; } &gt; } &gt; &gt; impl error::Error for SdpParserInternalError { &gt; fn description(&amp;self) -&gt; &amp;str { &gt; match *self { &gt;- SdpParserInternalError::Generic(ref message) | &gt;- SdpParserInternalError::Unsupported(ref message) =&gt; message, &gt;+ SdpParserInternalError::Generic(ref message) &gt;+ | SdpParserInternalError::Unsupported(ref message) =&gt; message, &gt; SdpParserInternalError::Integer(ref error) =&gt; error.description(), &gt; SdpParserInternalError::Float(ref error) =&gt; error.description(), &gt; SdpParserInternalError::Address(ref error) =&gt; error.description(), &gt; } &gt; } &gt; &gt; fn cause(&amp;self) -&gt; Option&lt;&amp;error::Error&gt; { &gt; match *self { &gt;@@ -59,152 +58,179 @@ impl error::Error for SdpParserInternalError { &gt; _ =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; #[test] &gt; fn test_sdp_parser_internal_error_generic() { &gt; let generic = SdpParserInternalError::Generic("generic message".to_string()); &gt;- assert_eq!(format!("{}", generic), &gt;- "Generic parsing error: generic message"); &gt;+ assert_eq!( &gt;+ format!("{}", generic), &gt;+ "Generic parsing error: generic message" &gt;+ ); &gt; assert_eq!(generic.description(), "generic message"); &gt; assert!(generic.cause().is_none()); &gt; } &gt; &gt; #[test] &gt; fn test_sdp_parser_internal_error_unsupported() { &gt;- let unsupported = SdpParserInternalError::Unsupported("unsupported internal message" &gt;- .to_string()); &gt;- assert_eq!(format!("{}", unsupported), &gt;- "Unsupported parsing error: unsupported internal message"); &gt;+ let unsupported = &gt;+ SdpParserInternalError::Unsupported("unsupported internal message".to_string()); &gt;+ assert_eq!( &gt;+ format!("{}", unsupported), &gt;+ "Unsupported parsing error: unsupported internal message" &gt;+ ); &gt; assert_eq!(unsupported.description(), "unsupported internal message"); &gt; assert!(unsupported.cause().is_none()); &gt; } &gt; &gt; #[test] &gt; fn test_sdp_parser_internal_error_integer() { &gt; let v = "12a"; &gt; let integer = v.parse::&lt;u64&gt;(); &gt; assert!(integer.is_err()); &gt; let int_err = SdpParserInternalError::Integer(integer.err().unwrap()); &gt;- assert_eq!(format!("{}", int_err), &gt;- "Integer parsing error: invalid digit found in string"); &gt;+ assert_eq!( &gt;+ format!("{}", int_err), &gt;+ "Integer parsing error: invalid digit found in string" &gt;+ ); &gt; assert_eq!(int_err.description(), "invalid digit found in string"); &gt; assert!(!int_err.cause().is_none()); &gt; } &gt; &gt; #[test] &gt; fn test_sdp_parser_internal_error_address() { &gt; let v = "127.0.0.a"; &gt;- use std::str::FromStr; &gt; use std::net::IpAddr; &gt;+ use std::str::FromStr; &gt; let addr = IpAddr::from_str(v); &gt; assert!(addr.is_err()); &gt; let addr_err = SdpParserInternalError::Address(addr.err().unwrap()); &gt;- assert_eq!(format!("{}", addr_err), &gt;- "IP address parsing error: invalid IP address syntax"); &gt;+ assert_eq!( &gt;+ format!("{}", addr_err), &gt;+ "IP address parsing error: invalid IP address syntax" &gt;+ ); &gt; assert_eq!(addr_err.description(), "invalid IP address syntax"); &gt; assert!(!addr_err.cause().is_none()); &gt; } &gt; &gt; #[derive(Debug, Clone)] &gt; pub enum SdpParserError { &gt; Line { &gt; error: SdpParserInternalError, &gt; line: String, &gt; line_number: usize, &gt; }, &gt; Unsupported { &gt; error: SdpParserInternalError, &gt; line: String, &gt; line_number: usize, &gt; }, &gt;- Sequence { message: String, line_number: usize }, &gt;+ Sequence { &gt;+ message: String, &gt;+ line_number: usize, &gt;+ }, &gt; } &gt; &gt; #[cfg(feature = "serialize")] &gt; impl Serialize for SdpParserError { &gt;- fn serialize&lt;S&gt;(&amp;self, serializer: S) -&gt; Result&lt;S::Ok, S::Error&gt; where S: Serializer { &gt;- let mut state = serializer.serialize_struct("error", match self { &gt;- &amp;SdpParserError::Sequence{..} =&gt; 3, &gt;- _ =&gt; 4 &gt;- })?; &gt;+ fn serialize&lt;S&gt;(&amp;self, serializer: S) -&gt; Result&lt;S::Ok, S::Error&gt; &gt;+ where &gt;+ S: Serializer, &gt;+ { &gt;+ let mut state = serializer.serialize_struct( &gt;+ "error", &gt;+ match self { &gt;+ &amp;SdpParserError::Sequence { .. } =&gt; 3, &gt;+ _ =&gt; 4, &gt;+ }, &gt;+ )?; &gt; match self { &gt;- &amp;SdpParserError::Line {ref error, ref line, ..} =&gt; { &gt;+ &amp;SdpParserError::Line { &gt;+ ref error, &gt;+ ref line, &gt;+ .. &gt;+ } =&gt; { &gt; state.serialize_field("type", "Line")?; &gt; state.serialize_field("message", &amp;format!("{}", error))?; &gt; state.serialize_field("line", &amp;line)? &gt;- }, &gt;- &amp;SdpParserError::Unsupported {ref error, ref line, ..} =&gt; { &gt;+ } &gt;+ &amp;SdpParserError::Unsupported { &gt;+ ref error, &gt;+ ref line, &gt;+ .. &gt;+ } =&gt; { &gt; state.serialize_field("type", "Unsupported")?; &gt; state.serialize_field("message", &amp;format!("{}", error))?; &gt; state.serialize_field("line", &amp;line)? &gt;- }, &gt;- &amp;SdpParserError::Sequence {ref message, ..} =&gt; { &gt;+ } &gt;+ &amp;SdpParserError::Sequence { ref message, .. } =&gt; { &gt; state.serialize_field("type", "Sequence")?; &gt; state.serialize_field("message", &amp;message)?; &gt; } &gt; }; &gt;- state.serialize_field("line_number", &amp;match self { &gt;- &amp;SdpParserError::Line {line_number, ..} =&gt; line_number, &gt;- &amp;SdpParserError::Unsupported {line_number, ..} =&gt; line_number, &gt;- &amp;SdpParserError::Sequence {line_number, ..} =&gt; line_number, &gt;- })?; &gt;+ state.serialize_field( &gt;+ "line_number", &gt;+ &amp;match self { &gt;+ &amp;SdpParserError::Line { line_number, .. } =&gt; line_number, &gt;+ &amp;SdpParserError::Unsupported { line_number, .. } =&gt; line_number, &gt;+ &amp;SdpParserError::Sequence { line_number, .. } =&gt; line_number, &gt;+ }, &gt;+ )?; &gt; state.end() &gt; } &gt; } &gt; &gt; impl fmt::Display for SdpParserError { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; match *self { &gt; SdpParserError::Line { &gt; ref error, &gt; ref line, &gt; ref line_number, &gt;- } =&gt; { &gt;- write!(f, &gt;- "Line error: {} in line({}): {}", &gt;- error.description(), &gt;- line_number, &gt;- line) &gt;- } &gt;+ } =&gt; write!( &gt;+ f, &gt;+ "Line error: {} in line({}): {}", &gt;+ error.description(), &gt;+ line_number, &gt;+ line &gt;+ ), &gt; SdpParserError::Unsupported { &gt; ref error, &gt; ref line, &gt; ref line_number, &gt;- } =&gt; { &gt;- write!(f, &gt;- "Unsupported: {} in line({}): {}", &gt;- error.description(), &gt;- line_number, &gt;- line) &gt;- } &gt;+ } =&gt; write!( &gt;+ f, &gt;+ "Unsupported: {} in line({}): {}", &gt;+ error.description(), &gt;+ line_number, &gt;+ line &gt;+ ), &gt; SdpParserError::Sequence { &gt; ref message, &gt; ref line_number, &gt; } =&gt; write!(f, "Sequence error in line({}): {}", line_number, message), &gt; } &gt; } &gt; } &gt; &gt;- &gt; impl error::Error for SdpParserError { &gt; fn description(&amp;self) -&gt; &amp;str { &gt; match *self { &gt;- SdpParserError::Line { ref error, .. } | &gt;- SdpParserError::Unsupported { ref error, .. } =&gt; error.description(), &gt;+ SdpParserError::Line { ref error, .. } &gt;+ | SdpParserError::Unsupported { ref error, .. } =&gt; error.description(), &gt; SdpParserError::Sequence { ref message, .. } =&gt; message, &gt; } &gt; } &gt; &gt; fn cause(&amp;self) -&gt; Option&lt;&amp;error::Error&gt; { &gt; match *self { &gt;- SdpParserError::Line { ref error, .. } | &gt;- SdpParserError::Unsupported { ref error, .. } =&gt; Some(error), &gt;+ SdpParserError::Line { ref error, .. } &gt;+ | SdpParserError::Unsupported { ref error, .. } =&gt; Some(error), &gt; // Can't tell much more about our internal errors &gt; _ =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; impl From&lt;ParseIntError&gt; for SdpParserInternalError { &gt; fn from(err: ParseIntError) -&gt; SdpParserInternalError { &gt;@@ -226,38 +252,44 @@ impl From&lt;ParseFloatError&gt; for SdpParserInternalError { &gt; &gt; #[test] &gt; fn test_sdp_parser_error_line() { &gt; let line1 = SdpParserError::Line { &gt; error: SdpParserInternalError::Generic("test message".to_string()), &gt; line: "test line".to_string(), &gt; line_number: 13, &gt; }; &gt;- assert_eq!(format!("{}", line1), &gt;- "Line error: test message in line(13): test line"); &gt;+ assert_eq!( &gt;+ format!("{}", line1), &gt;+ "Line error: test message in line(13): test line" &gt;+ ); &gt; assert_eq!(line1.description(), "test message"); &gt; assert!(line1.cause().is_some()); &gt; } &gt; &gt; #[test] &gt; fn test_sdp_parser_error_unsupported() { &gt; let unsupported1 = SdpParserError::Unsupported { &gt; error: SdpParserInternalError::Generic("unsupported value".to_string()), &gt; line: "unsupported line".to_string(), &gt; line_number: 21, &gt; }; &gt;- assert_eq!(format!("{}", unsupported1), &gt;- "Unsupported: unsupported value in line(21): unsupported line"); &gt;+ assert_eq!( &gt;+ format!("{}", unsupported1), &gt;+ "Unsupported: unsupported value in line(21): unsupported line" &gt;+ ); &gt; assert_eq!(unsupported1.description(), "unsupported value"); &gt; assert!(unsupported1.cause().is_some()); &gt; } &gt; &gt; #[test] &gt; fn test_sdp_parser_error_sequence() { &gt; let sequence1 = SdpParserError::Sequence { &gt; message: "sequence message".to_string(), &gt; line_number: 42, &gt; }; &gt;- assert_eq!(format!("{}", sequence1), &gt;- "Sequence error in line(42): sequence message"); &gt;+ assert_eq!( &gt;+ format!("{}", sequence1), &gt;+ "Sequence error in line(42): sequence message" &gt;+ ); &gt; assert_eq!(sequence1.description(), "sequence message"); &gt; assert!(sequence1.cause().is_none()); &gt; } &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa/src/lib.rs b/media/webrtc/signaling/src/sdp/rsdparsa/src/lib.rs &gt;index cd1f851aab29..4e6a5672166e 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/lib.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/lib.rs &gt;@@ -1,82 +1,86 @@ &gt;-#![cfg_attr(feature="clippy", feature(plugin))] &gt;+#![cfg_attr(feature = "clippy", feature(plugin))] &gt; &gt; #[macro_use] &gt; extern crate log; &gt;-#[cfg(feature="serialize")] &gt;+#[cfg(feature = "serialize")] &gt; #[macro_use] &gt; extern crate serde_derive; &gt;-#[cfg(feature="serialize")] &gt;+#[cfg(feature = "serialize")] &gt; extern crate serde; &gt; &gt;+use std::fmt; &gt; use std::net::IpAddr; &gt; use std::str::FromStr; &gt;-use std::fmt; &gt; &gt; pub mod attribute_type; &gt; pub mod error; &gt; pub mod media_type; &gt; pub mod network; &gt; pub mod unsupported_types; &gt; &gt;-use attribute_type::{SdpAttribute, SdpSingleDirection, SdpAttributeType, parse_attribute, &gt;- SdpAttributeSimulcastVersion, SdpAttributeRid}; &gt;-use error::{SdpParserInternalError, SdpParserError}; &gt;-use media_type::{SdpMedia, SdpMediaLine, parse_media, parse_media_vector, SdpProtocolValue, &gt;- SdpMediaValue, SdpFormatList}; &gt;+use attribute_type::{ &gt;+ parse_attribute, SdpAttribute, SdpAttributeRid, SdpAttributeSimulcastVersion, SdpAttributeType, &gt;+ SdpSingleDirection, &gt;+}; &gt;+use error::{SdpParserError, SdpParserInternalError}; &gt;+use media_type::{ &gt;+ parse_media, parse_media_vector, SdpFormatList, SdpMedia, SdpMediaLine, SdpMediaValue, &gt;+ SdpProtocolValue, &gt;+}; &gt; use network::{parse_addrtype, parse_nettype, parse_unicast_addr}; &gt;-use unsupported_types::{parse_email, parse_information, parse_key, parse_phone, parse_repeat, &gt;- parse_uri, parse_zone}; &gt;+use unsupported_types::{ &gt;+ parse_email, parse_information, parse_key, parse_phone, parse_repeat, parse_uri, parse_zone, &gt;+}; &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpBandwidth { &gt; As(u32), &gt; Ct(u32), &gt; Tias(u32), &gt; Unknown(String, u32), &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpConnection { &gt; pub addr: IpAddr, &gt; pub ttl: Option&lt;u8&gt;, &gt; pub amount: Option&lt;u32&gt;, &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpOrigin { &gt; pub username: String, &gt; pub session_id: u64, &gt; pub session_version: u64, &gt; pub unicast_addr: IpAddr, &gt; } &gt; &gt; impl fmt::Display for SdpOrigin { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- write!(f, &gt;- "origin: {}, {}, {}, {}", &gt;- self.username, &gt;- self.session_id, &gt;- self.session_version, &gt;- self.unicast_addr) &gt;+ write!( &gt;+ f, &gt;+ "origin: {}, {}, {}, {}", &gt;+ self.username, self.session_id, self.session_version, self.unicast_addr &gt;+ ) &gt; } &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpTiming { &gt; pub start: u64, &gt; pub stop: u64, &gt; } &gt; &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpType { &gt; Attribute(SdpAttribute), &gt; Bandwidth(SdpBandwidth), &gt; Connection(SdpConnection), &gt; Email(String), &gt; Information(String), &gt; Key(String), &gt; Media(SdpMediaLine), &gt;@@ -85,41 +89,40 @@ pub enum SdpType { &gt; Repeat(String), &gt; Session(String), &gt; Timing(SdpTiming), &gt; Uri(String), &gt; Version(u64), &gt; Zone(String), &gt; } &gt; &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpLine { &gt; pub line_number: usize, &gt; pub sdp_type: SdpType, &gt; } &gt; &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpSession { &gt; pub version: u64, &gt; pub origin: SdpOrigin, &gt; pub session: String, &gt; pub connection: Option&lt;SdpConnection&gt;, &gt; pub bandwidth: Vec&lt;SdpBandwidth&gt;, &gt; pub timing: Option&lt;SdpTiming&gt;, &gt; pub attribute: Vec&lt;SdpAttribute&gt;, &gt; pub media: Vec&lt;SdpMedia&gt;, &gt;- pub warnings: Vec&lt;SdpParserError&gt; &gt;- // unsupported values: &gt;- // information: Option&lt;String&gt;, &gt;- // uri: Option&lt;String&gt;, &gt;- // email: Option&lt;String&gt;, &gt;- // phone: Option&lt;String&gt;, &gt;- // repeat: Option&lt;String&gt;, &gt;- // zone: Option&lt;String&gt;, &gt;- // key: Option&lt;String&gt;, &gt;+ pub warnings: Vec&lt;SdpParserError&gt;, // unsupported values: &gt;+ // information: Option&lt;String&gt;, &gt;+ // uri: Option&lt;String&gt;, &gt;+ // email: Option&lt;String&gt;, &gt;+ // phone: Option&lt;String&gt;, &gt;+ // repeat: Option&lt;String&gt;, &gt;+ // zone: Option&lt;String&gt;, &gt;+ // key: Option&lt;String&gt; &gt; } &gt; &gt; impl SdpSession { &gt; pub fn new(version: u64, origin: SdpOrigin, session: String) -&gt; SdpSession { &gt; SdpSession { &gt; version, &gt; origin, &gt; session, &gt;@@ -157,71 +160,82 @@ impl SdpSession { &gt; } &gt; &gt; pub fn set_timing(&amp;mut self, t: &amp;SdpTiming) { &gt; self.timing = Some(t.clone()) &gt; } &gt; &gt; pub fn add_attribute(&amp;mut self, a: &amp;SdpAttribute) -&gt; Result&lt;(), SdpParserInternalError&gt; { &gt; if !a.allowed_at_session_level() { &gt;- return Err(SdpParserInternalError::Generic(format!("{} not allowed at session level", &gt;- a))); &gt;+ return Err(SdpParserInternalError::Generic(format!( &gt;+ "{} not allowed at session level", &gt;+ a &gt;+ ))); &gt; }; &gt; Ok(self.attribute.push(a.clone())) &gt; } &gt; &gt; pub fn extend_media(&amp;mut self, v: Vec&lt;SdpMedia&gt;) { &gt; self.media.extend(v) &gt; } &gt; &gt; pub fn get_attribute(&amp;self, t: SdpAttributeType) -&gt; Option&lt;&amp;SdpAttribute&gt; { &gt;- self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).next() &gt;+ self.attribute &gt;+ .iter() &gt;+ .filter(|a| SdpAttributeType::from(*a) == t) &gt;+ .next() &gt; } &gt; &gt;- pub fn add_media(&amp;mut self, media_type: SdpMediaValue, direction: SdpAttribute, port: u32, &gt;- protocol: SdpProtocolValue, addr: String) &gt;- -&gt; Result&lt;(),SdpParserInternalError&gt; { &gt;- let mut media = SdpMedia::new(SdpMediaLine { &gt;- media: media_type, &gt;- port, &gt;- port_count: 1, &gt;- proto: protocol, &gt;- formats: SdpFormatList::Integers(Vec::new()), &gt;- }); &gt;+ pub fn add_media( &gt;+ &amp;mut self, &gt;+ media_type: SdpMediaValue, &gt;+ direction: SdpAttribute, &gt;+ port: u32, &gt;+ protocol: SdpProtocolValue, &gt;+ addr: String, &gt;+ ) -&gt; Result&lt;(), SdpParserInternalError&gt; { &gt;+ let mut media = SdpMedia::new(SdpMediaLine { &gt;+ media: media_type, &gt;+ port, &gt;+ port_count: 1, &gt;+ proto: protocol, &gt;+ formats: SdpFormatList::Integers(Vec::new()), &gt;+ }); &gt; &gt;- media.add_attribute(&amp;direction)?; &gt;+ media.add_attribute(&amp;direction)?; &gt; &gt;- media.set_connection(&amp;SdpConnection { &gt;- addr: IpAddr::from_str(addr.as_str())?, &gt;- ttl: None, &gt;- amount: None, &gt;- })?; &gt;+ media.set_connection(&amp;SdpConnection { &gt;+ addr: IpAddr::from_str(addr.as_str())?, &gt;+ ttl: None, &gt;+ amount: None, &gt;+ })?; &gt; &gt;- self.media.push(media); &gt;+ self.media.push(media); &gt; &gt;- Ok(()) &gt;+ Ok(()) &gt; } &gt; } &gt; &gt; fn parse_session(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; trace!("session: {}", value); &gt; Ok(SdpType::Session(String::from(value))) &gt; } &gt; &gt; #[test] &gt; fn test_session_works() { &gt; assert!(parse_session("topic").is_ok()); &gt; } &gt; &gt;- &gt; fn parse_version(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; let ver = value.parse::&lt;u64&gt;()?; &gt; if ver != 0 { &gt;- return Err(SdpParserInternalError::Generic(format!("version type contains unsupported value {}", &gt;- ver))); &gt;+ return Err(SdpParserInternalError::Generic(format!( &gt;+ "version type contains unsupported value {}", &gt;+ ver &gt;+ ))); &gt; }; &gt; trace!("version: {}", ver); &gt; Ok(SdpType::Version(ver)) &gt; } &gt; &gt; #[test] &gt; fn test_version_works() { &gt; assert!(parse_version("0").is_ok()); &gt;@@ -233,61 +247,66 @@ fn test_version_unsupported_input() { &gt; assert!(parse_version("11").is_err()); &gt; assert!(parse_version("a").is_err()); &gt; } &gt; &gt; fn parse_origin(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; let mut tokens = value.split_whitespace(); &gt; let username = match tokens.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Origin type is missing username token" &gt;- .to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Origin type is missing username token".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; x, &gt; }; &gt; let session_id = match tokens.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Origin type is missing session ID token" &gt;- .to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Origin type is missing session ID token".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; x.parse::&lt;u64&gt;()?, &gt; }; &gt; let session_version = match tokens.next() { &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Origin type is missing session version token" &gt;- .to_string())) &gt;+ "Origin type is missing session version token".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; x.parse::&lt;u64&gt;()?, &gt; }; &gt; match tokens.next() { &gt; None =&gt; { &gt; return Err(SdpParserInternalError::Generic( &gt;- "Origin type is missing session version token".to_string(), &gt;- )) &gt;+ "Origin type is missing session version token".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; parse_nettype(x)?, &gt; }; &gt; let addrtype = match tokens.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Origin type is missing address type token" &gt;- .to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Origin type is missing address type token".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; parse_addrtype(x)?, &gt; }; &gt; let unicast_addr = match tokens.next() { &gt; None =&gt; { &gt;- return Err(SdpParserInternalError::Generic("Origin type is missing IP address token" &gt;- .to_string())) &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Origin type is missing IP address token".to_string(), &gt;+ )) &gt; } &gt; Some(x) =&gt; parse_unicast_addr(x)?, &gt; }; &gt; if !addrtype.same_protocol(&amp;unicast_addr) { &gt;- return Err(SdpParserInternalError::Generic("Origin addrtype does not match address." &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "Origin addrtype does not match address.".to_string(), &gt;+ )); &gt; } &gt; let o = SdpOrigin { &gt; username: String::from(username), &gt; session_id, &gt; session_version, &gt; unicast_addr, &gt; }; &gt; trace!("origin: {}", o); &gt;@@ -325,36 +344,38 @@ fn test_origin_broken_ip_addr() { &gt; #[test] &gt; fn test_origin_addr_type_mismatch() { &gt; assert!(parse_origin("mozilla 506705521068071134 0 IN IP4 ::1").is_err()); &gt; } &gt; &gt; fn parse_connection(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; let cv: Vec&lt;&amp;str&gt; = value.split_whitespace().collect(); &gt; if cv.len() != 3 { &gt;- return Err(SdpParserInternalError::Generic("connection attribute must have three tokens" &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "connection attribute must have three tokens".to_string(), &gt;+ )); &gt; } &gt; parse_nettype(cv[0])?; &gt; let addrtype = parse_addrtype(cv[1])?; &gt; let mut ttl = None; &gt; let mut amount = None; &gt; let mut addr_token = cv[2]; &gt; if addr_token.find('/') != None { &gt; let addr_tokens: Vec&lt;&amp;str&gt; = addr_token.split('/').collect(); &gt; if addr_tokens.len() &gt;= 3 { &gt; amount = Some(addr_tokens[2].parse::&lt;u32&gt;()?); &gt; } &gt; ttl = Some(addr_tokens[1].parse::&lt;u8&gt;()?); &gt; addr_token = addr_tokens[0]; &gt; } &gt; let addr = parse_unicast_addr(addr_token)?; &gt; if !addrtype.same_protocol(&amp;addr) { &gt;- return Err(SdpParserInternalError::Generic("connection addrtype does not match address." &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "connection addrtype does not match address.".to_string(), &gt;+ )); &gt; } &gt; let c = SdpConnection { addr, ttl, amount }; &gt; trace!("connection: {}", c.addr); &gt; Ok(SdpType::Connection(c)) &gt; } &gt; &gt; #[test] &gt; fn connection_works() { &gt;@@ -392,18 +413,19 @@ fn connection_broken_ip_addr() { &gt; #[test] &gt; fn connection_addr_type_mismatch() { &gt; assert!(parse_connection("IN IP4 ::1").is_err()); &gt; } &gt; &gt; fn parse_bandwidth(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; let bv: Vec&lt;&amp;str&gt; = value.split(':').collect(); &gt; if bv.len() != 2 { &gt;- return Err(SdpParserInternalError::Generic("bandwidth attribute must have two tokens" &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "bandwidth attribute must have two tokens".to_string(), &gt;+ )); &gt; } &gt; let bandwidth = bv[1].parse::&lt;u32&gt;()?; &gt; let bw = match bv[0].to_uppercase().as_ref() { &gt; "AS" =&gt; SdpBandwidth::As(bandwidth), &gt; "CT" =&gt; SdpBandwidth::Ct(bandwidth), &gt; "TIAS" =&gt; SdpBandwidth::Tias(bandwidth), &gt; _ =&gt; SdpBandwidth::Unknown(String::from(bv[0]), bandwidth), &gt; }; &gt;@@ -427,18 +449,19 @@ fn bandwidth_wrong_amount_of_tokens() { &gt; #[test] &gt; fn bandwidth_unsupported_type() { &gt; assert!(parse_bandwidth("UNSUPPORTED:12345").is_ok()); &gt; } &gt; &gt; fn parse_timing(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; let tv: Vec&lt;&amp;str&gt; = value.split_whitespace().collect(); &gt; if tv.len() != 2 { &gt;- return Err(SdpParserInternalError::Generic("timing attribute must have two tokens" &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "timing attribute must have two tokens".to_string(), &gt;+ )); &gt; } &gt; let start = tv[0].parse::&lt;u64&gt;()?; &gt; let stop = tv[1].parse::&lt;u64&gt;()?; &gt; let t = SdpTiming { start, stop }; &gt; trace!("timing: {}, {}", t.start, t.stop); &gt; Ok(SdpType::Timing(t)) &gt; } &gt; &gt;@@ -457,113 +480,106 @@ fn test_timing_non_numeric_tokens() { &gt; fn test_timing_wrong_amount_of_tokens() { &gt; assert!(parse_timing("0").is_err()); &gt; assert!(parse_timing("0 0 0").is_err()); &gt; } &gt; &gt; fn parse_sdp_line(line: &amp;str, line_number: usize) -&gt; Result&lt;SdpLine, SdpParserError&gt; { &gt; if line.find('=') == None { &gt; return Err(SdpParserError::Line { &gt;- error: SdpParserInternalError::Generic("missing = character in line" &gt;- .to_string()), &gt;- line: line.to_string(), &gt;- line_number: line_number, &gt;- }); &gt;+ error: SdpParserInternalError::Generic("missing = character in line".to_string()), &gt;+ line: line.to_string(), &gt;+ line_number: line_number, &gt;+ }); &gt; } &gt; let mut splitted_line = line.splitn(2, '='); &gt; let line_type = match splitted_line.next() { &gt; None =&gt; { &gt; return Err(SdpParserError::Line { &gt;- error: SdpParserInternalError::Generic("missing type".to_string()), &gt;- line: line.to_string(), &gt;- line_number: line_number, &gt;- }) &gt;+ error: SdpParserInternalError::Generic("missing type".to_string()), &gt;+ line: line.to_string(), &gt;+ line_number: line_number, &gt;+ }) &gt; } &gt; Some(t) =&gt; { &gt; let trimmed = t.trim(); &gt; if trimmed.len() &gt; 1 { &gt; return Err(SdpParserError::Line { &gt;- error: SdpParserInternalError::Generic("type too long".to_string()), &gt;- line: line.to_string(), &gt;- line_number: line_number, &gt;- }); &gt;+ error: SdpParserInternalError::Generic("type too long".to_string()), &gt;+ line: line.to_string(), &gt;+ line_number: line_number, &gt;+ }); &gt; } &gt; if trimmed.is_empty() { &gt; return Err(SdpParserError::Line { &gt;- error: SdpParserInternalError::Generic("type is empty".to_string()), &gt;- line: line.to_string(), &gt;- line_number: line_number, &gt;- }); &gt;+ error: SdpParserInternalError::Generic("type is empty".to_string()), &gt;+ line: line.to_string(), &gt;+ line_number: line_number, &gt;+ }); &gt; } &gt; trimmed &gt; } &gt; }; &gt; let line_value = match splitted_line.next() { &gt; None =&gt; { &gt; return Err(SdpParserError::Line { &gt;- error: SdpParserInternalError::Generic("missing value".to_string()), &gt;- line: line.to_string(), &gt;- line_number: line_number, &gt;- }) &gt;+ error: SdpParserInternalError::Generic("missing value".to_string()), &gt;+ line: line.to_string(), &gt;+ line_number: line_number, &gt;+ }) &gt; } &gt; Some(v) =&gt; { &gt; let trimmed = v.trim(); &gt; if trimmed.is_empty() { &gt; return Err(SdpParserError::Line { &gt;- error: SdpParserInternalError::Generic("value is empty".to_string()), &gt;- line: line.to_string(), &gt;- line_number: line_number, &gt;- }); &gt;+ error: SdpParserInternalError::Generic("value is empty".to_string()), &gt;+ line: line.to_string(), &gt;+ line_number: line_number, &gt;+ }); &gt; } &gt; trimmed &gt; } &gt; }; &gt; match line_type.to_lowercase().as_ref() { &gt;- "a" =&gt; parse_attribute(line_value), &gt;- "b" =&gt; parse_bandwidth(line_value), &gt;- "c" =&gt; parse_connection(line_value), &gt;- "e" =&gt; parse_email(line_value), &gt;- "i" =&gt; parse_information(line_value), &gt;- "k" =&gt; parse_key(line_value), &gt;- "m" =&gt; parse_media(line_value), &gt;- "o" =&gt; parse_origin(line_value), &gt;- "p" =&gt; parse_phone(line_value), &gt;- "r" =&gt; parse_repeat(line_value), &gt;- "s" =&gt; parse_session(line_value), &gt;- "t" =&gt; parse_timing(line_value), &gt;- "u" =&gt; parse_uri(line_value), &gt;- "v" =&gt; parse_version(line_value), &gt;- "z" =&gt; parse_zone(line_value), &gt;- _ =&gt; Err(SdpParserInternalError::Generic("unknown sdp type".to_string())), &gt;- } &gt;- .map(|sdp_type| { &gt;- SdpLine { &gt;- line_number, &gt;- sdp_type, &gt;- } &gt;- }) &gt;- .map_err(|e| match e { &gt;- SdpParserInternalError::Generic(..) | &gt;- SdpParserInternalError::Integer(..) | &gt;- SdpParserInternalError::Float(..) | &gt;- SdpParserInternalError::Address(..) =&gt; { &gt;- SdpParserError::Line { &gt;- error: e, &gt;- line: line.to_string(), &gt;- line_number: line_number, &gt;- } &gt;- } &gt;- SdpParserInternalError::Unsupported(..) =&gt; { &gt;- SdpParserError::Unsupported { &gt;- error: e, &gt;- line: line.to_string(), &gt;- line_number: line_number, &gt;- } &gt;- } &gt;- }) &gt;+ "a" =&gt; parse_attribute(line_value), &gt;+ "b" =&gt; parse_bandwidth(line_value), &gt;+ "c" =&gt; parse_connection(line_value), &gt;+ "e" =&gt; parse_email(line_value), &gt;+ "i" =&gt; parse_information(line_value), &gt;+ "k" =&gt; parse_key(line_value), &gt;+ "m" =&gt; parse_media(line_value), &gt;+ "o" =&gt; parse_origin(line_value), &gt;+ "p" =&gt; parse_phone(line_value), &gt;+ "r" =&gt; parse_repeat(line_value), &gt;+ "s" =&gt; parse_session(line_value), &gt;+ "t" =&gt; parse_timing(line_value), &gt;+ "u" =&gt; parse_uri(line_value), &gt;+ "v" =&gt; parse_version(line_value), &gt;+ "z" =&gt; parse_zone(line_value), &gt;+ _ =&gt; Err(SdpParserInternalError::Generic( &gt;+ "unknown sdp type".to_string(), &gt;+ )), &gt;+ }.map(|sdp_type| SdpLine { &gt;+ line_number, &gt;+ sdp_type, &gt;+ }).map_err(|e| match e { &gt;+ SdpParserInternalError::Generic(..) &gt;+ | SdpParserInternalError::Integer(..) &gt;+ | SdpParserInternalError::Float(..) &gt;+ | SdpParserInternalError::Address(..) =&gt; SdpParserError::Line { &gt;+ error: e, &gt;+ line: line.to_string(), &gt;+ line_number: line_number, &gt;+ }, &gt;+ SdpParserInternalError::Unsupported(..) =&gt; SdpParserError::Unsupported { &gt;+ error: e, &gt;+ line: line.to_string(), &gt;+ line_number: line_number, &gt;+ }, &gt;+ }) &gt; } &gt; &gt; #[test] &gt; fn test_parse_sdp_line_works() { &gt; assert!(parse_sdp_line("v=0", 0).is_ok()); &gt; assert!(parse_sdp_line("s=somesession", 0).is_ok()); &gt; } &gt; &gt;@@ -613,122 +629,131 @@ fn test_parse_sdp_line_invalid_a_line() { &gt; fn sanity_check_sdp_session(session: &amp;SdpSession) -&gt; Result&lt;(), SdpParserError&gt; { &gt; let make_error = |x: &amp;str| SdpParserError::Sequence { &gt; message: x.to_string(), &gt; line_number: 0, &gt; }; &gt; &gt; if !session.timing.is_some() { &gt; return Err(SdpParserError::Sequence { &gt;- message: "Missing timing type".to_string(), &gt;- line_number: 0, &gt;- }); &gt;+ message: "Missing timing type".to_string(), &gt;+ line_number: 0, &gt;+ }); &gt; } &gt; &gt; if session.media.is_empty() { &gt; return Err(SdpParserError::Sequence { &gt;- message: "Missing media section".to_string(), &gt;- line_number: 0, &gt;- }); &gt;+ message: "Missing media section".to_string(), &gt;+ line_number: 0, &gt;+ }); &gt; } &gt; &gt; if session.get_connection().is_none() { &gt; for msection in &amp;session.media { &gt; if msection.get_connection().is_none() { &gt; return Err(SdpParserError::Sequence { &gt; message: "Each media section must define a connection &gt;- if it is not defined on session level".to_string(), &gt;+ if it is not defined on session level" &gt;+ .to_string(), &gt; line_number: 0, &gt; }); &gt; } &gt; } &gt; } &gt; &gt; // Check that extmaps are not defined on session and media level &gt; if session.get_attribute(SdpAttributeType::Extmap).is_some() { &gt; for msection in &amp;session.media { &gt; if msection.get_attribute(SdpAttributeType::Extmap).is_some() { &gt; return Err(SdpParserError::Sequence { &gt;- message: "Extmap can't be define at session and media level" &gt;- .to_string(), &gt;- line_number: 0, &gt;- }); &gt;+ message: "Extmap can't be define at session and media level".to_string(), &gt;+ line_number: 0, &gt;+ }); &gt; } &gt; } &gt; } &gt; &gt; for msection in &amp;session.media { &gt; if msection.get_attribute(SdpAttributeType::Sendonly).is_some() { &gt;- if let Some(&amp;SdpAttribute::Simulcast(ref x)) = msection.get_attribute(SdpAttributeType::Simulcast) { &gt;+ if let Some(&amp;SdpAttribute::Simulcast(ref x)) = &gt;+ msection.get_attribute(SdpAttributeType::Simulcast) &gt;+ { &gt; if x.receive.len() &gt; 0 { &gt; return Err(SdpParserError::Sequence { &gt;- message: "Simulcast can't define receive parameters for sendonly".to_string(), &gt;+ message: "Simulcast can't define receive parameters for sendonly" &gt;+ .to_string(), &gt; line_number: 0, &gt; }); &gt; } &gt; } &gt; } &gt; if msection.get_attribute(SdpAttributeType::Recvonly).is_some() { &gt;- if let Some(&amp;SdpAttribute::Simulcast(ref x)) = msection.get_attribute(SdpAttributeType::Simulcast) { &gt;+ if let Some(&amp;SdpAttribute::Simulcast(ref x)) = &gt;+ msection.get_attribute(SdpAttributeType::Simulcast) &gt;+ { &gt; if x.send.len() &gt; 0 { &gt; return Err(SdpParserError::Sequence { &gt; message: "Simulcast can't define send parameters for recvonly".to_string(), &gt; line_number: 0, &gt; }); &gt; } &gt; } &gt; } &gt; &gt;- let rids:Vec&lt;&amp;SdpAttributeRid&gt; = msection.get_attributes().iter().filter_map(|attr| { &gt;- match attr { &gt;- &amp;SdpAttribute::Rid(ref rid) =&gt; Some(rid), &gt;- _ =&gt; None, &gt;- } &gt;- }).collect(); &gt;- let recv_rids:Vec&lt;&amp;str&gt; = rids.iter().filter_map(|rid| { &gt;- match rid.direction { &gt;- SdpSingleDirection::Recv =&gt; Some(rid.id.as_str()), &gt;- _ =&gt; None, &gt;- } &gt;- }).collect(); &gt;- let send_rids:Vec&lt;&amp;str&gt; = rids.iter().filter_map(|rid| { &gt;- match rid.direction { &gt;- SdpSingleDirection::Send =&gt; Some(rid.id.as_str()), &gt;- _ =&gt; None, &gt;- } &gt;- }).collect(); &gt;- &gt;+ let rids: Vec&lt;&amp;SdpAttributeRid&gt; = msection &gt;+ .get_attributes() &gt;+ .iter() &gt;+ .filter_map(|attr| match attr { &gt;+ &amp;SdpAttribute::Rid(ref rid) =&gt; Some(rid), &gt;+ _ =&gt; None, &gt;+ }).collect(); &gt;+ let recv_rids: Vec&lt;&amp;str&gt; = rids &gt;+ .iter() &gt;+ .filter_map(|rid| match rid.direction { &gt;+ SdpSingleDirection::Recv =&gt; Some(rid.id.as_str()), &gt;+ _ =&gt; None, &gt;+ }).collect(); &gt;+ let send_rids: Vec&lt;&amp;str&gt; = rids &gt;+ .iter() &gt;+ .filter_map(|rid| match rid.direction { &gt;+ SdpSingleDirection::Send =&gt; Some(rid.id.as_str()), &gt;+ _ =&gt; None, &gt;+ }).collect(); &gt; &gt; for rid_format in rids.iter().flat_map(|rid| &amp;rid.formats) { &gt; match msection.get_formats() { &gt; &amp;SdpFormatList::Integers(ref int_fmt) =&gt; { &gt;- if !int_fmt.contains(&amp;(*rid_format as u32)) { &gt;+ if !int_fmt.contains(&amp;(*rid_format as u32)) { &gt; return Err(make_error("Rid pts must be declared in the media section")); &gt; } &gt;- }, &gt;+ } &gt; &amp;SdpFormatList::Strings(ref str_fmt) =&gt; { &gt;- if !str_fmt.contains(&amp;rid_format.to_string()) { &gt;+ if !str_fmt.contains(&amp;rid_format.to_string()) { &gt; return Err(make_error("Rid pts must be declared in the media section")); &gt; } &gt; } &gt; } &gt; } &gt; &gt; if let Some(&amp;SdpAttribute::Simulcast(ref simulcast)) = &gt;- msection.get_attribute(SdpAttributeType::Simulcast) { &gt;- let check_defined_rids = |simulcast_version_list: &amp;Vec&lt;SdpAttributeSimulcastVersion&gt;, &gt;- rid_ids: &amp;[&amp;str]| -&gt; Result&lt;(),SdpParserError&gt; { &gt;- for simulcast_rid in simulcast_version_list.iter().flat_map(|x| &amp;x.ids) { &gt;- if !rid_ids.contains(&amp;simulcast_rid.id.as_str()) { &gt;- return Err(make_error( &gt;- "Simulcast RIDs must be defined in any rid attribute")); &gt;+ msection.get_attribute(SdpAttributeType::Simulcast) &gt;+ { &gt;+ let check_defined_rids = &gt;+ |simulcast_version_list: &amp;Vec&lt;SdpAttributeSimulcastVersion&gt;, &gt;+ rid_ids: &amp;[&amp;str]| &gt;+ -&gt; Result&lt;(), SdpParserError&gt; { &gt;+ for simulcast_rid in simulcast_version_list.iter().flat_map(|x| &amp;x.ids) { &gt;+ if !rid_ids.contains(&amp;simulcast_rid.id.as_str()) { &gt;+ return Err(make_error( &gt;+ "Simulcast RIDs must be defined in any rid attribute", &gt;+ )); &gt;+ } &gt; } &gt;- } &gt;- Ok(()) &gt;- }; &gt;+ Ok(()) &gt;+ }; &gt; &gt; check_defined_rids(&amp;simulcast.receive, &amp;recv_rids)?; &gt; check_defined_rids(&amp;simulcast.send, &amp;send_rids)?; &gt; } &gt; } &gt; &gt; Ok(()) &gt; } &gt;@@ -785,41 +810,51 @@ fn test_sanity_check_sdp_session_media() { &gt; &gt; #[test] &gt; fn test_sanity_check_sdp_session_extmap() { &gt; let mut sdp_session = create_dummy_sdp_session(); &gt; let t = SdpTiming { start: 0, stop: 0 }; &gt; sdp_session.set_timing(&amp;t); &gt; sdp_session.extend_media(vec![create_dummy_media_section()]); &gt; &gt;- let attribute = parse_attribute("extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time",); &gt;+ let attribute = &gt;+ parse_attribute("extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"); &gt; assert!(attribute.is_ok()); &gt; let extmap; &gt; if let SdpType::Attribute(a) = attribute.unwrap() { &gt; extmap = a; &gt; } else { &gt; panic!("SdpType is not Attribute"); &gt; } &gt; let ret = sdp_session.add_attribute(&amp;extmap); &gt; assert!(ret.is_ok()); &gt;- assert!(sdp_session.get_attribute(SdpAttributeType::Extmap).is_some()); &gt;+ assert!( &gt;+ sdp_session &gt;+ .get_attribute(SdpAttributeType::Extmap) &gt;+ .is_some() &gt;+ ); &gt; &gt; assert!(sanity_check_sdp_session(&amp;sdp_session).is_ok()); &gt; &gt;- let mattribute = parse_attribute("extmap:1/sendonly urn:ietf:params:rtp-hdrext:ssrc-audio-level",); &gt;+ let mattribute = &gt;+ parse_attribute("extmap:1/sendonly urn:ietf:params:rtp-hdrext:ssrc-audio-level"); &gt; assert!(mattribute.is_ok()); &gt; let mextmap; &gt; if let SdpType::Attribute(ma) = mattribute.unwrap() { &gt; mextmap = ma; &gt; } else { &gt; panic!("SdpType is not Attribute"); &gt; } &gt; let mut second_media = create_dummy_media_section(); &gt; assert!(second_media.add_attribute(&amp;mextmap).is_ok()); &gt;- assert!(second_media.get_attribute(SdpAttributeType::Extmap).is_some()); &gt;+ assert!( &gt;+ second_media &gt;+ .get_attribute(SdpAttributeType::Extmap) &gt;+ .is_some() &gt;+ ); &gt; &gt; sdp_session.extend_media(vec![second_media]); &gt; assert!(sdp_session.media.len() == 2); &gt; &gt; assert!(sanity_check_sdp_session(&amp;sdp_session).is_err()); &gt; &gt; sdp_session.attribute = Vec::new(); &gt; &gt;@@ -835,106 +870,101 @@ fn test_sanity_check_sdp_session_simulcast() { &gt; &gt; assert!(sanity_check_sdp_session(&amp;sdp_session).is_ok()); &gt; } &gt; &gt; // TODO add unit tests &gt; fn parse_sdp_vector(lines: &amp;[SdpLine]) -&gt; Result&lt;SdpSession, SdpParserError&gt; { &gt; if lines.len() &lt; 5 { &gt; return Err(SdpParserError::Sequence { &gt;- message: "SDP neeeds at least 5 lines".to_string(), &gt;- line_number: 0, &gt;- }); &gt;+ message: "SDP neeeds at least 5 lines".to_string(), &gt;+ line_number: 0, &gt;+ }); &gt; } &gt; &gt; // TODO are these mataches really the only way to verify the types? &gt; let version: u64 = match lines[0].sdp_type { &gt; SdpType::Version(v) =&gt; v, &gt; _ =&gt; { &gt; return Err(SdpParserError::Sequence { &gt;- message: "first line needs to be version number".to_string(), &gt;- line_number: lines[0].line_number, &gt;- }) &gt;+ message: "first line needs to be version number".to_string(), &gt;+ line_number: lines[0].line_number, &gt;+ }) &gt; } &gt; }; &gt; let origin: SdpOrigin = match lines[1].sdp_type { &gt; SdpType::Origin(ref v) =&gt; v.clone(), &gt; _ =&gt; { &gt; return Err(SdpParserError::Sequence { &gt;- message: "second line needs to be origin".to_string(), &gt;- line_number: lines[1].line_number, &gt;- }) &gt;+ message: "second line needs to be origin".to_string(), &gt;+ line_number: lines[1].line_number, &gt;+ }) &gt; } &gt; }; &gt; let session: String = match lines[2].sdp_type { &gt; SdpType::Session(ref v) =&gt; v.clone(), &gt; _ =&gt; { &gt; return Err(SdpParserError::Sequence { &gt;- message: "third line needs to be session".to_string(), &gt;- line_number: lines[2].line_number, &gt;- }) &gt;+ message: "third line needs to be session".to_string(), &gt;+ line_number: lines[2].line_number, &gt;+ }) &gt; } &gt; }; &gt; let mut sdp_session = SdpSession::new(version, origin, session); &gt; for (index, line) in lines.iter().enumerate().skip(3) { &gt; match line.sdp_type { &gt; SdpType::Attribute(ref a) =&gt; { &gt; sdp_session &gt; .add_attribute(a) &gt;- .map_err(|e: SdpParserInternalError| { &gt;- SdpParserError::Sequence { &gt;- message: format!("{}", e), &gt;- line_number: line.line_number, &gt;- } &gt;- })? &gt;+ .map_err(|e: SdpParserInternalError| SdpParserError::Sequence { &gt;+ message: format!("{}", e), &gt;+ line_number: line.line_number, &gt;+ })? &gt; } &gt; SdpType::Bandwidth(ref b) =&gt; sdp_session.add_bandwidth(b), &gt; SdpType::Timing(ref t) =&gt; sdp_session.set_timing(t), &gt; SdpType::Connection(ref c) =&gt; sdp_session.set_connection(c), &gt; SdpType::Media(_) =&gt; sdp_session.extend_media(parse_media_vector(&amp;lines[index..])?), &gt;- SdpType::Origin(_) | &gt;- SdpType::Session(_) | &gt;- SdpType::Version(_) =&gt; { &gt;+ SdpType::Origin(_) | SdpType::Session(_) | SdpType::Version(_) =&gt; { &gt; return Err(SdpParserError::Sequence { &gt;- message: "version, origin or session at wrong level".to_string(), &gt;- line_number: line.line_number, &gt;- }) &gt;+ message: "version, origin or session at wrong level".to_string(), &gt;+ line_number: line.line_number, &gt;+ }) &gt; } &gt; // the line parsers throw unsupported errors for these already &gt;- SdpType::Email(_) | &gt;- SdpType::Information(_) | &gt;- SdpType::Key(_) | &gt;- SdpType::Phone(_) | &gt;- SdpType::Repeat(_) | &gt;- SdpType::Uri(_) | &gt;- SdpType::Zone(_) =&gt; (), &gt;+ SdpType::Email(_) &gt;+ | SdpType::Information(_) &gt;+ | SdpType::Key(_) &gt;+ | SdpType::Phone(_) &gt;+ | SdpType::Repeat(_) &gt;+ | SdpType::Uri(_) &gt;+ | SdpType::Zone(_) =&gt; (), &gt; }; &gt; if !sdp_session.media.is_empty() { &gt; break; &gt; }; &gt; } &gt; sanity_check_sdp_session(&amp;sdp_session)?; &gt; Ok(sdp_session) &gt; } &gt; &gt; pub fn parse_sdp(sdp: &amp;str, fail_on_warning: bool) -&gt; Result&lt;SdpSession, SdpParserError&gt; { &gt; if sdp.is_empty() { &gt; return Err(SdpParserError::Line { &gt;- error: SdpParserInternalError::Generic("empty SDP".to_string()), &gt;- line: sdp.to_string(), &gt;- line_number: 0, &gt;- }); &gt;+ error: SdpParserInternalError::Generic("empty SDP".to_string()), &gt;+ line: sdp.to_string(), &gt;+ line_number: 0, &gt;+ }); &gt; } &gt; if sdp.len() &lt; 62 { &gt; return Err(SdpParserError::Line { &gt;- error: SdpParserInternalError::Generic("string to short to be valid SDP" &gt;- .to_string()), &gt;- line: sdp.to_string(), &gt;- line_number: 0, &gt;- }); &gt;+ error: SdpParserInternalError::Generic("string to short to be valid SDP".to_string()), &gt;+ line: sdp.to_string(), &gt;+ line_number: 0, &gt;+ }); &gt; } &gt; let lines = sdp.lines(); &gt; let mut errors: Vec&lt;SdpParserError&gt; = Vec::new(); &gt; let mut warnings: Vec&lt;SdpParserError&gt; = Vec::new(); &gt; let mut sdp_lines: Vec&lt;SdpLine&gt; = Vec::new(); &gt; for (line_number, line) in lines.enumerate() { &gt; let stripped_line = line.trim(); &gt; if stripped_line.is_empty() { &gt;@@ -946,43 +976,39 @@ pub fn parse_sdp(sdp: &amp;str, fail_on_warning: bool) -&gt; Result&lt;SdpSession, SdpPars &gt; } &gt; Err(e) =&gt; { &gt; match e { &gt; // FIXME is this really a good way to accomplish this? &gt; SdpParserError::Line { &gt; error, &gt; line, &gt; line_number, &gt;- } =&gt; { &gt;- errors.push(SdpParserError::Line { &gt;- error, &gt;- line, &gt;- line_number, &gt;- }) &gt;- } &gt;+ } =&gt; errors.push(SdpParserError::Line { &gt;+ error, &gt;+ line, &gt;+ line_number, &gt;+ }), &gt; SdpParserError::Unsupported { &gt; error, &gt; line, &gt; line_number, &gt; } =&gt; { &gt; warnings.push(SdpParserError::Unsupported { &gt;- error, &gt;- line, &gt;- line_number, &gt;- }); &gt;+ error, &gt;+ line, &gt;+ line_number, &gt;+ }); &gt; } &gt; SdpParserError::Sequence { &gt; message, &gt; line_number, &gt;- } =&gt; { &gt;- errors.push(SdpParserError::Sequence { &gt;- message, &gt;- line_number, &gt;- }) &gt;- } &gt;+ } =&gt; errors.push(SdpParserError::Sequence { &gt;+ message, &gt;+ line_number, &gt;+ }), &gt; } &gt; } &gt; }; &gt; } &gt; &gt; if fail_on_warning &amp;&amp; (warnings.len() &gt; 0) { &gt; return Err(warnings[0].clone()); &gt; } &gt;@@ -1009,98 +1035,122 @@ fn test_parse_sdp_zero_length_string_fails() { &gt; &gt; #[test] &gt; fn test_parse_sdp_to_short_string() { &gt; assert!(parse_sdp("fooooobarrrr", true).is_err()); &gt; } &gt; &gt; #[test] &gt; fn test_parse_sdp_line_error() { &gt;- assert!(parse_sdp("v=0\r\n &gt;+ assert!( &gt;+ parse_sdp( &gt;+ "v=0\r\n &gt; o=- 0 0 IN IP4 0.0.0.0\r\n &gt; s=-\r\n &gt; t=0 foobar\r\n &gt; m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n", &gt;- true) &gt;- .is_err()); &gt;+ true &gt;+ ).is_err() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn test_parse_sdp_unsupported_error() { &gt;- assert!(parse_sdp("v=0\r\n &gt;+ assert!( &gt;+ parse_sdp( &gt;+ "v=0\r\n &gt; o=- 0 0 IN IP4 0.0.0.0\r\n &gt; s=-\r\n &gt; t=0 0\r\n &gt; m=foobar 0 UDP/TLS/RTP/SAVPF 0\r\n", &gt;- true) &gt;- .is_err()); &gt;+ true &gt;+ ).is_err() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn test_parse_sdp_unsupported_warning() { &gt;- assert!(parse_sdp("v=0\r\n &gt;+ assert!( &gt;+ parse_sdp( &gt;+ "v=0\r\n &gt; o=- 0 0 IN IP4 0.0.0.0\r\n &gt; s=-\r\n &gt; c=IN IP4 198.51.100.7\r\n &gt; t=0 0\r\n &gt; m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n &gt; a=unsupported\r\n", &gt;- false) &gt;- .is_ok()); &gt;+ false &gt;+ ).is_ok() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn test_parse_sdp_sequence_error() { &gt;- assert!(parse_sdp("v=0\r\n &gt;+ assert!( &gt;+ parse_sdp( &gt;+ "v=0\r\n &gt; o=- 0 0 IN IP4 0.0.0.0\r\n &gt; t=0 0\r\n &gt; s=-\r\n &gt; m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n", &gt;- true) &gt;- .is_err()); &gt;+ true &gt;+ ).is_err() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn test_parse_sdp_integer_error() { &gt;- assert!(parse_sdp("v=0\r\n &gt;+ assert!( &gt;+ parse_sdp( &gt;+ "v=0\r\n &gt; o=- 0 0 IN IP4 0.0.0.0\r\n &gt; s=-\r\n &gt; t=0 0\r\n &gt; m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n &gt; a=rtcp:34er21\r\n", &gt;- true) &gt;- .is_err()); &gt;+ true &gt;+ ).is_err() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn test_parse_sdp_ipaddr_error() { &gt;- assert!(parse_sdp("v=0\r\n &gt;+ assert!( &gt;+ parse_sdp( &gt;+ "v=0\r\n &gt; o=- 0 0 IN IP4 0.a.b.0\r\n &gt; s=-\r\n &gt; t=0 0\r\n &gt; m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n", &gt;- true) &gt;- .is_err()); &gt;+ true &gt;+ ).is_err() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn test_parse_sdp_invalid_session_attribute() { &gt;- assert!(parse_sdp("v=0\r\n &gt;+ assert!( &gt;+ parse_sdp( &gt;+ "v=0\r\n &gt; o=- 0 0 IN IP4 0.a.b.0\r\n &gt; s=-\r\n &gt; t=0 0\r\n &gt; a=bundle-only\r\n &gt; m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n", &gt;- true) &gt;- .is_err()); &gt;+ true &gt;+ ).is_err() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn test_parse_sdp_invalid_media_attribute() { &gt;- assert!(parse_sdp("v=0\r\n &gt;+ assert!( &gt;+ parse_sdp( &gt;+ "v=0\r\n &gt; o=- 0 0 IN IP4 0.a.b.0\r\n &gt; s=-\r\n &gt; t=0 0\r\n &gt; m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n &gt; a=ice-lite\r\n", &gt;- true) &gt;- .is_err()); &gt;+ true &gt;+ ).is_err() &gt;+ ); &gt; } &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa/src/media_type.rs b/media/webrtc/signaling/src/sdp/rsdparsa/src/media_type.rs &gt;index 457c035c5e01..b4b9252962a4 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/media_type.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/media_type.rs &gt;@@ -1,25 +1,25 @@ &gt;-use std::fmt; &gt;-use {SdpType, SdpLine, SdpBandwidth, SdpConnection}; &gt;-use attribute_type::{SdpAttribute, SdpAttributeType, SdpAttributeRtpmap, SdpAttributeSctpmap}; &gt;+use attribute_type::{SdpAttribute, SdpAttributeRtpmap, SdpAttributeSctpmap, SdpAttributeType}; &gt; use error::{SdpParserError, SdpParserInternalError}; &gt;+use std::fmt; &gt;+use {SdpBandwidth, SdpConnection, SdpLine, SdpType}; &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpMediaLine { &gt; pub media: SdpMediaValue, &gt; pub port: u32, &gt; pub port_count: u32, &gt; pub proto: SdpProtocolValue, &gt; pub formats: SdpFormatList, &gt; } &gt; &gt;-#[derive(Clone,Debug,PartialEq)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[derive(Clone, Debug, PartialEq)] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpMediaValue { &gt; Audio, &gt; Video, &gt; Application, &gt; } &gt; &gt; impl fmt::Display for SdpMediaValue { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;@@ -27,18 +27,18 @@ impl fmt::Display for SdpMediaValue { &gt; SdpMediaValue::Audio =&gt; "Audio", &gt; SdpMediaValue::Video =&gt; "Video", &gt; SdpMediaValue::Application =&gt; "Application", &gt; }; &gt; write!(f, "{}", printable) &gt; } &gt; } &gt; &gt;-#[derive(Clone,Debug,PartialEq)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[derive(Clone, Debug, PartialEq)] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpProtocolValue { &gt; RtpSavpf, &gt; UdpTlsRtpSavpf, &gt; TcpTlsRtpSavpf, &gt; DtlsSctp, &gt; UdpDtlsSctp, &gt; TcpDtlsSctp, &gt; } &gt;@@ -53,32 +53,32 @@ impl fmt::Display for SdpProtocolValue { &gt; SdpProtocolValue::UdpDtlsSctp =&gt; "Udp/Dtls/Sctp", &gt; SdpProtocolValue::TcpDtlsSctp =&gt; "Tcp/Dtls/Sctp", &gt; }; &gt; write!(f, "{}", printable) &gt; } &gt; } &gt; &gt; #[derive(Clone)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub enum SdpFormatList { &gt; Integers(Vec&lt;u32&gt;), &gt; Strings(Vec&lt;String&gt;), &gt; } &gt; &gt; impl fmt::Display for SdpFormatList { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; match *self { &gt; SdpFormatList::Integers(ref x) =&gt; write!(f, "{:?}", x), &gt; SdpFormatList::Strings(ref x) =&gt; write!(f, "{:?}", x), &gt; } &gt; } &gt; } &gt; &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub struct SdpMedia { &gt; media: SdpMediaLine, &gt; connection: Option&lt;SdpConnection&gt;, &gt; bandwidth: Vec&lt;SdpBandwidth&gt;, &gt; attribute: Vec&lt;SdpAttribute&gt;, &gt; // unsupported values: &gt; // information: Option&lt;String&gt;, &gt; // key: Option&lt;String&gt;, &gt;@@ -127,85 +127,97 @@ impl SdpMedia { &gt; } &gt; &gt; pub fn get_attributes(&amp;self) -&gt; &amp;Vec&lt;SdpAttribute&gt; { &gt; &amp;self.attribute &gt; } &gt; &gt; pub fn add_attribute(&amp;mut self, attr: &amp;SdpAttribute) -&gt; Result&lt;(), SdpParserInternalError&gt; { &gt; if !attr.allowed_at_media_level() { &gt;- return Err(SdpParserInternalError::Generic(format!("{} not allowed at media level", &gt;- attr))); &gt;+ return Err(SdpParserInternalError::Generic(format!( &gt;+ "{} not allowed at media level", &gt;+ attr &gt;+ ))); &gt; } &gt; Ok(self.attribute.push(attr.clone())) &gt; } &gt; &gt; pub fn get_attribute(&amp;self, t: SdpAttributeType) -&gt; Option&lt;&amp;SdpAttribute&gt; { &gt;- self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).next() &gt;+ self.attribute &gt;+ .iter() &gt;+ .filter(|a| SdpAttributeType::from(*a) == t) &gt;+ .next() &gt; } &gt; &gt; pub fn remove_attribute(&amp;mut self, t: SdpAttributeType) { &gt; self.attribute.retain(|a| SdpAttributeType::from(a) != t); &gt; } &gt; &gt; pub fn set_attribute(&amp;mut self, attr: &amp;SdpAttribute) -&gt; Result&lt;(), SdpParserInternalError&gt; { &gt; self.remove_attribute(SdpAttributeType::from(attr)); &gt; self.add_attribute(attr) &gt; } &gt; &gt; pub fn remove_codecs(&amp;mut self) { &gt;- match self.media.formats{ &gt;+ match self.media.formats { &gt; SdpFormatList::Integers(_) =&gt; self.media.formats = SdpFormatList::Integers(Vec::new()), &gt; SdpFormatList::Strings(_) =&gt; self.media.formats = SdpFormatList::Strings(Vec::new()), &gt; } &gt; &gt;- self.attribute.retain({|x| &gt;- match x { &gt;- &amp;SdpAttribute::Rtpmap(_) | &gt;- &amp;SdpAttribute::Fmtp(_) | &gt;- &amp;SdpAttribute::Rtcpfb(_) | &gt;- &amp;SdpAttribute::Sctpmap(_) =&gt; false, &gt;- _ =&gt; true &gt;+ self.attribute.retain({ &gt;+ |x| match x { &gt;+ &amp;SdpAttribute::Rtpmap(_) &gt;+ | &amp;SdpAttribute::Fmtp(_) &gt;+ | &amp;SdpAttribute::Rtcpfb(_) &gt;+ | &amp;SdpAttribute::Sctpmap(_) =&gt; false, &gt;+ _ =&gt; true, &gt; } &gt; }); &gt; } &gt; &gt;- pub fn add_codec(&amp;mut self, rtpmap: SdpAttributeRtpmap) -&gt; Result&lt;(),SdpParserInternalError&gt; { &gt;- match self.media.formats { &gt;- SdpFormatList::Integers(ref mut x) =&gt; x.push(rtpmap.payload_type as u32), &gt;- SdpFormatList::Strings(ref mut x) =&gt; x.push(rtpmap.payload_type.to_string()), &gt;- } &gt;+ pub fn add_codec(&amp;mut self, rtpmap: SdpAttributeRtpmap) -&gt; Result&lt;(), SdpParserInternalError&gt; { &gt;+ match self.media.formats { &gt;+ SdpFormatList::Integers(ref mut x) =&gt; x.push(rtpmap.payload_type as u32), &gt;+ SdpFormatList::Strings(ref mut x) =&gt; x.push(rtpmap.payload_type.to_string()), &gt;+ } &gt; &gt; self.add_attribute(&amp;SdpAttribute::Rtpmap(rtpmap))?; &gt; Ok(()) &gt; } &gt; &gt; pub fn get_attributes_of_type(&amp;self, t: SdpAttributeType) -&gt; Vec&lt;&amp;SdpAttribute&gt; { &gt;- self.attribute.iter().filter(|a| SdpAttributeType::from(*a) == t).collect() &gt;+ self.attribute &gt;+ .iter() &gt;+ .filter(|a| SdpAttributeType::from(*a) == t) &gt;+ .collect() &gt; } &gt; &gt; pub fn get_connection(&amp;self) -&gt; &amp;Option&lt;SdpConnection&gt; { &gt; &amp;self.connection &gt; } &gt; &gt; pub fn set_connection(&amp;mut self, c: &amp;SdpConnection) -&gt; Result&lt;(), SdpParserInternalError&gt; { &gt; if self.connection.is_some() { &gt;- return Err(SdpParserInternalError::Generic("connection type already exists at this media level" &gt;- .to_string(), &gt;- )); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "connection type already exists at this media level".to_string(), &gt;+ )); &gt; } &gt; Ok(self.connection = Some(c.clone())) &gt; } &gt; &gt;- pub fn add_datachannel(&amp;mut self, name: String, port: u16, streams: u16, msg_size:u32) &gt;- -&gt; Result&lt;(),SdpParserInternalError&gt; { &gt;- // Only one allowed, for now. This may change as the specs (and deployments) evolve. &gt;+ pub fn add_datachannel( &gt;+ &amp;mut self, &gt;+ name: String, &gt;+ port: u16, &gt;+ streams: u16, &gt;+ msg_size: u32, &gt;+ ) -&gt; Result&lt;(), SdpParserInternalError&gt; { &gt;+ // Only one allowed, for now. This may change as the specs (and deployments) evolve. &gt; match self.media.proto { &gt;- SdpProtocolValue::UdpDtlsSctp | &gt;- SdpProtocolValue::TcpDtlsSctp =&gt; { &gt;+ SdpProtocolValue::UdpDtlsSctp | SdpProtocolValue::TcpDtlsSctp =&gt; { &gt; // new data channel format according to draft 21 &gt; self.media.formats = SdpFormatList::Strings(vec![name]); &gt; self.set_attribute(&amp;SdpAttribute::SctpPort(port as u64))?; &gt; } &gt; _ =&gt; { &gt; // old data channels format according to draft 05 &gt; self.media.formats = SdpFormatList::Integers(vec![port as u32]); &gt; self.set_attribute(&amp;SdpAttribute::Sctpmap(SdpAttributeSctpmap { &gt;@@ -219,38 +231,40 @@ impl SdpMedia { &gt; self.set_attribute(&amp;SdpAttribute::MaxMessageSize(msg_size as u64))?; &gt; } &gt; &gt; Ok(()) &gt; } &gt; } &gt; &gt; #[cfg(test)] &gt;-#[cfg_attr(feature="serialize", derive(Serialize))] &gt;+#[cfg_attr(feature = "serialize", derive(Serialize))] &gt; pub fn create_dummy_media_section() -&gt; SdpMedia { &gt; let media_line = SdpMediaLine { &gt; media: SdpMediaValue::Audio, &gt; port: 9, &gt; port_count: 0, &gt; proto: SdpProtocolValue::RtpSavpf, &gt; formats: SdpFormatList::Integers(Vec::new()), &gt; }; &gt; SdpMedia::new(media_line) &gt; } &gt; &gt; fn parse_media_token(value: &amp;str) -&gt; Result&lt;SdpMediaValue, SdpParserInternalError&gt; { &gt; Ok(match value.to_lowercase().as_ref() { &gt;- "audio" =&gt; SdpMediaValue::Audio, &gt;- "video" =&gt; SdpMediaValue::Video, &gt;- "application" =&gt; SdpMediaValue::Application, &gt;- _ =&gt; { &gt;- return Err(SdpParserInternalError::Unsupported(format!("unsupported media value: {}", &gt;- value))) &gt;- } &gt;- }) &gt;+ "audio" =&gt; SdpMediaValue::Audio, &gt;+ "video" =&gt; SdpMediaValue::Video, &gt;+ "application" =&gt; SdpMediaValue::Application, &gt;+ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Unsupported(format!( &gt;+ "unsupported media value: {}", &gt;+ value &gt;+ ))) &gt;+ } &gt;+ }) &gt; } &gt; &gt; #[test] &gt; fn test_parse_media_token() { &gt; let audio = parse_media_token("audio"); &gt; assert!(audio.is_ok()); &gt; assert_eq!(audio.unwrap(), SdpMediaValue::Audio); &gt; let video = parse_media_token("VIDEO"); &gt;@@ -259,30 +273,31 @@ fn test_parse_media_token() { &gt; let app = parse_media_token("aPplIcatIOn"); &gt; assert!(app.is_ok()); &gt; assert_eq!(app.unwrap(), SdpMediaValue::Application); &gt; &gt; assert!(parse_media_token("").is_err()); &gt; assert!(parse_media_token("foobar").is_err()); &gt; } &gt; &gt;- &gt; fn parse_protocol_token(value: &amp;str) -&gt; Result&lt;SdpProtocolValue, SdpParserInternalError&gt; { &gt; Ok(match value.to_uppercase().as_ref() { &gt;- "RTP/SAVPF" =&gt; SdpProtocolValue::RtpSavpf, &gt;- "UDP/TLS/RTP/SAVPF" =&gt; SdpProtocolValue::UdpTlsRtpSavpf, &gt;- "TCP/TLS/RTP/SAVPF" =&gt; SdpProtocolValue::TcpTlsRtpSavpf, &gt;- "DTLS/SCTP" =&gt; SdpProtocolValue::DtlsSctp, &gt;- "UDP/DTLS/SCTP" =&gt; SdpProtocolValue::UdpDtlsSctp, &gt;- "TCP/DTLS/SCTP" =&gt; SdpProtocolValue::TcpDtlsSctp, &gt;- _ =&gt; { &gt;- return Err(SdpParserInternalError::Unsupported(format!("unsupported protocol value: {}", &gt;- value))) &gt;- } &gt;- }) &gt;+ "RTP/SAVPF" =&gt; SdpProtocolValue::RtpSavpf, &gt;+ "UDP/TLS/RTP/SAVPF" =&gt; SdpProtocolValue::UdpTlsRtpSavpf, &gt;+ "TCP/TLS/RTP/SAVPF" =&gt; SdpProtocolValue::TcpTlsRtpSavpf, &gt;+ "DTLS/SCTP" =&gt; SdpProtocolValue::DtlsSctp, &gt;+ "UDP/DTLS/SCTP" =&gt; SdpProtocolValue::UdpDtlsSctp, &gt;+ "TCP/DTLS/SCTP" =&gt; SdpProtocolValue::TcpDtlsSctp, &gt;+ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Unsupported(format!( &gt;+ "unsupported protocol value: {}", &gt;+ value &gt;+ ))) &gt;+ } &gt;+ }) &gt; } &gt; &gt; #[test] &gt; fn test_parse_protocol_token() { &gt; let rtps = parse_protocol_token("rtp/savpf"); &gt; assert!(rtps.is_ok()); &gt; assert_eq!(rtps.unwrap(), SdpProtocolValue::RtpSavpf); &gt; let udps = parse_protocol_token("udp/tls/rtp/savpf"); &gt;@@ -303,27 +318,34 @@ fn test_parse_protocol_token() { &gt; &gt; assert!(parse_protocol_token("").is_err()); &gt; assert!(parse_protocol_token("foobar").is_err()); &gt; } &gt; &gt; pub fn parse_media(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; let mv: Vec&lt;&amp;str&gt; = value.split_whitespace().collect(); &gt; if mv.len() &lt; 4 { &gt;- return Err(SdpParserInternalError::Generic("media attribute must have at least four tokens" &gt;- .to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "media attribute must have at least four tokens".to_string(), &gt;+ )); &gt; } &gt; let media = parse_media_token(mv[0])?; &gt; let mut ptokens = mv[1].split('/'); &gt; let port = match ptokens.next() { &gt;- None =&gt; return Err(SdpParserInternalError::Generic("missing port token".to_string())), &gt;+ None =&gt; { &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "missing port token".to_string(), &gt;+ )) &gt;+ } &gt; Some(p) =&gt; p.parse::&lt;u32&gt;()?, &gt; }; &gt; if port &gt; 65535 { &gt;- return Err(SdpParserInternalError::Generic("media port token is too big".to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "media port token is too big".to_string(), &gt;+ )); &gt; } &gt; let port_count = match ptokens.next() { &gt; None =&gt; 0, &gt; Some(c) =&gt; c.parse::&lt;u32&gt;()?, &gt; }; &gt; let proto = parse_protocol_token(mv[2])?; &gt; let fmt_slice: &amp;[&amp;str] = &amp;mv[3..]; &gt; let formats = match media { &gt;@@ -407,102 +429,92 @@ fn test_media_invalid_payload() { &gt; } &gt; &gt; pub fn parse_media_vector(lines: &amp;[SdpLine]) -&gt; Result&lt;Vec&lt;SdpMedia&gt;, SdpParserError&gt; { &gt; let mut media_sections: Vec&lt;SdpMedia&gt; = Vec::new(); &gt; let mut sdp_media = match lines[0].sdp_type { &gt; SdpType::Media(ref v) =&gt; SdpMedia::new(v.clone()), &gt; _ =&gt; { &gt; return Err(SdpParserError::Sequence { &gt;- message: "first line in media section needs to be a media line" &gt;- .to_string(), &gt;- line_number: lines[0].line_number, &gt;- }) &gt;+ message: "first line in media section needs to be a media line".to_string(), &gt;+ line_number: lines[0].line_number, &gt;+ }) &gt; } &gt; }; &gt; &gt; for line in lines.iter().skip(1) { &gt; match line.sdp_type { &gt; SdpType::Connection(ref c) =&gt; { &gt; sdp_media &gt; .set_connection(c) &gt;- .map_err(|e: SdpParserInternalError| { &gt;- SdpParserError::Sequence { &gt;- message: format!("{}", e), &gt;- line_number: line.line_number, &gt;- } &gt;- })? &gt;+ .map_err(|e: SdpParserInternalError| SdpParserError::Sequence { &gt;+ message: format!("{}", e), &gt;+ line_number: line.line_number, &gt;+ })? &gt; } &gt; SdpType::Bandwidth(ref b) =&gt; sdp_media.add_bandwidth(b), &gt; SdpType::Attribute(ref a) =&gt; { &gt; match a { &gt; &amp;SdpAttribute::DtlsMessage(_) =&gt; { &gt; // Ignore this attribute on media level &gt; Ok(()) &gt;- }, &gt;+ } &gt; &amp;SdpAttribute::Rtpmap(ref rtpmap) =&gt; { &gt;- sdp_media.add_attribute(&amp;SdpAttribute::Rtpmap( &gt;- SdpAttributeRtpmap { &gt;- payload_type: rtpmap.payload_type, &gt;- codec_name: rtpmap.codec_name.clone(), &gt;- frequency: rtpmap.frequency, &gt;- channels: match sdp_media.media.media { &gt;- SdpMediaValue::Video =&gt; Some(0), &gt;- _ =&gt; rtpmap.channels &gt;- }, &gt;- } &gt;- )) &gt;- }, &gt;- _ =&gt; { &gt;- sdp_media.add_attribute(a) &gt;+ sdp_media.add_attribute(&amp;SdpAttribute::Rtpmap(SdpAttributeRtpmap { &gt;+ payload_type: rtpmap.payload_type, &gt;+ codec_name: rtpmap.codec_name.clone(), &gt;+ frequency: rtpmap.frequency, &gt;+ channels: match sdp_media.media.media { &gt;+ SdpMediaValue::Video =&gt; Some(0), &gt;+ _ =&gt; rtpmap.channels, &gt;+ }, &gt;+ })) &gt; } &gt;- }.map_err(|e: SdpParserInternalError| { &gt;- SdpParserError::Sequence { &gt;- message: format!("{}", e), &gt;- line_number: line.line_number, &gt;- } &gt;- })? &gt;+ _ =&gt; sdp_media.add_attribute(a), &gt;+ }.map_err(|e: SdpParserInternalError| SdpParserError::Sequence { &gt;+ message: format!("{}", e), &gt;+ line_number: line.line_number, &gt;+ })? &gt; } &gt; SdpType::Media(ref v) =&gt; { &gt; media_sections.push(sdp_media); &gt; sdp_media = SdpMedia::new(v.clone()); &gt; } &gt; &gt;- SdpType::Email(_) | &gt;- SdpType::Phone(_) | &gt;- SdpType::Origin(_) | &gt;- SdpType::Repeat(_) | &gt;- SdpType::Session(_) | &gt;- SdpType::Timing(_) | &gt;- SdpType::Uri(_) | &gt;- SdpType::Version(_) | &gt;- SdpType::Zone(_) =&gt; { &gt;+ SdpType::Email(_) &gt;+ | SdpType::Phone(_) &gt;+ | SdpType::Origin(_) &gt;+ | SdpType::Repeat(_) &gt;+ | SdpType::Session(_) &gt;+ | SdpType::Timing(_) &gt;+ | SdpType::Uri(_) &gt;+ | SdpType::Version(_) &gt;+ | SdpType::Zone(_) =&gt; { &gt; return Err(SdpParserError::Sequence { &gt;- message: "invalid type in media section".to_string(), &gt;- line_number: line.line_number, &gt;- }) &gt;+ message: "invalid type in media section".to_string(), &gt;+ line_number: line.line_number, &gt;+ }) &gt; } &gt; &gt; // the line parsers throw unsupported errors for these already &gt;- SdpType::Information(_) | &gt;- SdpType::Key(_) =&gt; (), &gt;+ SdpType::Information(_) | SdpType::Key(_) =&gt; (), &gt; }; &gt; } &gt; &gt; media_sections.push(sdp_media); &gt; &gt; Ok(media_sections) &gt; } &gt; &gt; #[test] &gt; fn test_media_vector_first_line_failure() { &gt; let mut sdp_lines: Vec&lt;SdpLine&gt; = Vec::new(); &gt; let line = SdpLine { &gt; line_number: 0, &gt;- sdp_type: SdpType::Session("hello".to_string()) &gt;+ sdp_type: SdpType::Session("hello".to_string()), &gt; }; &gt; sdp_lines.push(line); &gt; assert!(parse_media_vector(&amp;sdp_lines).is_err()); &gt; } &gt; &gt; #[test] &gt; fn test_media_vector_multiple_connections() { &gt; let mut sdp_lines: Vec&lt;SdpLine&gt; = Vec::new(); &gt;@@ -510,33 +522,34 @@ fn test_media_vector_multiple_connections() { &gt; media: SdpMediaValue::Audio, &gt; port: 9, &gt; port_count: 0, &gt; proto: SdpProtocolValue::RtpSavpf, &gt; formats: SdpFormatList::Integers(Vec::new()), &gt; }; &gt; let media = SdpLine { &gt; line_number: 0, &gt;- sdp_type: SdpType::Media(media_line) &gt;+ sdp_type: SdpType::Media(media_line), &gt; }; &gt; sdp_lines.push(media); &gt;- use network::{parse_unicast_addr}; &gt;+ use network::parse_unicast_addr; &gt; let addr = parse_unicast_addr("127.0.0.1").unwrap(); &gt; let c = SdpConnection { &gt; addr, &gt; ttl: None, &gt;- amount: None }; &gt;+ amount: None, &gt;+ }; &gt; let c1 = SdpLine { &gt; line_number: 1, &gt;- sdp_type: SdpType::Connection(c.clone()) &gt;+ sdp_type: SdpType::Connection(c.clone()), &gt; }; &gt; sdp_lines.push(c1); &gt; let c2 = SdpLine { &gt; line_number: 2, &gt;- sdp_type: SdpType::Connection(c) &gt;+ sdp_type: SdpType::Connection(c), &gt; }; &gt; sdp_lines.push(c2); &gt; assert!(parse_media_vector(&amp;sdp_lines).is_err()); &gt; } &gt; &gt; #[test] &gt; fn test_media_vector_invalid_types() { &gt; let mut sdp_lines: Vec&lt;SdpLine&gt; = Vec::new(); &gt;@@ -544,24 +557,24 @@ fn test_media_vector_invalid_types() { &gt; media: SdpMediaValue::Audio, &gt; port: 9, &gt; port_count: 0, &gt; proto: SdpProtocolValue::RtpSavpf, &gt; formats: SdpFormatList::Integers(Vec::new()), &gt; }; &gt; let media = SdpLine { &gt; line_number: 0, &gt;- sdp_type: SdpType::Media(media_line) &gt;+ sdp_type: SdpType::Media(media_line), &gt; }; &gt; sdp_lines.push(media); &gt;- use {SdpTiming}; &gt;+ use SdpTiming; &gt; let t = SdpTiming { start: 0, stop: 0 }; &gt; let tline = SdpLine { &gt; line_number: 1, &gt;- sdp_type: SdpType::Timing(t) &gt;+ sdp_type: SdpType::Timing(t), &gt; }; &gt; sdp_lines.push(tline); &gt; assert!(parse_media_vector(&amp;sdp_lines).is_err()); &gt; } &gt; &gt; #[test] &gt; fn test_media_vector_invalid_media_level_attribute() { &gt; let mut sdp_lines: Vec&lt;SdpLine&gt; = Vec::new(); &gt;@@ -569,19 +582,19 @@ fn test_media_vector_invalid_media_level_attribute() { &gt; media: SdpMediaValue::Audio, &gt; port: 9, &gt; port_count: 0, &gt; proto: SdpProtocolValue::RtpSavpf, &gt; formats: SdpFormatList::Integers(Vec::new()), &gt; }; &gt; let media = SdpLine { &gt; line_number: 0, &gt;- sdp_type: SdpType::Media(media_line) &gt;+ sdp_type: SdpType::Media(media_line), &gt; }; &gt; sdp_lines.push(media); &gt; let a = SdpAttribute::IceLite; &gt; let aline = SdpLine { &gt; line_number: 1, &gt;- sdp_type: SdpType::Attribute(a) &gt;+ sdp_type: SdpType::Attribute(a), &gt; }; &gt; sdp_lines.push(aline); &gt; assert!(parse_media_vector(&amp;sdp_lines).is_err()); &gt; } &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa/src/network.rs b/media/webrtc/signaling/src/sdp/rsdparsa/src/network.rs &gt;index 2d768bfc995e..b3711d95b3f8 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/network.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/network.rs &gt;@@ -1,62 +1,65 @@ &gt;-use std::str::FromStr; &gt; use std::fmt; &gt; use std::net::IpAddr; &gt;+use std::str::FromStr; &gt; &gt; use error::SdpParserInternalError; &gt; &gt;-#[derive(Clone,Copy,Debug,PartialEq)] &gt;+#[derive(Clone, Copy, Debug, PartialEq)] &gt; pub enum SdpAddrType { &gt; IP4 = 4, &gt; IP6 = 6, &gt; } &gt; &gt; impl SdpAddrType { &gt; pub fn same_protocol(&amp;self, addr: &amp;IpAddr) -&gt; bool { &gt;- (addr.is_ipv6() &amp;&amp; *self == SdpAddrType::IP6) || &gt;- (addr.is_ipv4() &amp;&amp; *self == SdpAddrType::IP4) &gt;+ (addr.is_ipv6() &amp;&amp; *self == SdpAddrType::IP6) &gt;+ || (addr.is_ipv4() &amp;&amp; *self == SdpAddrType::IP4) &gt; } &gt; } &gt; &gt; impl fmt::Display for SdpAddrType { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; let printable = match *self { &gt; SdpAddrType::IP4 =&gt; "Ip4", &gt; SdpAddrType::IP6 =&gt; "Ip6", &gt; }; &gt; write!(f, "{}", printable) &gt; } &gt; } &gt; &gt; pub fn parse_nettype(value: &amp;str) -&gt; Result&lt;(), SdpParserInternalError&gt; { &gt; if value.to_uppercase() != "IN" { &gt;- return Err(SdpParserInternalError::Generic("nettype needs to be IN".to_string())); &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "nettype needs to be IN".to_string(), &gt;+ )); &gt; }; &gt; Ok(()) &gt; } &gt; &gt; #[test] &gt; fn test_parse_nettype() { &gt; let internet = parse_nettype("iN"); &gt; assert!(internet.is_ok()); &gt; &gt; assert!(parse_nettype("").is_err()); &gt; assert!(parse_nettype("FOO").is_err()); &gt; } &gt; &gt; pub fn parse_addrtype(value: &amp;str) -&gt; Result&lt;SdpAddrType, SdpParserInternalError&gt; { &gt; Ok(match value.to_uppercase().as_ref() { &gt;- "IP4" =&gt; SdpAddrType::IP4, &gt;- "IP6" =&gt; SdpAddrType::IP6, &gt;- _ =&gt; { &gt;- return Err(SdpParserInternalError::Generic("address type needs to be IP4 or IP6" &gt;- .to_string())) &gt;- } &gt;- }) &gt;+ "IP4" =&gt; SdpAddrType::IP4, &gt;+ "IP6" =&gt; SdpAddrType::IP6, &gt;+ _ =&gt; { &gt;+ return Err(SdpParserInternalError::Generic( &gt;+ "address type needs to be IP4 or IP6".to_string(), &gt;+ )) &gt;+ } &gt;+ }) &gt; } &gt; &gt; #[test] &gt; fn test_parse_addrtype() { &gt; let ip4 = parse_addrtype("iP4"); &gt; assert!(ip4.is_ok()); &gt; assert_eq!(ip4.unwrap(), SdpAddrType::IP4); &gt; let ip6 = parse_addrtype("Ip6"); &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa/src/unsupported_types.rs b/media/webrtc/signaling/src/sdp/rsdparsa/src/unsupported_types.rs &gt;index 272224b6af0c..afce131c52c5 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa/src/unsupported_types.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa/src/unsupported_types.rs &gt;@@ -1,74 +1,95 @@ &gt; use error::SdpParserInternalError; &gt; use SdpType; &gt; &gt; pub fn parse_repeat(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; // TODO implement this if it's ever needed &gt;- Err(SdpParserInternalError::Unsupported(format!("unsupported type repeat: {} ", value))) &gt;+ Err(SdpParserInternalError::Unsupported(format!( &gt;+ "unsupported type repeat: {} ", &gt;+ value &gt;+ ))) &gt; } &gt; &gt; #[test] &gt; fn test_repeat_works() { &gt; // FIXME use a proper r value here &gt; assert!(parse_repeat("0 0").is_err()); &gt; } &gt; &gt; pub fn parse_zone(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; // TODO implement this if it's ever needed &gt;- Err(SdpParserInternalError::Unsupported(format!("unsupported type zone: {}", value))) &gt;+ Err(SdpParserInternalError::Unsupported(format!( &gt;+ "unsupported type zone: {}", &gt;+ value &gt;+ ))) &gt; } &gt; &gt; #[test] &gt; fn test_zone_works() { &gt; // FIXME use a proper z value here &gt; assert!(parse_zone("0 0").is_err()); &gt; } &gt; &gt; pub fn parse_key(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; // TODO implement this if it's ever needed &gt;- Err(SdpParserInternalError::Unsupported(format!("unsupported type key: {}", value))) &gt;+ Err(SdpParserInternalError::Unsupported(format!( &gt;+ "unsupported type key: {}", &gt;+ value &gt;+ ))) &gt; } &gt; &gt; #[test] &gt; fn test_keys_works() { &gt; // FIXME use a proper k value here &gt; assert!(parse_key("12345").is_err()); &gt; } &gt; &gt; pub fn parse_information(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt;- Err(SdpParserInternalError::Unsupported(format!("unsupported type information: {}", value))) &gt;+ Err(SdpParserInternalError::Unsupported(format!( &gt;+ "unsupported type information: {}", &gt;+ value &gt;+ ))) &gt; } &gt; &gt; #[test] &gt; fn test_information_works() { &gt; assert!(parse_information("foobar").is_err()); &gt; } &gt; &gt; pub fn parse_uri(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; // TODO check if this is really a URI &gt;- Err(SdpParserInternalError::Unsupported(format!("unsupported type uri: {}", value))) &gt;+ Err(SdpParserInternalError::Unsupported(format!( &gt;+ "unsupported type uri: {}", &gt;+ value &gt;+ ))) &gt; } &gt; &gt; #[test] &gt; fn test_uri_works() { &gt; assert!(parse_uri("http://www.mozilla.org").is_err()); &gt; } &gt; &gt; pub fn parse_email(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; // TODO check if this is really an email address &gt;- Err(SdpParserInternalError::Unsupported(format!("unsupported type email: {}", value))) &gt;+ Err(SdpParserInternalError::Unsupported(format!( &gt;+ "unsupported type email: {}", &gt;+ value &gt;+ ))) &gt; } &gt; &gt; #[test] &gt; fn test_email_works() { &gt; assert!(parse_email("nils@mozilla.com").is_err()); &gt; } &gt; &gt; pub fn parse_phone(value: &amp;str) -&gt; Result&lt;SdpType, SdpParserInternalError&gt; { &gt; // TODO check if this is really a phone number &gt;- Err(SdpParserInternalError::Unsupported(format!("unsupported type phone: {}", value))) &gt;+ Err(SdpParserInternalError::Unsupported(format!( &gt;+ "unsupported type phone: {}", &gt;+ value &gt;+ ))) &gt; } &gt; &gt; #[test] &gt; fn test_phone_works() { &gt; assert!(parse_phone("+123456789").is_err()); &gt; } &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa/tests/unit_tests.rs b/media/webrtc/signaling/src/sdp/rsdparsa/tests/unit_tests.rs &gt;index 335949d0f678..f99ae6e3e985 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa/tests/unit_tests.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa/tests/unit_tests.rs &gt;@@ -15,21 +15,25 @@ m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n"; &gt; let sdp = sdp_opt.unwrap(); &gt; assert_eq!(sdp.version, 0); &gt; assert_eq!(sdp.session, "-"); &gt; assert!(sdp.connection.is_some()); &gt; assert_eq!(sdp.attribute.len(), 0); &gt; assert_eq!(sdp.media.len(), 1); &gt; &gt; let msection = &amp;(sdp.media[0]); &gt;- assert_eq!(*msection.get_type(), &gt;- rsdparsa::media_type::SdpMediaValue::Audio); &gt;+ assert_eq!( &gt;+ *msection.get_type(), &gt;+ rsdparsa::media_type::SdpMediaValue::Audio &gt;+ ); &gt; assert_eq!(msection.get_port(), 0); &gt;- assert_eq!(*msection.get_proto(), &gt;- rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf); &gt;+ assert_eq!( &gt;+ *msection.get_proto(), &gt;+ rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf &gt;+ ); &gt; assert!(msection.get_attributes().is_empty()); &gt; assert!(msection.get_bandwidth().is_empty()); &gt; assert!(msection.get_connection().is_none()); &gt; } &gt; &gt; #[test] &gt; fn parse_minimal_sdp_with_emtpy_lines() { &gt; let sdp = "v=0\r\n &gt;@@ -89,25 +93,33 @@ a=sendrecv\r\n"; &gt; assert!(sdp_opt.is_some()); &gt; let sdp = sdp_opt.unwrap(); &gt; assert_eq!(sdp.version, 0); &gt; assert_eq!(sdp.session, "-"); &gt; assert_eq!(sdp.attribute.len(), 0); &gt; assert_eq!(sdp.media.len(), 1); &gt; &gt; let msection = &amp;(sdp.media[0]); &gt;- assert_eq!(*msection.get_type(), &gt;- rsdparsa::media_type::SdpMediaValue::Video); &gt;+ assert_eq!( &gt;+ *msection.get_type(), &gt;+ rsdparsa::media_type::SdpMediaValue::Video &gt;+ ); &gt; assert_eq!(msection.get_port(), 0); &gt;- assert_eq!(*msection.get_proto(), &gt;- rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf); &gt;+ assert_eq!( &gt;+ *msection.get_proto(), &gt;+ rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf &gt;+ ); &gt; assert!(!msection.get_bandwidth().is_empty()); &gt; assert!(!msection.get_connection().is_none()); &gt; assert!(!msection.get_attributes().is_empty()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some()); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv) &gt;+ .is_some() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn parse_firefox_audio_offer() { &gt; let sdp = "v=0\r\n &gt; o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n &gt; s=-\r\n &gt; t=0 0\r\n &gt;@@ -135,36 +147,88 @@ a=ssrc:2655508255 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}\r\n"; &gt; assert!(sdp_res.is_ok()); &gt; let sdp_opt = sdp_res.ok(); &gt; assert!(sdp_opt.is_some()); &gt; let sdp = sdp_opt.unwrap(); &gt; assert_eq!(sdp.version, 0); &gt; assert_eq!(sdp.media.len(), 1); &gt; &gt; let msection = &amp;(sdp.media[0]); &gt;- assert_eq!(*msection.get_type(), &gt;- rsdparsa::media_type::SdpMediaValue::Audio); &gt;+ assert_eq!( &gt;+ *msection.get_type(), &gt;+ rsdparsa::media_type::SdpMediaValue::Audio &gt;+ ); &gt; assert_eq!(msection.get_port(), 9); &gt;- assert_eq!(*msection.get_proto(), &gt;- rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf); &gt;+ assert_eq!( &gt;+ *msection.get_proto(), &gt;+ rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf &gt;+ ); &gt; assert!(msection.get_connection().is_some()); &gt; assert!(msection.get_bandwidth().is_empty()); &gt; assert!(!msection.get_attributes().is_empty()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Fmtp).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some()); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Fmtp) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc) &gt;+ .is_some() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn parse_firefox_video_offer() { &gt; let sdp = "v=0\r\n &gt; o=mozilla...THIS_IS_SDPARTA-52.0a1 506705521068071134 0 IN IP4 0.0.0.0\r\n &gt; s=-\r\n &gt; t=0 0\r\n &gt;@@ -203,37 +267,93 @@ a=ssrc:2709871439 cname:{735484ea-4f6c-f74a-bd66-7425f8476c2e}"; &gt; assert!(sdp_res.is_ok()); &gt; let sdp_opt = sdp_res.ok(); &gt; assert!(sdp_opt.is_some()); &gt; let sdp = sdp_opt.unwrap(); &gt; assert_eq!(sdp.version, 0); &gt; assert_eq!(sdp.media.len(), 1); &gt; &gt; let msection = &amp;(sdp.media[0]); &gt;- assert_eq!(*msection.get_type(), &gt;- rsdparsa::media_type::SdpMediaValue::Video); &gt;+ assert_eq!( &gt;+ *msection.get_type(), &gt;+ rsdparsa::media_type::SdpMediaValue::Video &gt;+ ); &gt; assert_eq!(msection.get_port(), 9); &gt;- assert_eq!(*msection.get_proto(), &gt;- rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf); &gt;+ assert_eq!( &gt;+ *msection.get_proto(), &gt;+ rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf &gt;+ ); &gt; assert!(msection.get_connection().is_some()); &gt; assert!(msection.get_bandwidth().is_empty()); &gt; assert!(!msection.get_attributes().is_empty()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Recvonly).is_some()); &gt;- assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Fmtp).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some()); &gt;- assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtcpfb).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some()); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Recvonly) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ !msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Fmtp) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ !msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtcpfb) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc) &gt;+ .is_some() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn parse_firefox_datachannel_offer() { &gt; let sdp = "v=0\r\n &gt; o=mozilla...THIS_IS_SDPARTA-52.0a2 3327975756663609975 0 IN IP4 0.0.0.0\r\n &gt; s=-\r\n &gt; t=0 0\r\n &gt;@@ -256,37 +376,93 @@ a=ssrc:3376683177 cname:{62f78ee0-620f-a043-86ca-b69f189f1aea}\r\n"; &gt; assert!(sdp_res.is_ok()); &gt; let sdp_opt = sdp_res.ok(); &gt; assert!(sdp_opt.is_some()); &gt; let sdp = sdp_opt.unwrap(); &gt; assert_eq!(sdp.version, 0); &gt; assert_eq!(sdp.media.len(), 1); &gt; &gt; let msection = &amp;(sdp.media[0]); &gt;- assert_eq!(*msection.get_type(), &gt;- rsdparsa::media_type::SdpMediaValue::Application); &gt;+ assert_eq!( &gt;+ *msection.get_type(), &gt;+ rsdparsa::media_type::SdpMediaValue::Application &gt;+ ); &gt; assert_eq!(msection.get_port(), 49760); &gt;- assert_eq!(*msection.get_proto(), &gt;- rsdparsa::media_type::SdpProtocolValue::DtlsSctp); &gt;+ assert_eq!( &gt;+ *msection.get_proto(), &gt;+ rsdparsa::media_type::SdpProtocolValue::DtlsSctp &gt;+ ); &gt; assert!(msection.get_connection().is_some()); &gt; assert!(msection.get_bandwidth().is_empty()); &gt; assert!(!msection.get_attributes().is_empty()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv).is_some()); &gt;- assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::EndOfCandidates).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid).is_some()); &gt;- assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid).is_some()); &gt;- assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtcpfb).is_some()); &gt;- assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux).is_some()); &gt;- assert!(!msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sctpmap).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup).is_some()); &gt;- assert!(msection.get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc).is_some()); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sendrecv) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ !msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Extmap) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::IcePwd) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::IceUfrag) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::EndOfCandidates) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Mid) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ !msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Msid) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ !msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtcpfb) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ !msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::RtcpMux) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ !msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Rtpmap) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Sctpmap) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Setup) &gt;+ .is_some() &gt;+ ); &gt;+ assert!( &gt;+ msection &gt;+ .get_attribute(rsdparsa::attribute_type::SdpAttributeType::Ssrc) &gt;+ .is_some() &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn parse_chrome_audio_video_offer() { &gt; let sdp = "v=0\r\n &gt; o=- 3836772544440436510 2 IN IP4 127.0.0.1\r\n &gt; s=-\r\n &gt; t=0 0\r\n &gt;@@ -377,31 +553,39 @@ a=ssrc:2673335628 label:b6ec5178-c611-403f-bbec-3833ed547c09\r\n"; &gt; assert!(sdp_res.is_ok()); &gt; let sdp_opt = sdp_res.ok(); &gt; assert!(sdp_opt.is_some()); &gt; let sdp = sdp_opt.unwrap(); &gt; assert_eq!(sdp.version, 0); &gt; assert_eq!(sdp.media.len(), 2); &gt; &gt; let msection1 = &amp;(sdp.media[0]); &gt;- assert_eq!(*msection1.get_type(), &gt;- rsdparsa::media_type::SdpMediaValue::Audio); &gt;+ assert_eq!( &gt;+ *msection1.get_type(), &gt;+ rsdparsa::media_type::SdpMediaValue::Audio &gt;+ ); &gt; assert_eq!(msection1.get_port(), 9); &gt;- assert_eq!(*msection1.get_proto(), &gt;- rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf); &gt;+ assert_eq!( &gt;+ *msection1.get_proto(), &gt;+ rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf &gt;+ ); &gt; assert!(!msection1.get_attributes().is_empty()); &gt; assert!(msection1.get_connection().is_some()); &gt; assert!(msection1.get_bandwidth().is_empty()); &gt; &gt; let msection2 = &amp;(sdp.media[1]); &gt;- assert_eq!(*msection2.get_type(), &gt;- rsdparsa::media_type::SdpMediaValue::Video); &gt;+ assert_eq!( &gt;+ *msection2.get_type(), &gt;+ rsdparsa::media_type::SdpMediaValue::Video &gt;+ ); &gt; assert_eq!(msection2.get_port(), 9); &gt;- assert_eq!(*msection2.get_proto(), &gt;- rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf); &gt;+ assert_eq!( &gt;+ *msection2.get_proto(), &gt;+ rsdparsa::media_type::SdpProtocolValue::UdpTlsRtpSavpf &gt;+ ); &gt; assert!(!msection2.get_attributes().is_empty()); &gt; assert!(msection2.get_connection().is_some()); &gt; assert!(msection2.get_bandwidth().is_empty()); &gt; } &gt; &gt; #[test] &gt; fn parse_firefox_simulcast_offer() { &gt; let sdp = "v=0\r\n &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs &gt;index 936dfb6d179e..461f0ae1b094 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/attribute.rs &gt;@@ -1,35 +1,36 @@ &gt;-use std::slice; &gt;-use libc::{size_t, uint8_t, uint16_t, uint32_t, int64_t, uint64_t, c_float}; &gt;+use libc::{c_float, int64_t, size_t, uint16_t, uint32_t, uint64_t, uint8_t}; &gt; use std::ptr; &gt;+use std::slice; &gt; &gt;-use rsdparsa::SdpSession; &gt;+use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_OK}; &gt; use rsdparsa::attribute_type::*; &gt;-use nserror::{nsresult, NS_OK, NS_ERROR_INVALID_ARG}; &gt;+use rsdparsa::SdpSession; &gt; &gt;-use types::StringView; &gt; use network::RustIpAddr; &gt;- &gt;+use types::StringView; &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn num_attributes(session: *const SdpSession) -&gt; u32 { &gt; (*session).attribute.len() as u32 &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn get_attribute_ptr(session: *const SdpSession, &gt;- index: u32, &gt;- ret: *mut *const SdpAttribute) -&gt; nsresult { &gt;+pub unsafe extern "C" fn get_attribute_ptr( &gt;+ session: *const SdpSession, &gt;+ index: u32, &gt;+ ret: *mut *const SdpAttribute, &gt;+) -&gt; nsresult { &gt; match (*session).attribute.get(index as usize) { &gt; Some(attribute) =&gt; { &gt; *ret = attribute as *const SdpAttribute; &gt; NS_OK &gt;- }, &gt;- None =&gt; NS_ERROR_INVALID_ARG &gt;+ } &gt;+ None =&gt; NS_ERROR_INVALID_ARG, &gt; } &gt; } &gt; &gt; fn count_attribute(attributes: &amp;[SdpAttribute], search: SdpAttributeType) -&gt; usize { &gt; let mut count = 0; &gt; for attribute in (*attributes).iter() { &gt; if SdpAttributeType::from(attribute) == search { &gt; count += 1; &gt;@@ -42,21 +43,27 @@ fn argsearch(attributes: &amp;[SdpAttribute], attribute_type: SdpAttributeType) -&gt; O &gt; for (i, attribute) in (*attributes).iter().enumerate() { &gt; if SdpAttributeType::from(attribute) == attribute_type { &gt; return Some(i); &gt; } &gt; } &gt; None &gt; } &gt; &gt;-pub unsafe fn has_attribute(attributes: *const Vec&lt;SdpAttribute&gt;, attribute_type: SdpAttributeType) -&gt; bool { &gt;+pub unsafe fn has_attribute( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ attribute_type: SdpAttributeType, &gt;+) -&gt; bool { &gt; argsearch((*attributes).as_slice(), attribute_type).is_some() &gt; } &gt; &gt;-fn get_attribute(attributes: &amp;[SdpAttribute], attribute_type: SdpAttributeType) -&gt; Option&lt;&amp;SdpAttribute&gt; { &gt;+fn get_attribute( &gt;+ attributes: &amp;[SdpAttribute], &gt;+ attribute_type: SdpAttributeType, &gt;+) -&gt; Option&lt;&amp;SdpAttribute&gt; { &gt; argsearch(attributes, attribute_type).map(|i| &amp;attributes[i]) &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub enum RustSdpAttributeDtlsMessageType { &gt; Client, &gt; Server, &gt;@@ -64,97 +71,114 @@ pub enum RustSdpAttributeDtlsMessageType { &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeDtlsMessage { &gt; pub role: uint8_t, &gt; pub value: StringView, &gt; } &gt; &gt;-impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeDtlsMessage &gt; for RustSdpAttributeDtlsMessage { &gt;- fn from(other: &amp;SdpAttributeDtlsMessage ) -&gt; Self { &gt;+impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeDtlsMessage&gt; for RustSdpAttributeDtlsMessage { &gt;+ fn from(other: &amp;SdpAttributeDtlsMessage) -&gt; Self { &gt; match other { &gt; &amp;SdpAttributeDtlsMessage::Client(ref x) =&gt; RustSdpAttributeDtlsMessage { &gt; role: RustSdpAttributeDtlsMessageType::Client as uint8_t, &gt; value: StringView::from(x.as_str()), &gt; }, &gt; &amp;SdpAttributeDtlsMessage::Server(ref x) =&gt; RustSdpAttributeDtlsMessage { &gt; role: RustSdpAttributeDtlsMessageType::Server as uint8_t, &gt;- value: StringView::from(x.as_str()) &gt;- } &gt;+ value: StringView::from(x.as_str()), &gt;+ }, &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_dtls_message(attributes: *const Vec&lt;SdpAttribute&gt;, &gt;- ret: *mut RustSdpAttributeDtlsMessage) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_get_dtls_message( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret: *mut RustSdpAttributeDtlsMessage, &gt;+) -&gt; nsresult { &gt; let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::DtlsMessage); &gt; if let Some(&amp;SdpAttribute::DtlsMessage(ref dtls_message)) = attr { &gt; *ret = RustSdpAttributeDtlsMessage::from(dtls_message); &gt; return NS_OK; &gt; } &gt; NS_ERROR_INVALID_ARG &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_iceufrag(attributes: *const Vec&lt;SdpAttribute&gt;, ret: *mut StringView) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_get_iceufrag( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret: *mut StringView, &gt;+) -&gt; nsresult { &gt; let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::IceUfrag); &gt; if let Some(&amp;SdpAttribute::IceUfrag(ref string)) = attr { &gt; *ret = StringView::from(string.as_str()); &gt; return NS_OK; &gt; } &gt; NS_ERROR_INVALID_ARG &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_icepwd(attributes: *const Vec&lt;SdpAttribute&gt;, ret: *mut StringView) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_get_icepwd( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret: *mut StringView, &gt;+) -&gt; nsresult { &gt; let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::IcePwd); &gt; if let Some(&amp;SdpAttribute::IcePwd(ref string)) = attr { &gt; *ret = StringView::from(string.as_str()); &gt; return NS_OK; &gt; } &gt; NS_ERROR_INVALID_ARG &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_identity(attributes: *const Vec&lt;SdpAttribute&gt;, ret: *mut StringView) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_get_identity( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret: *mut StringView, &gt;+) -&gt; nsresult { &gt; let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Identity); &gt; if let Some(&amp;SdpAttribute::Identity(ref string)) = attr { &gt; *ret = StringView::from(string.as_str()); &gt; return NS_OK; &gt; } &gt; NS_ERROR_INVALID_ARG &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_iceoptions(attributes: *const Vec&lt;SdpAttribute&gt;, ret: *mut *const Vec&lt;String&gt;) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_get_iceoptions( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret: *mut *const Vec&lt;String&gt;, &gt;+) -&gt; nsresult { &gt; let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::IceOptions); &gt; if let Some(&amp;SdpAttribute::IceOptions(ref options)) = attr { &gt; *ret = options; &gt; return NS_OK; &gt; } &gt; NS_ERROR_INVALID_ARG &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_maxptime(attributes: *const Vec&lt;SdpAttribute&gt;, ret: *mut uint64_t) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_get_maxptime( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret: *mut uint64_t, &gt;+) -&gt; nsresult { &gt; let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::MaxPtime); &gt; if let Some(&amp;SdpAttribute::MaxPtime(ref max_ptime)) = attr { &gt; *ret = *max_ptime; &gt; return NS_OK; &gt; } &gt; NS_ERROR_INVALID_ARG &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeFingerprint { &gt; hash_algorithm: uint16_t, &gt;- fingerprint: *const Vec&lt;u8&gt; &gt;+ fingerprint: *const Vec&lt;u8&gt;, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeFingerprint&gt; for RustSdpAttributeFingerprint { &gt; fn from(other: &amp;SdpAttributeFingerprint) -&gt; Self { &gt; RustSdpAttributeFingerprint { &gt; hash_algorithm: other.hash_algorithm as uint16_t, &gt; fingerprint: &amp;other.fingerprint, &gt; } &gt;@@ -162,22 +186,30 @@ impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeFingerprint&gt; for RustSdpAttributeFingerprint { &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_fingerprint_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::Fingerprint) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_fingerprints(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_fingerprints: *mut RustSdpAttributeFingerprint) { &gt;- let attrs: Vec&lt;_&gt; = (*attributes).iter().filter_map(|x| if let SdpAttribute::Fingerprint(ref data) = *x { &gt;- Some(RustSdpAttributeFingerprint::from(data)) &gt;- } else { &gt;- None &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_fingerprints( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_fingerprints: *mut RustSdpAttributeFingerprint, &gt;+) { &gt;+ let attrs: Vec&lt;_&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::Fingerprint(ref data) = *x { &gt;+ Some(RustSdpAttributeFingerprint::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; let fingerprints = slice::from_raw_parts_mut(ret_fingerprints, ret_size); &gt; fingerprints.copy_from_slice(attrs.as_slice()); &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone)] &gt; pub enum RustSdpAttributeSetup { &gt; Active, &gt;@@ -187,23 +219,26 @@ pub enum RustSdpAttributeSetup { &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeSetup&gt; for RustSdpAttributeSetup { &gt; fn from(other: &amp;SdpAttributeSetup) -&gt; Self { &gt; match *other { &gt; SdpAttributeSetup::Active =&gt; RustSdpAttributeSetup::Active, &gt; SdpAttributeSetup::Actpass =&gt; RustSdpAttributeSetup::Actpass, &gt; SdpAttributeSetup::Holdconn =&gt; RustSdpAttributeSetup::Holdconn, &gt;- SdpAttributeSetup::Passive =&gt; RustSdpAttributeSetup::Passive &gt;+ SdpAttributeSetup::Passive =&gt; RustSdpAttributeSetup::Passive, &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_setup(attributes: *const Vec&lt;SdpAttribute&gt;, ret: *mut RustSdpAttributeSetup) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_get_setup( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret: *mut RustSdpAttributeSetup, &gt;+) -&gt; nsresult { &gt; let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Setup); &gt; if let Some(&amp;SdpAttribute::Setup(ref setup)) = attr { &gt; *ret = RustSdpAttributeSetup::from(setup); &gt; return NS_OK; &gt; } &gt; NS_ERROR_INVALID_ARG &gt; } &gt; &gt;@@ -215,33 +250,41 @@ pub struct RustSdpAttributeSsrc { &gt; pub value: StringView, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeSsrc&gt; for RustSdpAttributeSsrc { &gt; fn from(other: &amp;SdpAttributeSsrc) -&gt; Self { &gt; RustSdpAttributeSsrc { &gt; id: other.id, &gt; attribute: StringView::from(&amp;other.attribute), &gt;- value: StringView::from(&amp;other.value) &gt;+ value: StringView::from(&amp;other.value), &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_ssrc_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::Ssrc) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_ssrcs(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_ssrcs: *mut RustSdpAttributeSsrc) { &gt;- let attrs: Vec&lt;_&gt; = (*attributes).iter().filter_map(|x| if let SdpAttribute::Ssrc(ref data) = *x { &gt;- Some(RustSdpAttributeSsrc::from(data)) &gt;- } else { &gt;- None &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_ssrcs( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_ssrcs: *mut RustSdpAttributeSsrc, &gt;+) { &gt;+ let attrs: Vec&lt;_&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::Ssrc(ref data) = *x { &gt;+ Some(RustSdpAttributeSsrc::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; let ssrcs = slice::from_raw_parts_mut(ret_ssrcs, ret_size); &gt; ssrcs.copy_from_slice(attrs.as_slice()); &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeRtpmap { &gt; pub payload_type: uint8_t, &gt;@@ -251,41 +294,48 @@ pub struct RustSdpAttributeRtpmap { &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeRtpmap&gt; for RustSdpAttributeRtpmap { &gt; fn from(other: &amp;SdpAttributeRtpmap) -&gt; Self { &gt; RustSdpAttributeRtpmap { &gt; payload_type: other.payload_type as uint8_t, &gt; codec_name: StringView::from(other.codec_name.as_str()), &gt; frequency: other.frequency as uint32_t, &gt;- channels: other.channels.unwrap_or(1) &gt;+ channels: other.channels.unwrap_or(1), &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_rtpmap_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::Rtpmap) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_rtpmaps(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_rtpmaps: *mut RustSdpAttributeRtpmap) { &gt;- let attrs: Vec&lt;_&gt; = (*attributes).iter().filter_map(|x| if let SdpAttribute::Rtpmap(ref data) = *x { &gt;- Some(RustSdpAttributeRtpmap::from(data)) &gt;- } else { &gt;- None &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_rtpmaps( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_rtpmaps: *mut RustSdpAttributeRtpmap, &gt;+) { &gt;+ let attrs: Vec&lt;_&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::Rtpmap(ref data) = *x { &gt;+ Some(RustSdpAttributeRtpmap::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; let rtpmaps = slice::from_raw_parts_mut(ret_rtpmaps, ret_size); &gt; rtpmaps.copy_from_slice(attrs.as_slice()); &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeFmtpParameters { &gt;- &gt; // H264 &gt; pub packetization_mode: uint32_t, &gt; pub level_asymmetry_allowed: bool, &gt; pub profile_level_id: uint32_t, &gt; pub max_fs: uint32_t, &gt; pub max_cpb: uint32_t, &gt; pub max_dpb: uint32_t, &gt; pub max_br: uint32_t, &gt;@@ -309,34 +359,34 @@ pub struct RustSdpAttributeFmtpParameters { &gt; pub encodings: *const Vec&lt;uint8_t&gt;, &gt; &gt; // Unknown &gt; pub unknown_tokens: *const Vec&lt;String&gt;, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeFmtpParameters&gt; for RustSdpAttributeFmtpParameters { &gt; fn from(other: &amp;SdpAttributeFmtpParameters) -&gt; Self { &gt;- RustSdpAttributeFmtpParameters{ &gt;- packetization_mode: other.packetization_mode, &gt;- level_asymmetry_allowed: other.level_asymmetry_allowed, &gt;- profile_level_id: other.profile_level_id, &gt;- max_fs: other.max_fs, &gt;- max_cpb: other.max_cpb, &gt;- max_dpb: other.max_dpb, &gt;- max_br: other.max_br, &gt;- max_mbps: other.max_mbps, &gt;- usedtx: other.usedtx, &gt;- stereo: other.stereo, &gt;- useinbandfec: other.useinbandfec, &gt;- cbr: other.cbr, &gt;- max_fr: other.max_fr, &gt;- maxplaybackrate: other.maxplaybackrate, &gt;- dtmf_tones: StringView::from(other.dtmf_tones.as_str()), &gt;- encodings: &amp;other.encodings, &gt;- unknown_tokens: &amp;other.unknown_tokens, &gt;+ RustSdpAttributeFmtpParameters { &gt;+ packetization_mode: other.packetization_mode, &gt;+ level_asymmetry_allowed: other.level_asymmetry_allowed, &gt;+ profile_level_id: other.profile_level_id, &gt;+ max_fs: other.max_fs, &gt;+ max_cpb: other.max_cpb, &gt;+ max_dpb: other.max_dpb, &gt;+ max_br: other.max_br, &gt;+ max_mbps: other.max_mbps, &gt;+ usedtx: other.usedtx, &gt;+ stereo: other.stereo, &gt;+ useinbandfec: other.useinbandfec, &gt;+ cbr: other.cbr, &gt;+ max_fr: other.max_fr, &gt;+ maxplaybackrate: other.maxplaybackrate, &gt;+ dtmf_tones: StringView::from(other.dtmf_tones.as_str()), &gt;+ encodings: &amp;other.encodings, &gt;+ unknown_tokens: &amp;other.unknown_tokens, &gt; } &gt; } &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeFmtp { &gt; pub payload_type: uint8_t, &gt;@@ -345,44 +395,52 @@ pub struct RustSdpAttributeFmtp { &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_fmtp_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::Fmtp) &gt; } &gt; &gt; fn find_payload_type(attributes: &amp;[SdpAttribute], payload_type: u8) -&gt; Option&lt;&amp;SdpAttributeRtpmap&gt; { &gt;- attributes.iter().filter_map(|x| if let SdpAttribute::Rtpmap(ref data) = *x { &gt;- if data.payload_type == payload_type { &gt;+ attributes &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::Rtpmap(ref data) = *x { &gt;+ if data.payload_type == payload_type { &gt;+ Some(data) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).next() &gt;+} &gt;+ &gt;+#[no_mangle] &gt;+pub unsafe extern "C" fn sdp_get_fmtp( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_fmtp: *mut RustSdpAttributeFmtp, &gt;+) -&gt; size_t { &gt;+ let fmtps = (*attributes).iter().filter_map(|x| { &gt;+ if let SdpAttribute::Fmtp(ref data) = *x { &gt; Some(data) &gt; } else { &gt; None &gt; } &gt;- } else { &gt;- None &gt;- }).next() &gt;-} &gt;- &gt;-#[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_fmtp(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, &gt;- ret_fmtp: *mut RustSdpAttributeFmtp) -&gt; size_t { &gt;- let fmtps = (*attributes).iter().filter_map(|x| if let SdpAttribute::Fmtp(ref data) = *x { &gt;- Some(data) &gt;- } else { &gt;- None &gt; }); &gt; let mut rust_fmtps = Vec::new(); &gt; for fmtp in fmtps { &gt; if let Some(rtpmap) = find_payload_type((*attributes).as_slice(), fmtp.payload_type) { &gt;- rust_fmtps.push( RustSdpAttributeFmtp{ &gt;+ rust_fmtps.push(RustSdpAttributeFmtp { &gt; payload_type: fmtp.payload_type as u8, &gt; codec_name: StringView::from(rtpmap.codec_name.as_str()), &gt; parameters: RustSdpAttributeFmtpParameters::from(&amp;fmtp.parameters), &gt;- } &gt;- ); &gt;+ }); &gt; } &gt; } &gt; let fmtps = if ret_size &lt;= rust_fmtps.len() { &gt; slice::from_raw_parts_mut(ret_fmtp, ret_size) &gt; } else { &gt; slice::from_raw_parts_mut(ret_fmtp, rust_fmtps.len()) &gt; }; &gt; fmtps.copy_from_slice(rust_fmtps.as_slice()); &gt;@@ -424,25 +482,26 @@ pub unsafe extern "C" fn sdp_get_sctp_port(attributes: *const Vec&lt;SdpAttribute&gt;) &gt; pub struct RustSdpAttributeFlags { &gt; pub ice_lite: bool, &gt; pub rtcp_mux: bool, &gt; pub rtcp_rsize: bool, &gt; pub bundle_only: bool, &gt; pub end_of_candidates: bool, &gt; } &gt; &gt;- &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_attribute_flags(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; RustSdpAttributeFlags { &gt;+pub unsafe extern "C" fn sdp_get_attribute_flags( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+) -&gt; RustSdpAttributeFlags { &gt; let mut ret = RustSdpAttributeFlags { &gt; ice_lite: false, &gt; rtcp_mux: false, &gt; rtcp_rsize: false, &gt; bundle_only: false, &gt;- end_of_candidates: false &gt;+ end_of_candidates: false, &gt; }; &gt; for attribute in (*attributes).iter() { &gt; if let SdpAttribute::IceLite = *attribute { &gt; ret.ice_lite = true; &gt; } else if let SdpAttribute::RtcpMux = *attribute { &gt; ret.rtcp_mux = true; &gt; } else if let SdpAttribute::RtcpRsize = *attribute { &gt; ret.rtcp_rsize = true; &gt;@@ -451,87 +510,108 @@ pub unsafe extern "C" fn sdp_get_attribute_flags(attributes: *const Vec&lt;SdpAttri &gt; } else if let SdpAttribute::EndOfCandidates = *attribute { &gt; ret.end_of_candidates = true; &gt; } &gt; } &gt; ret &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_mid(attributes: *const Vec&lt;SdpAttribute&gt;, ret: *mut StringView) -&gt; nsresult { &gt;- for attribute in (*attributes).iter(){ &gt;+pub unsafe extern "C" fn sdp_get_mid( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret: *mut StringView, &gt;+) -&gt; nsresult { &gt;+ for attribute in (*attributes).iter() { &gt; if let SdpAttribute::Mid(ref data) = *attribute { &gt; *ret = StringView::from(data.as_str()); &gt; return NS_OK; &gt; } &gt; } &gt; NS_ERROR_INVALID_ARG &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeMsid { &gt; id: StringView, &gt;- appdata: StringView &gt;+ appdata: StringView, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeMsid&gt; for RustSdpAttributeMsid { &gt; fn from(other: &amp;SdpAttributeMsid) -&gt; Self { &gt; RustSdpAttributeMsid { &gt; id: StringView::from(other.id.as_str()), &gt;- appdata: StringView::from(&amp;other.appdata) &gt;+ appdata: StringView::from(&amp;other.appdata), &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_msid_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::Msid) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_msids(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_msids: *mut RustSdpAttributeMsid) { &gt;- let attrs: Vec&lt;_&gt; = (*attributes).iter().filter_map(|x| if let SdpAttribute::Msid(ref data) = *x { &gt;- Some(RustSdpAttributeMsid::from(data)) &gt;- } else { &gt;- None &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_msids( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_msids: *mut RustSdpAttributeMsid, &gt;+) { &gt;+ let attrs: Vec&lt;_&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::Msid(ref data) = *x { &gt;+ Some(RustSdpAttributeMsid::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; let msids = slice::from_raw_parts_mut(ret_msids, ret_size); &gt; msids.copy_from_slice(attrs.as_slice()); &gt; } &gt; &gt; // TODO: Finish msid attributes once parsing is changed upstream. &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeMsidSemantic { &gt; pub semantic: StringView, &gt;- pub msids: *const Vec&lt;String&gt; &gt;+ pub msids: *const Vec&lt;String&gt;, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeMsidSemantic&gt; for RustSdpAttributeMsidSemantic { &gt; fn from(other: &amp;SdpAttributeMsidSemantic) -&gt; Self { &gt; RustSdpAttributeMsidSemantic { &gt; semantic: StringView::from(other.semantic.as_str()), &gt;- msids: &amp;other.msids &gt;+ msids: &amp;other.msids, &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_msid_semantic_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt;+pub unsafe extern "C" fn sdp_get_msid_semantic_count( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::MsidSemantic) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_msid_semantics(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_msid_semantics: *mut RustSdpAttributeMsidSemantic) { &gt;- let attrs: Vec&lt;_&gt; = (*attributes).iter().filter_map(|x| if let SdpAttribute::MsidSemantic(ref data) = *x { &gt;- Some(RustSdpAttributeMsidSemantic::from(data)) &gt;- } else { &gt;- None &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_msid_semantics( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_msid_semantics: *mut RustSdpAttributeMsidSemantic, &gt;+) { &gt;+ let attrs: Vec&lt;_&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::MsidSemantic(ref data) = *x { &gt;+ Some(RustSdpAttributeMsidSemantic::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; let msid_semantics = slice::from_raw_parts_mut(ret_msid_semantics, ret_size); &gt; msid_semantics.copy_from_slice(attrs.as_slice()); &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub enum RustSdpAttributeGroupSemantic { &gt; LipSynchronization, &gt;@@ -541,148 +621,177 @@ pub enum RustSdpAttributeGroupSemantic { &gt; ForwardErrorCorrection, &gt; DecodingDependency, &gt; Bundle, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeGroupSemantic&gt; for RustSdpAttributeGroupSemantic { &gt; fn from(other: &amp;SdpAttributeGroupSemantic) -&gt; Self { &gt; match *other { &gt;- SdpAttributeGroupSemantic::LipSynchronization =&gt; RustSdpAttributeGroupSemantic::LipSynchronization, &gt;- SdpAttributeGroupSemantic::FlowIdentification =&gt; RustSdpAttributeGroupSemantic::FlowIdentification, &gt;- SdpAttributeGroupSemantic::SingleReservationFlow =&gt; RustSdpAttributeGroupSemantic::SingleReservationFlow, &gt;- SdpAttributeGroupSemantic::AlternateNetworkAddressType =&gt; RustSdpAttributeGroupSemantic::AlternateNetworkAddressType, &gt;- SdpAttributeGroupSemantic::ForwardErrorCorrection =&gt; RustSdpAttributeGroupSemantic::ForwardErrorCorrection, &gt;- SdpAttributeGroupSemantic::DecodingDependency =&gt; RustSdpAttributeGroupSemantic::DecodingDependency, &gt;- SdpAttributeGroupSemantic::Bundle =&gt; RustSdpAttributeGroupSemantic::Bundle &gt;+ SdpAttributeGroupSemantic::LipSynchronization =&gt; { &gt;+ RustSdpAttributeGroupSemantic::LipSynchronization &gt;+ } &gt;+ SdpAttributeGroupSemantic::FlowIdentification =&gt; { &gt;+ RustSdpAttributeGroupSemantic::FlowIdentification &gt;+ } &gt;+ SdpAttributeGroupSemantic::SingleReservationFlow =&gt; { &gt;+ RustSdpAttributeGroupSemantic::SingleReservationFlow &gt;+ } &gt;+ SdpAttributeGroupSemantic::AlternateNetworkAddressType =&gt; { &gt;+ RustSdpAttributeGroupSemantic::AlternateNetworkAddressType &gt;+ } &gt;+ SdpAttributeGroupSemantic::ForwardErrorCorrection =&gt; { &gt;+ RustSdpAttributeGroupSemantic::ForwardErrorCorrection &gt;+ } &gt;+ SdpAttributeGroupSemantic::DecodingDependency =&gt; { &gt;+ RustSdpAttributeGroupSemantic::DecodingDependency &gt;+ } &gt;+ SdpAttributeGroupSemantic::Bundle =&gt; RustSdpAttributeGroupSemantic::Bundle, &gt; } &gt; } &gt; } &gt; &gt;- &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeGroup { &gt; pub semantic: RustSdpAttributeGroupSemantic, &gt;- pub tags: *const Vec&lt;String&gt; &gt;+ pub tags: *const Vec&lt;String&gt;, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeGroup&gt; for RustSdpAttributeGroup { &gt; fn from(other: &amp;SdpAttributeGroup) -&gt; Self { &gt; RustSdpAttributeGroup { &gt; semantic: RustSdpAttributeGroupSemantic::from(&amp;other.semantics), &gt;- tags: &amp;other.tags &gt;+ tags: &amp;other.tags, &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_group_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::Group) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_groups(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_groups: *mut RustSdpAttributeGroup) { &gt;- let attrs: Vec&lt;_&gt; = (*attributes).iter().filter_map(|x| if let SdpAttribute::Group(ref data) = *x { &gt;- Some(RustSdpAttributeGroup::from(data)) &gt;- } else { &gt;- None &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_groups( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_groups: *mut RustSdpAttributeGroup, &gt;+) { &gt;+ let attrs: Vec&lt;_&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::Group(ref data) = *x { &gt;+ Some(RustSdpAttributeGroup::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; let groups = slice::from_raw_parts_mut(ret_groups, ret_size); &gt; groups.copy_from_slice(attrs.as_slice()); &gt; } &gt; &gt; #[repr(C)] &gt; pub struct RustSdpAttributeRtcp { &gt; pub port: uint32_t, &gt; pub unicast_addr: RustIpAddr, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeRtcp&gt; for RustSdpAttributeRtcp { &gt; fn from(other: &amp;SdpAttributeRtcp) -&gt; Self { &gt; RustSdpAttributeRtcp { &gt; port: other.port as u32, &gt;- unicast_addr: RustIpAddr::from(&amp;other.unicast_addr) &gt;+ unicast_addr: RustIpAddr::from(&amp;other.unicast_addr), &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_rtcp(attributes: *const Vec&lt;SdpAttribute&gt;, ret: *mut RustSdpAttributeRtcp) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_get_rtcp( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret: *mut RustSdpAttributeRtcp, &gt;+) -&gt; nsresult { &gt; let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Rtcp); &gt; if let Some(&amp;SdpAttribute::Rtcp(ref data)) = attr { &gt; *ret = RustSdpAttributeRtcp::from(data); &gt; return NS_OK; &gt; } &gt; NS_ERROR_INVALID_ARG &gt; } &gt; &gt;- &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeRtcpFb { &gt; pub payload_type: u32, &gt; pub feedback_type: u32, &gt; pub parameter: StringView, &gt;- pub extra: StringView &gt;+ pub extra: StringView, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeRtcpFb&gt; for RustSdpAttributeRtcpFb { &gt; fn from(other: &amp;SdpAttributeRtcpFb) -&gt; Self { &gt; RustSdpAttributeRtcpFb { &gt;- payload_type: match other.payload_type{ &gt;+ payload_type: match other.payload_type { &gt; SdpAttributePayloadType::Wildcard =&gt; u32::max_value(), &gt; SdpAttributePayloadType::PayloadType(x) =&gt; x as u32, &gt; }, &gt; feedback_type: other.feedback_type.clone() as u32, &gt; parameter: StringView::from(other.parameter.as_str()), &gt; extra: StringView::from(other.extra.as_str()), &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_rtcpfb_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::Rtcpfb) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_rtcpfbs(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_rtcpfbs: *mut RustSdpAttributeRtcpFb) { &gt;- let attrs: Vec&lt;_&gt; = (*attributes).iter().filter_map(|x| if let SdpAttribute::Rtcpfb(ref data) = *x { &gt;- Some(RustSdpAttributeRtcpFb::from(data)) &gt;- } else { &gt;- None &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_rtcpfbs( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_rtcpfbs: *mut RustSdpAttributeRtcpFb, &gt;+) { &gt;+ let attrs: Vec&lt;_&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::Rtcpfb(ref data) = *x { &gt;+ Some(RustSdpAttributeRtcpFb::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; let rtcpfbs = slice::from_raw_parts_mut(ret_rtcpfbs, ret_size); &gt; rtcpfbs.clone_from_slice(attrs.as_slice()); &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeImageAttrXYRange { &gt; // range &gt; pub min: uint32_t, &gt; pub max: uint32_t, &gt; pub step: uint32_t, &gt; &gt; // discrete values &gt; pub discrete_values: *const Vec&lt;u32&gt;, &gt; } &gt; &gt;-impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeImageAttrXYRange &gt; for RustSdpAttributeImageAttrXYRange { &gt;+impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeImageAttrXYRange&gt; for RustSdpAttributeImageAttrXYRange { &gt; fn from(other: &amp;SdpAttributeImageAttrXYRange) -&gt; Self { &gt; match other { &gt; &amp;SdpAttributeImageAttrXYRange::Range(min, max, step) =&gt; { &gt; RustSdpAttributeImageAttrXYRange { &gt; min, &gt; max, &gt; step: step.unwrap_or(1), &gt; discrete_values: ptr::null(), &gt; } &gt;- }, &gt;+ } &gt; &amp;SdpAttributeImageAttrXYRange::DiscreteValues(ref discrete_values) =&gt; { &gt; RustSdpAttributeImageAttrXYRange { &gt; min: 0, &gt; max: 1, &gt; step: 1, &gt; discrete_values, &gt; } &gt; } &gt;@@ -699,46 +808,44 @@ pub struct RustSdpAttributeImageAttrSRange { &gt; &gt; // discrete values &gt; pub discrete_values: *const Vec&lt;c_float&gt;, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeImageAttrSRange&gt; for RustSdpAttributeImageAttrSRange { &gt; fn from(other: &amp;SdpAttributeImageAttrSRange) -&gt; Self { &gt; match other { &gt;- &amp;SdpAttributeImageAttrSRange::Range(min, max) =&gt; { &gt;- RustSdpAttributeImageAttrSRange { &gt;- min, &gt;- max, &gt;- discrete_values: ptr::null(), &gt;- } &gt;+ &amp;SdpAttributeImageAttrSRange::Range(min, max) =&gt; RustSdpAttributeImageAttrSRange { &gt;+ min, &gt;+ max, &gt;+ discrete_values: ptr::null(), &gt; }, &gt; &amp;SdpAttributeImageAttrSRange::DiscreteValues(ref discrete_values) =&gt; { &gt; RustSdpAttributeImageAttrSRange { &gt; min: 0.0, &gt; max: 1.0, &gt; discrete_values, &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeImageAttrPRange { &gt; pub min: c_float, &gt; pub max: c_float, &gt; } &gt; &gt;-impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeImageAttrPRange &gt; for RustSdpAttributeImageAttrPRange { &gt;+impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeImageAttrPRange&gt; for RustSdpAttributeImageAttrPRange { &gt; fn from(other: &amp;SdpAttributeImageAttrPRange) -&gt; Self { &gt; RustSdpAttributeImageAttrPRange { &gt; min: other.min, &gt;- max: other.max &gt;+ max: other.max, &gt; } &gt; } &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeImageAttrSet { &gt; pub x: RustSdpAttributeImageAttrXYRange, &gt;@@ -748,84 +855,85 @@ pub struct RustSdpAttributeImageAttrSet { &gt; pub sar: RustSdpAttributeImageAttrSRange, &gt; &gt; pub has_par: bool, &gt; pub par: RustSdpAttributeImageAttrPRange, &gt; &gt; pub q: c_float, &gt; } &gt; &gt;-impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeImageAttrSet &gt; for RustSdpAttributeImageAttrSet { &gt;+impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeImageAttrSet&gt; for RustSdpAttributeImageAttrSet { &gt; fn from(other: &amp;SdpAttributeImageAttrSet) -&gt; Self { &gt; RustSdpAttributeImageAttrSet { &gt; x: RustSdpAttributeImageAttrXYRange::from(&amp;other.x), &gt; y: RustSdpAttributeImageAttrXYRange::from(&amp;other.y), &gt; &gt; has_sar: other.sar.is_some(), &gt; sar: match other.sar { &gt; Some(ref x) =&gt; RustSdpAttributeImageAttrSRange::from(x), &gt; // This is just any valid value accepted by rust, &gt; // it might as well by uninitilized &gt; None =&gt; RustSdpAttributeImageAttrSRange::from( &gt;- &amp;SdpAttributeImageAttrSRange::DiscreteValues(vec![])) &gt;+ &amp;SdpAttributeImageAttrSRange::DiscreteValues(vec![]), &gt;+ ), &gt; }, &gt; &gt; has_par: other.par.is_some(), &gt; par: match other.par { &gt; Some(ref x) =&gt; RustSdpAttributeImageAttrPRange::from(x), &gt; // This is just any valid value accepted by rust, &gt; // it might as well by uninitilized &gt;- None =&gt; RustSdpAttributeImageAttrPRange { &gt;- min: 0.0, &gt;- max: 1.0, &gt;- } &gt;+ None =&gt; RustSdpAttributeImageAttrPRange { min: 0.0, max: 1.0 }, &gt; }, &gt; &gt; q: other.q.unwrap_or(0.5), &gt; } &gt; } &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeImageAttrSetList { &gt;- pub sets: *const Vec&lt;SdpAttributeImageAttrSet&gt; &gt;+ pub sets: *const Vec&lt;SdpAttributeImageAttrSet&gt;, &gt; } &gt; &gt;-impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeImageAttrSetList &gt; for RustSdpAttributeImageAttrSetList { &gt;+impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeImageAttrSetList&gt; for RustSdpAttributeImageAttrSetList { &gt; fn from(other: &amp;SdpAttributeImageAttrSetList) -&gt; Self { &gt; match other { &gt;- &amp;SdpAttributeImageAttrSetList::Wildcard =&gt; &gt;- RustSdpAttributeImageAttrSetList{ &gt;- sets: ptr::null(), &gt;- }, &gt;- &amp;SdpAttributeImageAttrSetList::Sets(ref sets) =&gt; &gt;- RustSdpAttributeImageAttrSetList { &gt;- sets: sets, &gt;+ &amp;SdpAttributeImageAttrSetList::Wildcard =&gt; { &gt;+ RustSdpAttributeImageAttrSetList { sets: ptr::null() } &gt;+ } &gt;+ &amp;SdpAttributeImageAttrSetList::Sets(ref sets) =&gt; { &gt;+ RustSdpAttributeImageAttrSetList { sets: sets } &gt; } &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_imageattr_get_set_count(sets: *const Vec&lt;SdpAttributeImageAttrSet&gt;) &gt;- -&gt; size_t { &gt;+pub unsafe extern "C" fn sdp_imageattr_get_set_count( &gt;+ sets: *const Vec&lt;SdpAttributeImageAttrSet&gt;, &gt;+) -&gt; size_t { &gt; (*sets).len() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_imageattr_get_sets(sets: *const Vec&lt;SdpAttributeImageAttrSet&gt;, &gt;- ret_size: size_t, &gt;- ret: *mut RustSdpAttributeImageAttrSet) { &gt;- let rust_sets: Vec&lt;_&gt; = (*sets).iter().map(RustSdpAttributeImageAttrSet::from).collect(); &gt;+pub unsafe extern "C" fn sdp_imageattr_get_sets( &gt;+ sets: *const Vec&lt;SdpAttributeImageAttrSet&gt;, &gt;+ ret_size: size_t, &gt;+ ret: *mut RustSdpAttributeImageAttrSet, &gt;+) { &gt;+ let rust_sets: Vec&lt;_&gt; = (*sets) &gt;+ .iter() &gt;+ .map(RustSdpAttributeImageAttrSet::from) &gt;+ .collect(); &gt; let sets = slice::from_raw_parts_mut(ret, ret_size); &gt; sets.clone_from_slice(rust_sets.as_slice()); &gt; } &gt; &gt;- &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeImageAttr { &gt; pub pt: u32, &gt; pub send: RustSdpAttributeImageAttrSetList, &gt; pub recv: RustSdpAttributeImageAttrSetList, &gt; } &gt; &gt;@@ -837,107 +945,125 @@ impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeImageAttr&gt; for RustSdpAttributeImageAttr { &gt; SdpAttributePayloadType::PayloadType(x) =&gt; x as u32, &gt; }, &gt; send: RustSdpAttributeImageAttrSetList::from(&amp;other.send), &gt; recv: RustSdpAttributeImageAttrSetList::from(&amp;other.recv), &gt; } &gt; } &gt; } &gt; &gt;- &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_imageattr_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::ImageAttr) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_imageattrs(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_attrs: *mut RustSdpAttributeImageAttr) { &gt;- let attrs: Vec&lt;_&gt; = (*attributes).iter().filter_map(|x| if let SdpAttribute::ImageAttr(ref data) = *x { &gt;- Some(RustSdpAttributeImageAttr::from(data)) &gt;- } else { &gt;- None &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_imageattrs( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_attrs: *mut RustSdpAttributeImageAttr, &gt;+) { &gt;+ let attrs: Vec&lt;_&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::ImageAttr(ref data) = *x { &gt;+ Some(RustSdpAttributeImageAttr::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; let imageattrs = slice::from_raw_parts_mut(ret_attrs, ret_size); &gt; imageattrs.copy_from_slice(attrs.as_slice()); &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeSctpmap { &gt; pub port: uint32_t, &gt; pub channels: uint32_t, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeSctpmap&gt; for RustSdpAttributeSctpmap { &gt; fn from(other: &amp;SdpAttributeSctpmap) -&gt; Self { &gt; RustSdpAttributeSctpmap { &gt; port: other.port as u32, &gt;- channels: other.channels &gt;+ channels: other.channels, &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_sctpmap_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::Sctpmap) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_sctpmaps(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_sctpmaps: *mut RustSdpAttributeSctpmap) { &gt;- let attrs: Vec&lt;_&gt; = (*attributes).iter().filter_map(|x| if let SdpAttribute::Sctpmap(ref data) = *x { &gt;- Some(RustSdpAttributeSctpmap::from(data)) &gt;- } else { &gt;- None &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_sctpmaps( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_sctpmaps: *mut RustSdpAttributeSctpmap, &gt;+) { &gt;+ let attrs: Vec&lt;_&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::Sctpmap(ref data) = *x { &gt;+ Some(RustSdpAttributeSctpmap::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; let sctpmaps = slice::from_raw_parts_mut(ret_sctpmaps, ret_size); &gt; sctpmaps.copy_from_slice(attrs.as_slice()); &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeSimulcastId { &gt; pub id: StringView, &gt; pub paused: bool, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeSimulcastId&gt; for RustSdpAttributeSimulcastId { &gt; fn from(other: &amp;SdpAttributeSimulcastId) -&gt; Self { &gt;- RustSdpAttributeSimulcastId{ &gt;+ RustSdpAttributeSimulcastId { &gt; id: StringView::from(other.id.as_str()), &gt;- paused: other.paused &gt;+ paused: other.paused, &gt; } &gt; } &gt; } &gt; &gt;- &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeSimulcastVersion { &gt;- pub ids: *const Vec&lt;SdpAttributeSimulcastId&gt; &gt;+ pub ids: *const Vec&lt;SdpAttributeSimulcastId&gt;, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeSimulcastVersion&gt; for RustSdpAttributeSimulcastVersion { &gt; fn from(other: &amp;SdpAttributeSimulcastVersion) -&gt; Self { &gt;- RustSdpAttributeSimulcastVersion { &gt;- ids: &amp;other.ids, &gt;- } &gt;+ RustSdpAttributeSimulcastVersion { ids: &amp;other.ids } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_simulcast_get_ids_count(ids: *const Vec&lt;SdpAttributeSimulcastId&gt;) &gt;- -&gt; size_t { &gt;+pub unsafe extern "C" fn sdp_simulcast_get_ids_count( &gt;+ ids: *const Vec&lt;SdpAttributeSimulcastId&gt;, &gt;+) -&gt; size_t { &gt; (*ids).len() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_simulcast_get_ids(ids: *const Vec&lt;SdpAttributeSimulcastId&gt;, &gt;- ret_size: size_t, &gt;- ret: *mut RustSdpAttributeSimulcastId) { &gt;- let rust_ids: Vec&lt;_&gt; = (*ids).iter().map(RustSdpAttributeSimulcastId::from).collect(); &gt;+pub unsafe extern "C" fn sdp_simulcast_get_ids( &gt;+ ids: *const Vec&lt;SdpAttributeSimulcastId&gt;, &gt;+ ret_size: size_t, &gt;+ ret: *mut RustSdpAttributeSimulcastId, &gt;+) { &gt;+ let rust_ids: Vec&lt;_&gt; = (*ids) &gt;+ .iter() &gt;+ .map(RustSdpAttributeSimulcastId::from) &gt;+ .collect(); &gt; let ids = slice::from_raw_parts_mut(ret, ret_size); &gt; ids.clone_from_slice(rust_ids.as_slice()); &gt; } &gt; &gt; #[repr(C)] &gt; pub struct RustSdpAttributeSimulcast { &gt; pub send: *const Vec&lt;SdpAttributeSimulcastVersion&gt;, &gt; pub receive: *const Vec&lt;SdpAttributeSimulcastVersion&gt;, &gt;@@ -949,172 +1075,185 @@ impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeSimulcast&gt; for RustSdpAttributeSimulcast { &gt; send: &amp;other.send, &gt; receive: &amp;other.receive, &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_simulcast_get_version_count( &gt;- version_list: *const Vec&lt;SdpAttributeSimulcastVersion&gt;) &gt;- -&gt; size_t { &gt;+ version_list: *const Vec&lt;SdpAttributeSimulcastVersion&gt;, &gt;+) -&gt; size_t { &gt; (*version_list).len() &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_simulcast_get_versions( &gt;- version_list: *const Vec&lt;SdpAttributeSimulcastVersion&gt;, &gt;- ret_size: size_t, ret: *mut RustSdpAttributeSimulcastVersion) { &gt;- let rust_versions_list: Vec&lt;_&gt; = (*version_list).iter() &gt;- .map(RustSdpAttributeSimulcastVersion::from) &gt;- .collect(); &gt;+ version_list: *const Vec&lt;SdpAttributeSimulcastVersion&gt;, &gt;+ ret_size: size_t, &gt;+ ret: *mut RustSdpAttributeSimulcastVersion, &gt;+) { &gt;+ let rust_versions_list: Vec&lt;_&gt; = (*version_list) &gt;+ .iter() &gt;+ .map(RustSdpAttributeSimulcastVersion::from) &gt;+ .collect(); &gt; let versions = slice::from_raw_parts_mut(ret, ret_size); &gt; versions.clone_from_slice(rust_versions_list.as_slice()) &gt; } &gt; &gt;- &gt;- &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_simulcast(attributes: *const Vec&lt;SdpAttribute&gt;, &gt;- ret: *mut RustSdpAttributeSimulcast) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_get_simulcast( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret: *mut RustSdpAttributeSimulcast, &gt;+) -&gt; nsresult { &gt; let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Simulcast); &gt; if let Some(&amp;SdpAttribute::Simulcast(ref data)) = attr { &gt; *ret = RustSdpAttributeSimulcast::from(data); &gt; return NS_OK; &gt; } &gt; NS_ERROR_INVALID_ARG &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub enum RustDirection { &gt; Recvonly, &gt; Sendonly, &gt; Sendrecv, &gt;- Inactive &gt;+ Inactive, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a Option&lt;SdpAttributeDirection&gt;&gt; for RustDirection { &gt; fn from(other: &amp;Option&lt;SdpAttributeDirection&gt;) -&gt; Self { &gt; match *other { &gt;- Some(ref direction) =&gt; { &gt;- match *direction { &gt;- SdpAttributeDirection::Recvonly =&gt; RustDirection::Recvonly, &gt;- SdpAttributeDirection::Sendonly =&gt; RustDirection::Sendonly, &gt;- SdpAttributeDirection::Sendrecv =&gt; RustDirection::Sendrecv &gt;- } &gt;+ Some(ref direction) =&gt; match *direction { &gt;+ SdpAttributeDirection::Recvonly =&gt; RustDirection::Recvonly, &gt;+ SdpAttributeDirection::Sendonly =&gt; RustDirection::Sendonly, &gt;+ SdpAttributeDirection::Sendrecv =&gt; RustDirection::Sendrecv, &gt; }, &gt;- None =&gt; RustDirection::Inactive &gt;+ None =&gt; RustDirection::Inactive, &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_direction(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; RustDirection { &gt; for attribute in (*attributes).iter() { &gt; match *attribute { &gt; SdpAttribute::Recvonly =&gt; { &gt; return RustDirection::Recvonly; &gt;- }, &gt;+ } &gt; SdpAttribute::Sendonly =&gt; { &gt; return RustDirection::Sendonly; &gt;- }, &gt;+ } &gt; SdpAttribute::Sendrecv =&gt; { &gt; return RustDirection::Sendrecv; &gt;- }, &gt;+ } &gt; SdpAttribute::Inactive =&gt; { &gt; return RustDirection::Inactive; &gt;- }, &gt;- _ =&gt; () &gt;+ } &gt;+ _ =&gt; (), &gt; } &gt; } &gt; RustDirection::Sendrecv &gt; } &gt; &gt; #[repr(C)] &gt; pub struct RustSdpAttributeRemoteCandidate { &gt; pub component: uint32_t, &gt; pub address: RustIpAddr, &gt; pub port: uint32_t, &gt; } &gt; &gt;- &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeRemoteCandidate&gt; for RustSdpAttributeRemoteCandidate { &gt; fn from(other: &amp;SdpAttributeRemoteCandidate) -&gt; Self { &gt; RustSdpAttributeRemoteCandidate { &gt; component: other.component, &gt; address: RustIpAddr::from(&amp;other.address), &gt;- port: other.port &gt;+ port: other.port, &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_remote_candidate_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt;+pub unsafe extern "C" fn sdp_get_remote_candidate_count( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::RemoteCandidate) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_remote_candidates(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_candidates: *mut RustSdpAttributeRemoteCandidate) { &gt;- let attrs = (*attributes).iter().filter_map(|x| if let SdpAttribute::RemoteCandidate(ref data) = *x { &gt;- Some(RustSdpAttributeRemoteCandidate::from(data)) &gt;- } else { &gt;- None &gt;+pub unsafe extern "C" fn sdp_get_remote_candidates( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_candidates: *mut RustSdpAttributeRemoteCandidate, &gt;+) { &gt;+ let attrs = (*attributes).iter().filter_map(|x| { &gt;+ if let SdpAttribute::RemoteCandidate(ref data) = *x { &gt;+ Some(RustSdpAttributeRemoteCandidate::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt; }); &gt; let candidates = slice::from_raw_parts_mut(ret_candidates, ret_size); &gt; for (source, destination) in attrs.zip(candidates) { &gt; *destination = source &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_candidate_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::Candidate) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_candidates(attributes: *const Vec&lt;SdpAttribute&gt;, _ret_size: size_t, &gt;- ret: *mut *const Vec&lt;String&gt;) { &gt;- let attr_strings: Vec&lt;String&gt; = (*attributes).iter().filter_map( |x| { &gt;- if let SdpAttribute::Candidate(ref attr) = *x { &gt;- // The serialized attribute starts with "candidate:...", this needs to be removed &gt;- Some(attr.to_string()[10..].to_string()) &gt;- } else { &gt;- None &gt;- } &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_candidates( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ _ret_size: size_t, &gt;+ ret: *mut *const Vec&lt;String&gt;, &gt;+) { &gt;+ let attr_strings: Vec&lt;String&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::Candidate(ref attr) = *x { &gt;+ // The serialized attribute starts with "candidate:...", this needs to be removed &gt;+ Some(attr.to_string()[10..].to_string()) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; &gt; *ret = Box::into_raw(Box::from(attr_strings)); &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeRidParameters { &gt; pub max_width: uint32_t, &gt; pub max_height: uint32_t, &gt; pub max_fps: uint32_t, &gt; pub max_fs: uint32_t, &gt; pub max_br: uint32_t, &gt; pub max_pps: uint32_t, &gt;- pub unknown:*const Vec&lt;String&gt; &gt;+ pub unknown: *const Vec&lt;String&gt;, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeRidParameters&gt; for RustSdpAttributeRidParameters { &gt;- fn from(other: &amp;SdpAttributeRidParameters) -&gt; Self { &gt;- RustSdpAttributeRidParameters { &gt;- max_width: other.max_width, &gt;- max_height: other.max_height, &gt;- max_fps: other.max_fps, &gt;- max_fs: other.max_fs, &gt;- max_br: other.max_br, &gt;- max_pps: other.max_pps, &gt;+ fn from(other: &amp;SdpAttributeRidParameters) -&gt; Self { &gt;+ RustSdpAttributeRidParameters { &gt;+ max_width: other.max_width, &gt;+ max_height: other.max_height, &gt;+ max_fps: other.max_fps, &gt;+ max_fs: other.max_fs, &gt;+ max_br: other.max_br, &gt;+ max_pps: other.max_pps, &gt; &gt;- unknown: &amp;other.unknown &gt;- } &gt;- } &gt;+ unknown: &amp;other.unknown, &gt;+ } &gt;+ } &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeRid { &gt; pub id: StringView, &gt; pub direction: uint32_t, &gt; pub formats: *const Vec&lt;uint16_t&gt;, &gt;@@ -1135,55 +1274,71 @@ impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeRid&gt; for RustSdpAttributeRid { &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_rid_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::Rid) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_rids(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_rids: *mut RustSdpAttributeRid) { &gt;- let attrs: Vec&lt;_&gt; = (*attributes).iter().filter_map(|x| if let SdpAttribute::Rid(ref data) = *x { &gt;- Some(RustSdpAttributeRid::from(data)) &gt;- } else { &gt;- None &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_rids( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_rids: *mut RustSdpAttributeRid, &gt;+) { &gt;+ let attrs: Vec&lt;_&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::Rid(ref data) = *x { &gt;+ Some(RustSdpAttributeRid::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; let rids = slice::from_raw_parts_mut(ret_rids, ret_size); &gt; rids.clone_from_slice(attrs.as_slice()); &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct RustSdpAttributeExtmap { &gt; pub id: uint16_t, &gt; pub direction_specified: bool, &gt; pub direction: RustDirection, &gt; pub url: StringView, &gt;- pub extension_attributes: StringView &gt;+ pub extension_attributes: StringView, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpAttributeExtmap&gt; for RustSdpAttributeExtmap { &gt; fn from(other: &amp;SdpAttributeExtmap) -&gt; Self { &gt; RustSdpAttributeExtmap { &gt;- id : other.id as uint16_t, &gt;+ id: other.id as uint16_t, &gt; direction_specified: other.direction.is_some(), &gt; direction: RustDirection::from(&amp;other.direction), &gt; url: StringView::from(other.url.as_str()), &gt;- extension_attributes: StringView::from(&amp;other.extension_attributes) &gt;+ extension_attributes: StringView::from(&amp;other.extension_attributes), &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_extmap_count(attributes: *const Vec&lt;SdpAttribute&gt;) -&gt; size_t { &gt; count_attribute((*attributes).as_slice(), SdpAttributeType::Extmap) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_extmaps(attributes: *const Vec&lt;SdpAttribute&gt;, ret_size: size_t, ret_rids: *mut RustSdpAttributeExtmap) { &gt;- let attrs: Vec&lt;_&gt; = (*attributes).iter().filter_map(|x| if let SdpAttribute::Extmap(ref data) = *x { &gt;- Some(RustSdpAttributeExtmap::from(data)) &gt;- } else { &gt;- None &gt;- }).collect(); &gt;+pub unsafe extern "C" fn sdp_get_extmaps( &gt;+ attributes: *const Vec&lt;SdpAttribute&gt;, &gt;+ ret_size: size_t, &gt;+ ret_rids: *mut RustSdpAttributeExtmap, &gt;+) { &gt;+ let attrs: Vec&lt;_&gt; = (*attributes) &gt;+ .iter() &gt;+ .filter_map(|x| { &gt;+ if let SdpAttribute::Extmap(ref data) = *x { &gt;+ Some(RustSdpAttributeExtmap::from(data)) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).collect(); &gt; let extmaps = slice::from_raw_parts_mut(ret_rids, ret_size); &gt; extmaps.copy_from_slice(attrs.as_slice()); &gt; } &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs &gt;index e9de855b6add..e736802c73c1 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/lib.rs &gt;@@ -1,63 +1,65 @@ &gt;-extern crate rsdparsa; &gt; extern crate libc; &gt;-#[macro_use] extern crate log; &gt;+extern crate rsdparsa; &gt;+#[macro_use] &gt;+extern crate log; &gt; extern crate nserror; &gt; &gt;-use std::ptr; &gt;-use std::os::raw::c_char; &gt; use std::error::Error; &gt;+use std::os::raw::c_char; &gt;+use std::ptr; &gt; &gt; use libc::size_t; &gt; &gt; use std::rc::Rc; &gt; &gt;-use nserror::{nsresult, NS_OK, NS_ERROR_INVALID_ARG}; &gt;-use rsdparsa::{SdpTiming, SdpBandwidth, SdpSession}; &gt;+use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_OK}; &gt;+use rsdparsa::attribute_type::SdpAttribute; &gt; use rsdparsa::error::SdpParserError; &gt; use rsdparsa::media_type::{SdpMediaValue, SdpProtocolValue}; &gt;-use rsdparsa::attribute_type::{SdpAttribute}; &gt;+use rsdparsa::{SdpBandwidth, SdpSession, SdpTiming}; &gt; &gt;-pub mod types; &gt;-pub mod network; &gt; pub mod attribute; &gt; pub mod media_section; &gt;+pub mod network; &gt;+pub mod types; &gt; &gt;+use network::{get_bandwidth, origin_view_helper, RustSdpConnection, RustSdpOrigin}; &gt; pub use types::{StringView, NULL_STRING}; &gt;-use network::{RustSdpOrigin, origin_view_helper, RustSdpConnection, &gt;- get_bandwidth}; &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn parse_sdp(sdp: StringView, &gt;- fail_on_warning: bool, &gt;- session: *mut *const SdpSession, &gt;- error: *mut *const SdpParserError) -&gt; nsresult { &gt;+pub unsafe extern "C" fn parse_sdp( &gt;+ sdp: StringView, &gt;+ fail_on_warning: bool, &gt;+ session: *mut *const SdpSession, &gt;+ error: *mut *const SdpParserError, &gt;+) -&gt; nsresult { &gt; let sdp_str = match sdp.into() { &gt; Ok(string) =&gt; string, &gt; Err(boxed_error) =&gt; { &gt; *session = ptr::null(); &gt; *error = Box::into_raw(Box::new(SdpParserError::Sequence { &gt; message: (*boxed_error).description().to_string(), &gt; line_number: 0, &gt; })); &gt; return NS_ERROR_INVALID_ARG; &gt; } &gt; }; &gt; &gt; let parser_result = rsdparsa::parse_sdp(&amp;sdp_str, fail_on_warning); &gt; match parser_result { &gt; Ok(parsed) =&gt; { &gt;- *error = match parsed.warnings.len(){ &gt;+ *error = match parsed.warnings.len() { &gt; 0 =&gt; ptr::null(), &gt; _ =&gt; Box::into_raw(Box::new(parsed.warnings[0].clone())), &gt; }; &gt; *session = Rc::into_raw(Rc::new(parsed)); &gt; NS_OK &gt;- }, &gt;+ } &gt; Err(e) =&gt; { &gt; *session = ptr::null(); &gt; debug!("{:?}", e); &gt; debug!("Error parsing SDP in rust: {}", e.description()); &gt; *error = Box::into_raw(Box::new(e)); &gt; NS_ERROR_INVALID_ARG &gt; } &gt; } &gt;@@ -75,167 +77,186 @@ pub unsafe extern "C" fn sdp_new_reference(session: *mut SdpSession) -&gt; *const S &gt; let ret = Rc::into_raw(Rc::clone(&amp;original)); &gt; Rc::into_raw(original); // So the original reference doesn't get dropped &gt; ret &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_error_line_num(error: *mut SdpParserError) -&gt; size_t { &gt; match *error { &gt;- SdpParserError::Line {line_number, ..} | &gt;- SdpParserError::Unsupported { line_number, ..} | &gt;- SdpParserError::Sequence {line_number, ..} =&gt; line_number &gt;+ SdpParserError::Line { line_number, .. } &gt;+ | SdpParserError::Unsupported { line_number, .. } &gt;+ | SdpParserError::Sequence { line_number, .. } =&gt; line_number, &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_error_message(error: *mut SdpParserError) -&gt; StringView { &gt; StringView::from((*error).description()) &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_free_error(error: *mut SdpParserError) { &gt; let e = Box::from_raw(error); &gt; drop(e); &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn get_version(session: *const SdpSession) -&gt; u64 { &gt;+pub unsafe extern "C" fn get_version(session: *const SdpSession) -&gt; u64 { &gt; (*session).get_version() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_origin(session: *const SdpSession) -&gt; RustSdpOrigin { &gt;+pub unsafe extern "C" fn sdp_get_origin(session: *const SdpSession) -&gt; RustSdpOrigin { &gt; origin_view_helper((*session).get_origin()) &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn session_view(session: *const SdpSession) -&gt; StringView { &gt; StringView::from((*session).get_session()) &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_session_has_connection(session: *const SdpSession) -&gt; bool { &gt; (*session).connection.is_some() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_session_connection(session: *const SdpSession, &gt;- connection: *mut RustSdpConnection) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_get_session_connection( &gt;+ session: *const SdpSession, &gt;+ connection: *mut RustSdpConnection, &gt;+) -&gt; nsresult { &gt; match (*session).connection { &gt; Some(ref c) =&gt; { &gt; *connection = RustSdpConnection::from(c); &gt; NS_OK &gt;- }, &gt;- None =&gt; NS_ERROR_INVALID_ARG &gt;+ } &gt;+ None =&gt; NS_ERROR_INVALID_ARG, &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_add_media_section(session: *mut SdpSession, &gt;- media_type: u32, direction: u32, &gt;- port: u16, protocol: u32, &gt;- addr_type: u32, addr: StringView) -&gt; nsresult { &gt;- &gt;- let addr_str:String = match addr.into() { &gt;- Ok(x) =&gt; x, &gt;- Err(boxed_error) =&gt; { &gt;- println!("Error while pasing string, description: {:?}", (*boxed_error).description()); &gt;- return NS_ERROR_INVALID_ARG; &gt;- } &gt;+pub unsafe extern "C" fn sdp_add_media_section( &gt;+ session: *mut SdpSession, &gt;+ media_type: u32, &gt;+ direction: u32, &gt;+ port: u16, &gt;+ protocol: u32, &gt;+ addr_type: u32, &gt;+ addr: StringView, &gt;+) -&gt; nsresult { &gt;+ let addr_str: String = match addr.into() { &gt;+ Ok(x) =&gt; x, &gt;+ Err(boxed_error) =&gt; { &gt;+ println!( &gt;+ "Error while pasing string, description: {:?}", &gt;+ (*boxed_error).description() &gt;+ ); &gt;+ return NS_ERROR_INVALID_ARG; &gt;+ } &gt; }; &gt; &gt; let media_type = match media_type { &gt; 0 =&gt; SdpMediaValue::Audio, // MediaType::kAudio &gt; 1 =&gt; SdpMediaValue::Video, // MediaType::kVideo &gt; 3 =&gt; SdpMediaValue::Application, // MediaType::kApplication &gt; _ =&gt; { &gt;- return NS_ERROR_INVALID_ARG; &gt;- } &gt;+ return NS_ERROR_INVALID_ARG; &gt;+ } &gt; }; &gt; let protocol = match protocol { &gt;- 20 =&gt; SdpProtocolValue::RtpSavpf, // Protocol::kRtpSavpf &gt;- 24 =&gt; SdpProtocolValue::UdpTlsRtpSavpf, // Protocol::kUdpTlsRtpSavpf &gt;- 25 =&gt; SdpProtocolValue::TcpTlsRtpSavpf, // Protocol::kTcpTlsRtpSavpf &gt;- 37 =&gt; SdpProtocolValue::DtlsSctp, // Protocol::kDtlsSctp &gt;- 38 =&gt; SdpProtocolValue::UdpDtlsSctp, // Protocol::kUdpDtlsSctp &gt;- 39 =&gt; SdpProtocolValue::TcpDtlsSctp, // Protocol::kTcpDtlsSctp &gt;+ 20 =&gt; SdpProtocolValue::RtpSavpf, // Protocol::kRtpSavpf &gt;+ 24 =&gt; SdpProtocolValue::UdpTlsRtpSavpf, // Protocol::kUdpTlsRtpSavpf &gt;+ 25 =&gt; SdpProtocolValue::TcpTlsRtpSavpf, // Protocol::kTcpTlsRtpSavpf &gt;+ 37 =&gt; SdpProtocolValue::DtlsSctp, // Protocol::kDtlsSctp &gt;+ 38 =&gt; SdpProtocolValue::UdpDtlsSctp, // Protocol::kUdpDtlsSctp &gt;+ 39 =&gt; SdpProtocolValue::TcpDtlsSctp, // Protocol::kTcpDtlsSctp &gt; _ =&gt; { &gt;- return NS_ERROR_INVALID_ARG; &gt;- } &gt;+ return NS_ERROR_INVALID_ARG; &gt;+ } &gt; }; &gt; let direction = match direction { &gt; 1 =&gt; SdpAttribute::Sendonly, &gt; 2 =&gt; SdpAttribute::Recvonly, &gt; 3 =&gt; SdpAttribute::Sendrecv, &gt; _ =&gt; { &gt;- return NS_ERROR_INVALID_ARG; &gt;- } &gt;+ return NS_ERROR_INVALID_ARG; &gt;+ } &gt; }; &gt; &gt; // Check that the provided address type is valid. The rust parser will find out &gt; // on his own which address type was provided &gt; match addr_type { &gt;- // enum AddrType { kAddrTypeNone, kIPv4, kIPv6 }; &gt;- // kAddrTypeNone is explicitly not covered as it is an 'invalid' flag &gt;- 1...2 =&gt; (), &gt;- _ =&gt; { &gt;- return NS_ERROR_INVALID_ARG; &gt;- } &gt;+ // enum AddrType { kAddrTypeNone, kIPv4, kIPv6 }; &gt;+ // kAddrTypeNone is explicitly not covered as it is an 'invalid' flag &gt;+ 1...2 =&gt; (), &gt;+ _ =&gt; { &gt;+ return NS_ERROR_INVALID_ARG; &gt;+ } &gt; } &gt; &gt; match (*session).add_media(media_type, direction, port as u32, protocol, addr_str) { &gt; Ok(_) =&gt; NS_OK, &gt;- Err(_) =&gt; NS_ERROR_INVALID_ARG &gt;+ Err(_) =&gt; NS_ERROR_INVALID_ARG, &gt; } &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone)] &gt; pub struct RustSdpTiming { &gt; pub start: u64, &gt; pub stop: u64, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpTiming&gt; for RustSdpTiming { &gt; fn from(timing: &amp;SdpTiming) -&gt; Self { &gt;- RustSdpTiming {start: timing.start, stop: timing.stop} &gt;+ RustSdpTiming { &gt;+ start: timing.start, &gt;+ stop: timing.stop, &gt;+ } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_session_has_timing(session: *const SdpSession) -&gt; bool { &gt; (*session).timing.is_some() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_session_timing(session: *const SdpSession, &gt;- timing: *mut RustSdpTiming) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_session_timing( &gt;+ session: *const SdpSession, &gt;+ timing: *mut RustSdpTiming, &gt;+) -&gt; nsresult { &gt; match (*session).timing { &gt; Some(ref t) =&gt; { &gt; *timing = RustSdpTiming::from(t); &gt; NS_OK &gt;- }, &gt;- None =&gt; NS_ERROR_INVALID_ARG &gt;+ } &gt;+ None =&gt; NS_ERROR_INVALID_ARG, &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_media_section_count(session: *const SdpSession) -&gt; size_t { &gt; (*session).media.len() &gt; } &gt; &gt;- &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn get_sdp_bandwidth(session: *const SdpSession, &gt;- bandwidth_type: *const c_char) -&gt; u32 { &gt;+pub unsafe extern "C" fn get_sdp_bandwidth( &gt;+ session: *const SdpSession, &gt;+ bandwidth_type: *const c_char, &gt;+) -&gt; u32 { &gt; get_bandwidth(&amp;(*session).bandwidth, bandwidth_type) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_session_bandwidth_vec(session: *const SdpSession) -&gt; *const Vec&lt;SdpBandwidth&gt; { &gt;+pub unsafe extern "C" fn sdp_get_session_bandwidth_vec( &gt;+ session: *const SdpSession, &gt;+) -&gt; *const Vec&lt;SdpBandwidth&gt; { &gt; &amp;(*session).bandwidth &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn get_sdp_session_attributes(session: *const SdpSession) -&gt; *const Vec&lt;SdpAttribute&gt; { &gt;+pub unsafe extern "C" fn get_sdp_session_attributes( &gt;+ session: *const SdpSession, &gt;+) -&gt; *const Vec&lt;SdpAttribute&gt; { &gt; &amp;(*session).attribute &gt; } &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs &gt;index 6eed578712af..7f0d28488a24 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/media_section.rs &gt;@@ -1,45 +1,46 @@ &gt;-use std::ptr; &gt; use std::os::raw::c_char; &gt;+use std::ptr; &gt; &gt; use libc::{size_t, uint32_t}; &gt; &gt;-use nserror::{nsresult, NS_OK, NS_ERROR_INVALID_ARG}; &gt;-use rsdparsa::{SdpBandwidth, SdpSession}; &gt;-use rsdparsa::media_type::{SdpMedia, SdpMediaValue, SdpProtocolValue, &gt;- SdpFormatList}; &gt;+use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_OK}; &gt; use rsdparsa::attribute_type::{SdpAttribute, SdpAttributeRtpmap}; &gt;+use rsdparsa::media_type::{SdpFormatList, SdpMedia, SdpMediaValue, SdpProtocolValue}; &gt;+use rsdparsa::{SdpBandwidth, SdpSession}; &gt; &gt; use network::{get_bandwidth, RustSdpConnection}; &gt; use types::StringView; &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_media_section(session: *const SdpSession, &gt;- index: size_t) -&gt; *const SdpMedia { &gt;+pub unsafe extern "C" fn sdp_get_media_section( &gt;+ session: *const SdpSession, &gt;+ index: size_t, &gt;+) -&gt; *const SdpMedia { &gt; return match (*session).media.get(index) { &gt; Some(m) =&gt; m, &gt;- None =&gt; ptr::null() &gt;+ None =&gt; ptr::null(), &gt; }; &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub enum RustSdpMediaValue { &gt; Audio, &gt; Video, &gt; Application, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpMediaValue&gt; for RustSdpMediaValue { &gt; fn from(val: &amp;SdpMediaValue) -&gt; Self { &gt; match *val { &gt; SdpMediaValue::Audio =&gt; RustSdpMediaValue::Audio, &gt; SdpMediaValue::Video =&gt; RustSdpMediaValue::Video, &gt;- SdpMediaValue::Application =&gt; RustSdpMediaValue::Application &gt;+ SdpMediaValue::Application =&gt; RustSdpMediaValue::Application, &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_rust_get_media_type(sdp_media: *const SdpMedia) -&gt; RustSdpMediaValue { &gt; RustSdpMediaValue::from((*sdp_media).get_type()) &gt; } &gt;@@ -64,37 +65,41 @@ impl&lt;'a&gt; From&lt;&amp;'a SdpProtocolValue&gt; for RustSdpProtocolValue { &gt; SdpProtocolValue::DtlsSctp =&gt; RustSdpProtocolValue::DtlsSctp, &gt; SdpProtocolValue::UdpDtlsSctp =&gt; RustSdpProtocolValue::UdpDtlsSctp, &gt; SdpProtocolValue::TcpDtlsSctp =&gt; RustSdpProtocolValue::TcpDtlsSctp, &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_media_protocol(sdp_media: *const SdpMedia) -&gt; RustSdpProtocolValue { &gt;+pub unsafe extern "C" fn sdp_get_media_protocol( &gt;+ sdp_media: *const SdpMedia, &gt;+) -&gt; RustSdpProtocolValue { &gt; RustSdpProtocolValue::from((*sdp_media).get_proto()) &gt; } &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub enum RustSdpFormatType { &gt; Integers, &gt;- Strings &gt;+ Strings, &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_format_type(sdp_media: *const SdpMedia) -&gt; RustSdpFormatType { &gt;+pub unsafe extern "C" fn sdp_get_format_type(sdp_media: *const SdpMedia) -&gt; RustSdpFormatType { &gt; match *(*sdp_media).get_formats() { &gt; SdpFormatList::Integers(_) =&gt; RustSdpFormatType::Integers, &gt;- SdpFormatList::Strings(_) =&gt; RustSdpFormatType::Strings &gt;+ SdpFormatList::Strings(_) =&gt; RustSdpFormatType::Strings, &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_format_string_vec(sdp_media: *const SdpMedia) -&gt; *const Vec&lt;String&gt; { &gt;+pub unsafe extern "C" fn sdp_get_format_string_vec( &gt;+ sdp_media: *const SdpMedia, &gt;+) -&gt; *const Vec&lt;String&gt; { &gt; if let SdpFormatList::Strings(ref formats) = *(*sdp_media).get_formats() { &gt; formats &gt; } else { &gt; ptr::null() &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;@@ -117,80 +122,100 @@ pub unsafe extern "C" fn sdp_get_media_port(sdp_media: *const SdpMedia) -&gt; uint3 &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_get_media_port_count(sdp_media: *const SdpMedia) -&gt; uint32_t { &gt; (*sdp_media).get_port_count() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_media_bandwidth(sdp_media: *const SdpMedia, &gt;- bandwidth_type: *const c_char) -&gt; uint32_t { &gt;+pub unsafe extern "C" fn sdp_get_media_bandwidth( &gt;+ sdp_media: *const SdpMedia, &gt;+ bandwidth_type: *const c_char, &gt;+) -&gt; uint32_t { &gt; get_bandwidth((*sdp_media).get_bandwidth(), bandwidth_type) &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_media_bandwidth_vec(sdp_media: *const SdpMedia) -&gt; *const Vec&lt;SdpBandwidth&gt; { &gt;+pub unsafe extern "C" fn sdp_get_media_bandwidth_vec( &gt;+ sdp_media: *const SdpMedia, &gt;+) -&gt; *const Vec&lt;SdpBandwidth&gt; { &gt; (*sdp_media).get_bandwidth() &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_media_has_connection(sdp_media: *const SdpMedia) -&gt; bool { &gt; (*sdp_media).get_connection().is_some() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_media_connection(sdp_media: *const SdpMedia, ret: *mut RustSdpConnection) -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_get_media_connection( &gt;+ sdp_media: *const SdpMedia, &gt;+ ret: *mut RustSdpConnection, &gt;+) -&gt; nsresult { &gt; if let &amp;Some(ref connection) = (*sdp_media).get_connection() { &gt; *ret = RustSdpConnection::from(connection); &gt; return NS_OK; &gt; } &gt; NS_ERROR_INVALID_ARG &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_get_media_attribute_list(sdp_media: *const SdpMedia) -&gt; *const Vec&lt;SdpAttribute&gt; { &gt;+pub unsafe extern "C" fn sdp_get_media_attribute_list( &gt;+ sdp_media: *const SdpMedia, &gt;+) -&gt; *const Vec&lt;SdpAttribute&gt; { &gt; (*sdp_media).get_attributes() &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_media_clear_codecs(sdp_media: *mut SdpMedia) { &gt; (*sdp_media).remove_codecs() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_media_add_codec(sdp_media: *mut SdpMedia, pt: u8, &gt;- codec_name: StringView, clockrate: u32, &gt;- channels: u16) -&gt; nsresult { &gt;- let rtpmap = SdpAttributeRtpmap{ &gt;- payload_type: pt, &gt;- codec_name: match codec_name.into() { &gt;- Ok(x) =&gt; x, &gt;- Err(boxed_error) =&gt; { &gt;- println!("Error while pasing string, description: {:?}", (*boxed_error).description()); &gt;- return NS_ERROR_INVALID_ARG; &gt;- } &gt;- }, &gt;- frequency: clockrate, &gt;- channels: Some(channels as u32), &gt;- }; &gt;+pub unsafe extern "C" fn sdp_media_add_codec( &gt;+ sdp_media: *mut SdpMedia, &gt;+ pt: u8, &gt;+ codec_name: StringView, &gt;+ clockrate: u32, &gt;+ channels: u16, &gt;+) -&gt; nsresult { &gt;+ let rtpmap = SdpAttributeRtpmap { &gt;+ payload_type: pt, &gt;+ codec_name: match codec_name.into() { &gt;+ Ok(x) =&gt; x, &gt;+ Err(boxed_error) =&gt; { &gt;+ println!( &gt;+ "Error while pasing string, description: {:?}", &gt;+ (*boxed_error).description() &gt;+ ); &gt;+ return NS_ERROR_INVALID_ARG; &gt;+ } &gt;+ }, &gt;+ frequency: clockrate, &gt;+ channels: Some(channels as u32), &gt;+ }; &gt; &gt; match (*sdp_media).add_codec(rtpmap) { &gt; Ok(_) =&gt; NS_OK, &gt; Err(_) =&gt; NS_ERROR_INVALID_ARG, &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn sdp_media_add_datachannel(sdp_media: *mut SdpMedia, name: StringView, &gt;- port: u16, streams: u16, message_size: u32) &gt;- -&gt; nsresult { &gt;+pub unsafe extern "C" fn sdp_media_add_datachannel( &gt;+ sdp_media: *mut SdpMedia, &gt;+ name: StringView, &gt;+ port: u16, &gt;+ streams: u16, &gt;+ message_size: u32, &gt;+) -&gt; nsresult { &gt; let name_str = match name.into() { &gt; Ok(x) =&gt; x, &gt; Err(_) =&gt; { &gt; return NS_ERROR_INVALID_ARG; &gt; } &gt; }; &gt;- match (*sdp_media).add_datachannel(name_str, port, streams, message_size){ &gt;+ match (*sdp_media).add_datachannel(name_str, port, streams, message_size) { &gt; Ok(_) =&gt; NS_OK, &gt;- Err(_) =&gt; NS_ERROR_INVALID_ARG &gt;+ Err(_) =&gt; NS_ERROR_INVALID_ARG, &gt; } &gt; } &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/network.rs b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/network.rs &gt;index a1baf6dc940a..01ede83b98b0 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/network.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/network.rs &gt;@@ -1,134 +1,136 @@ &gt;+use std::ffi::{CStr, CString}; &gt; use std::net::IpAddr; &gt; use std::os::raw::c_char; &gt;-use std::ffi::{CStr, CString}; &gt; &gt;-use libc::{uint8_t, uint64_t}; &gt;+use libc::{uint64_t, uint8_t}; &gt; &gt;-use rsdparsa::{SdpOrigin, SdpConnection, SdpBandwidth}; &gt;+use rsdparsa::{SdpBandwidth, SdpConnection, SdpOrigin}; &gt; &gt; use types::StringView; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy, PartialEq)] &gt; pub enum RustSdpAddrType { &gt; None, &gt; IP4, &gt;- IP6 &gt;+ IP6, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a IpAddr&gt; for RustSdpAddrType { &gt; fn from(addr: &amp;IpAddr) -&gt; RustSdpAddrType { &gt; match *addr { &gt; IpAddr::V4(_) =&gt; RustSdpAddrType::IP4, &gt;- IpAddr::V6(_) =&gt; RustSdpAddrType::IP6 &gt;+ IpAddr::V6(_) =&gt; RustSdpAddrType::IP6, &gt; } &gt; } &gt; } &gt; &gt; pub fn get_octets(addr: &amp;IpAddr) -&gt; [u8; 16] { &gt; let mut octets = [0; 16]; &gt; match *addr { &gt; IpAddr::V4(v4_addr) =&gt; { &gt; let v4_octets = v4_addr.octets(); &gt; (&amp;mut octets[0..4]).copy_from_slice(&amp;v4_octets); &gt;- }, &gt;+ } &gt; IpAddr::V6(v6_addr) =&gt; { &gt; let v6_octets = v6_addr.octets(); &gt; octets.copy_from_slice(&amp;v6_octets); &gt; } &gt; } &gt; octets &gt; } &gt; &gt; #[repr(C)] &gt; pub struct RustIpAddr { &gt; addr_type: RustSdpAddrType, &gt;- unicast_addr: [u8; 50] &gt;+ unicast_addr: [u8; 50], &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a IpAddr&gt; for RustIpAddr { &gt; fn from(addr: &amp;IpAddr) -&gt; Self { &gt; let mut c_addr = [0; 50]; &gt; let str_addr = format!("{}", addr); &gt; let str_bytes = str_addr.as_bytes(); &gt; if str_bytes.len() &lt; 50 { &gt; c_addr[..str_bytes.len()].copy_from_slice(&amp;str_bytes); &gt; } &gt;- RustIpAddr {addr_type: RustSdpAddrType::from(addr), &gt;- unicast_addr: c_addr } &gt;+ RustIpAddr { &gt;+ addr_type: RustSdpAddrType::from(addr), &gt;+ unicast_addr: c_addr, &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a Option&lt;IpAddr&gt;&gt; for RustIpAddr { &gt; fn from(addr: &amp;Option&lt;IpAddr&gt;) -&gt; Self { &gt; match *addr { &gt; Some(ref x) =&gt; RustIpAddr::from(x), &gt; None =&gt; RustIpAddr { &gt; addr_type: RustSdpAddrType::None, &gt;- unicast_addr: [0; 50] &gt;- } &gt;+ unicast_addr: [0; 50], &gt;+ }, &gt; } &gt; } &gt; } &gt; &gt; #[repr(C)] &gt; pub struct RustSdpConnection { &gt; pub addr: RustIpAddr, &gt; pub ttl: uint8_t, &gt;- pub amount: uint64_t &gt;+ pub amount: uint64_t, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a SdpConnection&gt; for RustSdpConnection { &gt; fn from(sdp_connection: &amp;SdpConnection) -&gt; Self { &gt; let ttl = match sdp_connection.ttl { &gt; Some(x) =&gt; x as u8, &gt;- None =&gt; 0 &gt;+ None =&gt; 0, &gt; }; &gt; let amount = match sdp_connection.amount { &gt; Some(x) =&gt; x as u64, &gt;- None =&gt; 0 &gt;+ None =&gt; 0, &gt; }; &gt;- RustSdpConnection { addr: RustIpAddr::from(&amp;sdp_connection.addr), &gt;- ttl: ttl, amount: amount } &gt;+ RustSdpConnection { &gt;+ addr: RustIpAddr::from(&amp;sdp_connection.addr), &gt;+ ttl: ttl, &gt;+ amount: amount, &gt;+ } &gt; } &gt; } &gt; &gt; #[repr(C)] &gt; pub struct RustSdpOrigin { &gt; username: StringView, &gt; session_id: u64, &gt; session_version: u64, &gt; addr: RustIpAddr, &gt; } &gt; &gt;- &gt; fn bandwidth_match(str_bw: &amp;str, enum_bw: &amp;SdpBandwidth) -&gt; bool { &gt; match *enum_bw { &gt; SdpBandwidth::As(_) =&gt; str_bw == "AS", &gt; SdpBandwidth::Ct(_) =&gt; str_bw == "CT", &gt; SdpBandwidth::Tias(_) =&gt; str_bw == "TIAS", &gt; SdpBandwidth::Unknown(ref type_name, _) =&gt; str_bw == type_name, &gt; } &gt; } &gt; &gt; fn bandwidth_value(bandwidth: &amp;SdpBandwidth) -&gt; u32 { &gt; match *bandwidth { &gt;- SdpBandwidth::As(x) | SdpBandwidth::Ct(x) | &gt;- SdpBandwidth::Tias(x) =&gt; x, &gt;- SdpBandwidth::Unknown(_, _) =&gt; 0 &gt;+ SdpBandwidth::As(x) | SdpBandwidth::Ct(x) | SdpBandwidth::Tias(x) =&gt; x, &gt;+ SdpBandwidth::Unknown(_, _) =&gt; 0, &gt; } &gt; } &gt; &gt;-pub unsafe fn get_bandwidth(bandwidths: &amp;Vec&lt;SdpBandwidth&gt;, &gt;- bandwidth_type: *const c_char) -&gt; u32 { &gt;+pub unsafe fn get_bandwidth(bandwidths: &amp;Vec&lt;SdpBandwidth&gt;, bandwidth_type: *const c_char) -&gt; u32 { &gt; let bw_type = match CStr::from_ptr(bandwidth_type).to_str() { &gt; Ok(string) =&gt; string, &gt;- Err(_) =&gt; return 0 &gt;+ Err(_) =&gt; return 0, &gt; }; &gt; for bandwidth in bandwidths.iter() { &gt; if bandwidth_match(bw_type, bandwidth) { &gt; return bandwidth_value(bandwidth); &gt; } &gt; } &gt; 0 &gt; } &gt;@@ -137,44 +139,44 @@ pub unsafe fn get_bandwidth(bandwidths: &amp;Vec&lt;SdpBandwidth&gt;, &gt; pub unsafe extern "C" fn sdp_serialize_bandwidth(bw: *const Vec&lt;SdpBandwidth&gt;) -&gt; *mut c_char { &gt; let mut builder = String::new(); &gt; for bandwidth in (*bw).iter() { &gt; match *bandwidth { &gt; SdpBandwidth::As(val) =&gt; { &gt; builder.push_str("b=AS:"); &gt; builder.push_str(&amp;val.to_string()); &gt; builder.push_str("\r\n"); &gt;- }, &gt;+ } &gt; SdpBandwidth::Ct(val) =&gt; { &gt; builder.push_str("b=CT:"); &gt; builder.push_str(&amp;val.to_string()); &gt; builder.push_str("\r\n"); &gt;- }, &gt;+ } &gt; SdpBandwidth::Tias(val) =&gt; { &gt; builder.push_str("b=TIAS:"); &gt; builder.push_str(&amp;val.to_string()); &gt; builder.push_str("\r\n"); &gt;- }, &gt;+ } &gt; SdpBandwidth::Unknown(ref name, val) =&gt; { &gt; builder.push_str("b="); &gt; builder.push_str(name.as_str()); &gt; builder.push(':'); &gt; builder.push_str(&amp;val.to_string()); &gt; builder.push_str("\r\n"); &gt;- }, &gt;+ } &gt; } &gt; } &gt; CString::from_vec_unchecked(builder.into_bytes()).into_raw() &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn sdp_free_string(s: *mut c_char) { &gt; drop(CString::from_raw(s)); &gt; } &gt; &gt; pub unsafe fn origin_view_helper(origin: &amp;SdpOrigin) -&gt; RustSdpOrigin { &gt; RustSdpOrigin { &gt; username: StringView::from(origin.username.as_str()), &gt; session_id: origin.session_id, &gt; session_version: origin.session_version, &gt;- addr: RustIpAddr::from(&amp;origin.unicast_addr) &gt;+ addr: RustIpAddr::from(&amp;origin.unicast_addr), &gt; } &gt; } &gt;diff --git a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/types.rs b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/types.rs &gt;index 8e4674c26cbf..ce90e0e05ddf 100644 &gt;--- a/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/types.rs &gt;+++ b/media/webrtc/signaling/src/sdp/rsdparsa_capi/src/types.rs &gt;@@ -1,155 +1,175 @@ &gt;-use libc::{size_t, uint8_t, uint16_t, uint32_t}; &gt;-use std::ffi::CStr; &gt;-use std::{str, slice}; &gt;-use std::error::Error; &gt;+use libc::{size_t, uint16_t, uint32_t, uint8_t}; &gt; use std::boxed::Box; &gt;+use std::error::Error; &gt;+use std::ffi::CStr; &gt;+use std::{slice, str}; &gt; &gt;-use nserror::{nsresult, NS_OK, NS_ERROR_INVALID_ARG}; &gt;+use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_OK}; &gt; &gt; #[repr(C)] &gt; #[derive(Clone, Copy)] &gt; pub struct StringView { &gt; buffer: *const u8, &gt;- len: size_t &gt;+ len: size_t, &gt; } &gt; &gt;-pub const NULL_STRING: StringView = StringView { buffer: 0 as *const u8, &gt;- len: 0 }; &gt;+pub const NULL_STRING: StringView = StringView { &gt;+ buffer: 0 as *const u8, &gt;+ len: 0, &gt;+}; &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a str&gt; for StringView { &gt; fn from(input: &amp;str) -&gt; StringView { &gt;- StringView { buffer: input.as_ptr(), len: input.len()} &gt;+ StringView { &gt;+ buffer: input.as_ptr(), &gt;+ len: input.len(), &gt;+ } &gt; } &gt; } &gt; &gt;-impl Into&lt;Result&lt;String,Box&lt;Error&gt;&gt;&gt; for StringView { &gt;- fn into(self) -&gt; Result&lt;String,Box&lt;Error&gt;&gt; { &gt;- &gt;+impl Into&lt;Result&lt;String, Box&lt;Error&gt;&gt;&gt; for StringView { &gt;+ fn into(self) -&gt; Result&lt;String, Box&lt;Error&gt;&gt; { &gt; // This block must be unsafe as it converts a StringView, most likly provided from the &gt; // C++ code, into a rust String and thus needs to operate with raw pointers. &gt; let string_slice: &amp;[u8]; &gt; unsafe { &gt; // Add one to the length as the length passed in the StringView is the length of &gt; // the string and is missing the null terminator &gt;- string_slice = slice::from_raw_parts(self.buffer, self.len+1 as usize); &gt;+ string_slice = slice::from_raw_parts(self.buffer, self.len + 1 as usize); &gt; } &gt; &gt;- let c_str = match CStr::from_bytes_with_nul(string_slice) { &gt;- Ok(string) =&gt; string, &gt;- Err(x) =&gt; { return Err(Box::new(x)); }, &gt;- }; &gt;+ let c_str = match CStr::from_bytes_with_nul(string_slice) { &gt;+ Ok(string) =&gt; string, &gt;+ Err(x) =&gt; { &gt;+ return Err(Box::new(x)); &gt;+ } &gt;+ }; &gt; &gt;- let str_slice: &amp;str = match str::from_utf8(c_str.to_bytes()) { &gt;- Ok(string) =&gt; string, &gt;- Err(x) =&gt; { return Err(Box::new(x)); }, &gt;- }; &gt;+ let str_slice: &amp;str = match str::from_utf8(c_str.to_bytes()) { &gt;+ Ok(string) =&gt; string, &gt;+ Err(x) =&gt; { &gt;+ return Err(Box::new(x)); &gt;+ } &gt;+ }; &gt; &gt;- Ok(str_slice.to_string()) &gt;+ Ok(str_slice.to_string()) &gt; } &gt; } &gt; &gt; impl&lt;'a, T: AsRef&lt;str&gt;&gt; From&lt;&amp;'a Option&lt;T&gt;&gt; for StringView { &gt; fn from(input: &amp;Option&lt;T&gt;) -&gt; StringView { &gt; match *input { &gt;- Some(ref x) =&gt; StringView { buffer: x.as_ref().as_ptr(), &gt;- len: x.as_ref().len()}, &gt;- None =&gt; NULL_STRING &gt;+ Some(ref x) =&gt; StringView { &gt;+ buffer: x.as_ref().as_ptr(), &gt;+ len: x.as_ref().len(), &gt;+ }, &gt;+ None =&gt; NULL_STRING, &gt; } &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn string_vec_len(vec: *const Vec&lt;String&gt;) -&gt; size_t { &gt; (*vec).len() as size_t &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn string_vec_get_view(vec: *const Vec&lt;String&gt;, &gt;- index: size_t, &gt;- ret: *mut StringView) -&gt; nsresult { &gt;+pub unsafe extern "C" fn string_vec_get_view( &gt;+ vec: *const Vec&lt;String&gt;, &gt;+ index: size_t, &gt;+ ret: *mut StringView, &gt;+) -&gt; nsresult { &gt; match (*vec).get(index) { &gt; Some(ref string) =&gt; { &gt; *ret = StringView::from(string.as_str()); &gt; NS_OK &gt;- }, &gt;- None =&gt; NS_ERROR_INVALID_ARG &gt;+ } &gt;+ None =&gt; NS_ERROR_INVALID_ARG, &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn free_boxed_string_vec(ptr: *mut Vec&lt;String&gt;) -&gt; nsresult { &gt; drop(Box::from_raw(ptr)); &gt; NS_OK &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn f32_vec_len(vec: *const Vec&lt;f32&gt;) -&gt; size_t { &gt; (*vec).len() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn f32_vec_get(vec: *const Vec&lt;f32&gt;, &gt;- index: size_t, &gt;- ret: *mut f32) -&gt; nsresult { &gt;+pub unsafe extern "C" fn f32_vec_get( &gt;+ vec: *const Vec&lt;f32&gt;, &gt;+ index: size_t, &gt;+ ret: *mut f32, &gt;+) -&gt; nsresult { &gt; match (*vec).get(index) { &gt; Some(val) =&gt; { &gt; *ret = *val; &gt; NS_OK &gt;- }, &gt;- None =&gt; NS_ERROR_INVALID_ARG &gt;+ } &gt;+ None =&gt; NS_ERROR_INVALID_ARG, &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn u32_vec_len(vec: *const Vec&lt;u32&gt;) -&gt; size_t { &gt; (*vec).len() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn u32_vec_get(vec: *const Vec&lt;u32&gt;, &gt;- index: size_t, &gt;- ret: *mut uint32_t) -&gt; nsresult { &gt;+pub unsafe extern "C" fn u32_vec_get( &gt;+ vec: *const Vec&lt;u32&gt;, &gt;+ index: size_t, &gt;+ ret: *mut uint32_t, &gt;+) -&gt; nsresult { &gt; match (*vec).get(index) { &gt; Some(val) =&gt; { &gt; *ret = *val; &gt; NS_OK &gt;- }, &gt;- None =&gt; NS_ERROR_INVALID_ARG &gt;+ } &gt;+ None =&gt; NS_ERROR_INVALID_ARG, &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn u16_vec_len(vec: *const Vec&lt;u16&gt;) -&gt; size_t { &gt; (*vec).len() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn u16_vec_get(vec: *const Vec&lt;u16&gt;, &gt;- index: size_t, &gt;- ret: *mut uint16_t) -&gt; nsresult { &gt;+pub unsafe extern "C" fn u16_vec_get( &gt;+ vec: *const Vec&lt;u16&gt;, &gt;+ index: size_t, &gt;+ ret: *mut uint16_t, &gt;+) -&gt; nsresult { &gt; match (*vec).get(index) { &gt; Some(val) =&gt; { &gt; *ret = *val; &gt; NS_OK &gt;- }, &gt;- None =&gt; NS_ERROR_INVALID_ARG &gt;+ } &gt;+ None =&gt; NS_ERROR_INVALID_ARG, &gt; } &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn u8_vec_len(vec: *const Vec&lt;u8&gt;) -&gt; size_t { &gt; (*vec).len() &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern "C" fn u8_vec_get(vec: *const Vec&lt;u8&gt;, &gt;- index: size_t, &gt;- ret: *mut uint8_t) -&gt; nsresult { &gt;+pub unsafe extern "C" fn u8_vec_get( &gt;+ vec: *const Vec&lt;u8&gt;, &gt;+ index: size_t, &gt;+ ret: *mut uint8_t, &gt;+) -&gt; nsresult { &gt; match (*vec).get(index) { &gt; Some(val) =&gt; { &gt; *ret = *val; &gt; NS_OK &gt;- }, &gt;- None =&gt; NS_ERROR_INVALID_ARG &gt;+ } &gt;+ None =&gt; NS_ERROR_INVALID_ARG, &gt; } &gt; } &gt;diff --git a/modules/libpref/parser/src/lib.rs b/modules/libpref/parser/src/lib.rs &gt;index 8d8b9a6125e4..41c473b70218 100644 &gt;--- a/modules/libpref/parser/src/lib.rs &gt;+++ b/modules/libpref/parser/src/lib.rs &gt;@@ -98,50 +98,65 @@ pub enum PrefType { &gt; Bool, &gt; } &gt; &gt; /// Keep this in sync with PrefValueKind in Preferences.h. &gt; #[derive(Clone, Copy, Debug, PartialEq)] &gt; #[repr(u8)] &gt; pub enum PrefValueKind { &gt; Default, &gt;- User &gt;+ User, &gt; } &gt; &gt; /// Keep this in sync with PrefValue in Preferences.cpp. &gt; #[repr(C)] &gt; pub union PrefValue { &gt; string_val: *const c_char, &gt; int_val: i32, &gt; bool_val: bool, &gt; } &gt; &gt; /// Keep this in sync with PrefsParserPrefFn in Preferences.cpp. &gt;-type PrefFn = unsafe extern "C" fn(pref_name: *const c_char, pref_type: PrefType, &gt;- pref_value_kind: PrefValueKind, pref_value: PrefValue, &gt;- is_sticky: bool, is_locked: bool); &gt;+type PrefFn = unsafe extern "C" fn( &gt;+ pref_name: *const c_char, &gt;+ pref_type: PrefType, &gt;+ pref_value_kind: PrefValueKind, &gt;+ pref_value: PrefValue, &gt;+ is_sticky: bool, &gt;+ is_locked: bool, &gt;+); &gt; &gt; /// Keep this in sync with PrefsParserErrorFn in Preferences.cpp. &gt; type ErrorFn = unsafe extern "C" fn(msg: *const c_char); &gt; &gt; /// Parse the contents of a prefs file. &gt; /// &gt; /// `buf` is a null-terminated string. `len` is its length, excluding the &gt; /// null terminator. &gt; /// &gt; /// `pref_fn` is called once for each successfully parsed pref. &gt; /// &gt; /// `error_fn` is called once for each parse error detected. &gt; /// &gt; /// Keep this in sync with the prefs_parser_parse() declaration in &gt; /// Preferences.cpp. &gt; #[no_mangle] &gt;-pub extern "C" fn prefs_parser_parse(path: *const c_char, kind: PrefValueKind, buf: *const c_char, &gt;- len: usize, pref_fn: PrefFn, error_fn: ErrorFn) -&gt; bool { &gt;- let path = unsafe { std::ffi::CStr::from_ptr(path).to_string_lossy().into_owned() }; &gt;+pub extern "C" fn prefs_parser_parse( &gt;+ path: *const c_char, &gt;+ kind: PrefValueKind, &gt;+ buf: *const c_char, &gt;+ len: usize, &gt;+ pref_fn: PrefFn, &gt;+ error_fn: ErrorFn, &gt;+) -&gt; bool { &gt;+ let path = unsafe { &gt;+ std::ffi::CStr::from_ptr(path) &gt;+ .to_string_lossy() &gt;+ .into_owned() &gt;+ }; &gt; &gt; // Make sure `buf` ends in a '\0', and include that in the length, because &gt; // it represents EOF. &gt; let buf = unsafe { std::slice::from_raw_parts(buf as *const c_uchar, len + 1) }; &gt; assert!(buf.last() == Some(&amp;EOF)); &gt; &gt; let mut parser = Parser::new(&amp;path, kind, &amp;buf, pref_fn, error_fn); &gt; parser.parse() &gt;@@ -195,104 +210,138 @@ enum CharKind { &gt; SingleChar, // Unambiguous single-char tokens: [()+,-] &gt; SpaceNL, // [\t\v\f \n] &gt; Keyword, // [A-Za-z_] &gt; Quote, // ["'] &gt; Slash, // / &gt; Digit, // [0-9] &gt; Hash, // # &gt; CR, // \r &gt;- Other // Everything else; invalid except within strings and comments. &gt;+ Other, // Everything else; invalid except within strings and comments. &gt; } &gt; &gt; const C_SINGL: CharKind = CharKind::SingleChar; &gt; const C_SPCNL: CharKind = CharKind::SpaceNL; &gt; const C_KEYWD: CharKind = CharKind::Keyword; &gt; const C_QUOTE: CharKind = CharKind::Quote; &gt; const C_SLASH: CharKind = CharKind::Slash; &gt; const C_DIGIT: CharKind = CharKind::Digit; &gt;-const C_HASH : CharKind = CharKind::Hash; &gt;-const C_CR : CharKind = CharKind::CR; &gt;+const C_HASH: CharKind = CharKind::Hash; &gt;+const C_CR: CharKind = CharKind::CR; &gt; const C______: CharKind = CharKind::Other; &gt; &gt; const CHAR_KINDS: [CharKind; 256] = [ &gt;-/* 0 1 2 3 4 5 6 7 8 9 */ &gt;-/* 0+ */ C_SINGL, C______, C______, C______, C______, C______, C______, C______, C______, C_SPCNL, &gt;-/* 10+ */ C_SPCNL, C_SPCNL, C_SPCNL, C_CR , C______, C______, C______, C______, C______, C______, &gt;-/* 20+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 30+ */ C______, C______, C_SPCNL, C______, C_QUOTE, C_HASH , C______, C______, C______, C_QUOTE, &gt;-/* 40+ */ C_SINGL, C_SINGL, C______, C_SINGL, C_SINGL, C_SINGL, C______, C_SLASH, C_DIGIT, C_DIGIT, &gt;-/* 50+ */ C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C______, C_SINGL, &gt;-/* 60+ */ C______, C______, C______, C______, C______, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, &gt;-/* 70+ */ C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, &gt;-/* 80+ */ C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, &gt;-/* 90+ */ C_KEYWD, C______, C______, C______, C______, C_KEYWD, C______, C_KEYWD, C_KEYWD, C_KEYWD, &gt;-/* 100+ */ C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, &gt;-/* 110+ */ C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, &gt;-/* 120+ */ C_KEYWD, C_KEYWD, C_KEYWD, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 130+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 140+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 150+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 160+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 170+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 180+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 190+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 200+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 210+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 220+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 230+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 240+ */ C______, C______, C______, C______, C______, C______, C______, C______, C______, C______, &gt;-/* 250+ */ C______, C______, C______, C______, C______, C______ &gt;+ /* 0 1 2 3 4 5 6 7 8 9 */ &gt;+ /* 0+ */ &gt;+ C_SINGL, C______, C______, C______, C______, C______, C______, C______, C______, C_SPCNL, &gt;+ /* 10+ */ C_SPCNL, C_SPCNL, C_SPCNL, C_CR, C______, C______, C______, C______, C______, &gt;+ C______, /* 20+ */ C______, C______, C______, C______, C______, C______, C______, &gt;+ C______, C______, C______, /* 30+ */ C______, C______, C_SPCNL, C______, C_QUOTE, C_HASH, &gt;+ C______, C______, C______, C_QUOTE, /* 40+ */ C_SINGL, C_SINGL, C______, C_SINGL, &gt;+ C_SINGL, C_SINGL, C______, C_SLASH, C_DIGIT, C_DIGIT, /* 50+ */ C_DIGIT, C_DIGIT, &gt;+ C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C______, C_SINGL, &gt;+ /* 60+ */ C______, C______, C______, C______, C______, C_KEYWD, C_KEYWD, C_KEYWD, &gt;+ C_KEYWD, C_KEYWD, /* 70+ */ C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, &gt;+ C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, /* 80+ */ C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, &gt;+ C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, /* 90+ */ C_KEYWD, C______, &gt;+ C______, C______, C______, C_KEYWD, C______, C_KEYWD, C_KEYWD, C_KEYWD, &gt;+ /* 100+ */ C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, &gt;+ C_KEYWD, C_KEYWD, /* 110+ */ C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, &gt;+ C_KEYWD, C_KEYWD, C_KEYWD, C_KEYWD, /* 120+ */ C_KEYWD, C_KEYWD, C_KEYWD, C______, &gt;+ C______, C______, C______, C______, C______, C______, /* 130+ */ C______, C______, &gt;+ C______, C______, C______, C______, C______, C______, C______, C______, &gt;+ /* 140+ */ C______, C______, C______, C______, C______, C______, C______, C______, &gt;+ C______, C______, /* 150+ */ C______, C______, C______, C______, C______, C______, &gt;+ C______, C______, C______, C______, /* 160+ */ C______, C______, C______, C______, &gt;+ C______, C______, C______, C______, C______, C______, /* 170+ */ C______, C______, &gt;+ C______, C______, C______, C______, C______, C______, C______, C______, &gt;+ /* 180+ */ C______, C______, C______, C______, C______, C______, C______, C______, &gt;+ C______, C______, /* 190+ */ C______, C______, C______, C______, C______, C______, &gt;+ C______, C______, C______, C______, /* 200+ */ C______, C______, C______, C______, &gt;+ C______, C______, C______, C______, C______, C______, /* 210+ */ C______, C______, &gt;+ C______, C______, C______, C______, C______, C______, C______, C______, &gt;+ /* 220+ */ C______, C______, C______, C______, C______, C______, C______, C______, &gt;+ C______, C______, /* 230+ */ C______, C______, C______, C______, C______, C______, &gt;+ C______, C______, C______, C______, /* 240+ */ C______, C______, C______, C______, &gt;+ C______, C______, C______, C______, C______, C______, /* 250+ */ C______, C______, &gt;+ C______, C______, C______, C______, &gt; ]; &gt; &gt; const _______: bool = false; &gt; const SPECIAL_STRING_CHARS: [bool; 256] = [ &gt;-/* 0 1 2 3 4 5 6 7 8 9 */ &gt;-/* 0+ */ true, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 10+ */ true, _______, _______, true, _______, _______, _______, _______, _______, _______, &gt;-/* 20+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 30+ */ _______, _______, _______, _______, true, _______, _______, _______, _______, true, &gt;-/* 40+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 50+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 60+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 70+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 80+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 90+ */ _______, _______, true, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 100+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 110+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 120+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 130+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 140+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 150+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 160+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 170+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 180+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 190+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 200+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 210+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 220+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 230+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 240+ */ _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;-/* 250+ */ _______, _______, _______, _______, _______, _______ &gt;+ /* 0 1 2 3 4 5 6 7 8 9 */ &gt;+ /* 0+ */ &gt;+ true, _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;+ /* 10+ */ true, _______, _______, true, _______, _______, _______, _______, _______, &gt;+ _______, /* 20+ */ _______, _______, _______, _______, _______, _______, _______, &gt;+ _______, _______, _______, /* 30+ */ _______, _______, _______, _______, true, _______, &gt;+ _______, _______, _______, true, /* 40+ */ _______, _______, _______, _______, _______, &gt;+ _______, _______, _______, _______, _______, /* 50+ */ _______, _______, _______, &gt;+ _______, _______, _______, _______, _______, _______, _______, /* 60+ */ _______, &gt;+ _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;+ /* 70+ */ _______, _______, _______, _______, _______, _______, _______, _______, &gt;+ _______, _______, /* 80+ */ _______, _______, _______, _______, _______, _______, &gt;+ _______, _______, _______, _______, /* 90+ */ _______, _______, true, _______, _______, &gt;+ _______, _______, _______, _______, _______, /* 100+ */ _______, _______, _______, &gt;+ _______, _______, _______, _______, _______, _______, _______, /* 110+ */ _______, &gt;+ _______, _______, _______, _______, _______, _______, _______, _______, _______, &gt;+ /* 120+ */ _______, _______, _______, _______, _______, _______, _______, _______, &gt;+ _______, _______, /* 130+ */ _______, _______, _______, _______, _______, _______, &gt;+ _______, _______, _______, _______, /* 140+ */ _______, _______, _______, _______, &gt;+ _______, _______, _______, _______, _______, _______, /* 150+ */ _______, _______, &gt;+ _______, _______, _______, _______, _______, _______, _______, _______, &gt;+ /* 160+ */ _______, _______, _______, _______, _______, _______, _______, _______, &gt;+ _______, _______, /* 170+ */ _______, _______, _______, _______, _______, _______, &gt;+ _______, _______, _______, _______, /* 180+ */ _______, _______, _______, _______, &gt;+ _______, _______, _______, _______, _______, _______, /* 190+ */ _______, _______, &gt;+ _______, _______, _______, _______, _______, _______, _______, _______, &gt;+ /* 200+ */ _______, _______, _______, _______, _______, _______, _______, _______, &gt;+ _______, _______, /* 210+ */ _______, _______, _______, _______, _______, _______, &gt;+ _______, _______, _______, _______, /* 220+ */ _______, _______, _______, _______, &gt;+ _______, _______, _______, _______, _______, _______, /* 230+ */ _______, _______, &gt;+ _______, _______, _______, _______, _______, _______, _______, _______, &gt;+ /* 240+ */ _______, _______, _______, _______, _______, _______, _______, _______, &gt;+ _______, _______, /* 250+ */ _______, _______, _______, _______, _______, _______, &gt; ]; &gt; &gt; struct KeywordInfo { &gt;- string: &amp;'static [u8], &gt;- token: Token, &gt;+ string: &amp;'static [u8], &gt;+ token: Token, &gt; } &gt; &gt; const KEYWORD_INFOS: [KeywordInfo; 7] = [ &gt;- // These are ordered by frequency. &gt;- KeywordInfo { string: b"pref", token: Token::Pref }, &gt;- KeywordInfo { string: b"true", token: Token::True }, &gt;- KeywordInfo { string: b"false", token: Token::False }, &gt;- KeywordInfo { string: b"user_pref", token: Token::UserPref }, &gt;- KeywordInfo { string: b"sticky", token: Token::Sticky }, &gt;- KeywordInfo { string: b"locked", token: Token::Locked }, &gt;- KeywordInfo { string: b"sticky_pref", token: Token::StickyPref }, &gt;+ // These are ordered by frequency. &gt;+ KeywordInfo { &gt;+ string: b"pref", &gt;+ token: Token::Pref, &gt;+ }, &gt;+ KeywordInfo { &gt;+ string: b"true", &gt;+ token: Token::True, &gt;+ }, &gt;+ KeywordInfo { &gt;+ string: b"false", &gt;+ token: Token::False, &gt;+ }, &gt;+ KeywordInfo { &gt;+ string: b"user_pref", &gt;+ token: Token::UserPref, &gt;+ }, &gt;+ KeywordInfo { &gt;+ string: b"sticky", &gt;+ token: Token::Sticky, &gt;+ }, &gt;+ KeywordInfo { &gt;+ string: b"locked", &gt;+ token: Token::Locked, &gt;+ }, &gt;+ KeywordInfo { &gt;+ string: b"sticky_pref", &gt;+ token: Token::StickyPref, &gt;+ }, &gt; ]; &gt; &gt; struct Parser&lt;'t&gt; { &gt; path: &amp;'t str, // Path to the file being parsed. Used in error messages. &gt; kind: PrefValueKind, // Default prefs file or user prefs file? &gt; buf: &amp;'t [u8], // Text being parsed. &gt; i: usize, // Index of next char to be read. &gt; line_num: u32, // Current line number within the text. &gt;@@ -300,18 +349,23 @@ struct Parser&lt;'t&gt; { &gt; error_fn: ErrorFn, // Callback for parse errors. &gt; has_errors: bool, // Have we encountered errors? &gt; } &gt; &gt; // As described above, we use 0 to represent EOF. &gt; const EOF: u8 = b'\0'; &gt; &gt; impl&lt;'t&gt; Parser&lt;'t&gt; { &gt;- fn new(path: &amp;'t str, kind: PrefValueKind, buf: &amp;'t [u8], pref_fn: PrefFn, error_fn: ErrorFn) &gt;- -&gt; Parser&lt;'t&gt; { &gt;+ fn new( &gt;+ path: &amp;'t str, &gt;+ kind: PrefValueKind, &gt;+ buf: &amp;'t [u8], &gt;+ pref_fn: PrefFn, &gt;+ error_fn: ErrorFn, &gt;+ ) -&gt; Parser&lt;'t&gt; { &gt; // Make sure these tables take up 1 byte per entry. &gt; assert!(std::mem::size_of_val(&amp;CHAR_KINDS) == 256); &gt; assert!(std::mem::size_of_val(&amp;SPECIAL_STRING_CHARS) == 256); &gt; &gt; Parser { &gt; path: path, &gt; kind: kind, &gt; buf: buf, &gt;@@ -320,34 +374,36 @@ impl&lt;'t&gt; Parser&lt;'t&gt; { &gt; pref_fn: pref_fn, &gt; error_fn: error_fn, &gt; has_errors: false, &gt; } &gt; } &gt; &gt; fn parse(&amp;mut self) -&gt; bool { &gt; // These are reused, because allocating a new Vec for every string is slow. &gt;- let mut name_str = Vec::with_capacity(128); // For pref names. &gt;+ let mut name_str = Vec::with_capacity(128); // For pref names. &gt; let mut value_str = Vec::with_capacity(512); // For string pref values. &gt;- let mut none_str = Vec::with_capacity(0); // For tokens that shouldn't be strings. &gt;+ let mut none_str = Vec::with_capacity(0); // For tokens that shouldn't be strings. &gt; &gt; let mut token = self.get_token(&amp;mut none_str); &gt; &gt; // At the top of the loop we already have a token. In a valid input &gt; // this will be either the first token of a new pref, or EOF. &gt; loop { &gt; // &lt;pref-spec&gt; &gt; let (pref_value_kind, mut is_sticky) = match token { &gt; Token::Pref =&gt; (PrefValueKind::Default, false), &gt; Token::StickyPref =&gt; (PrefValueKind::Default, true), &gt; Token::UserPref =&gt; (PrefValueKind::User, false), &gt; Token::SingleChar(EOF) =&gt; return !self.has_errors, &gt; _ =&gt; { &gt; token = self.error_and_recover( &gt;- token, "expected pref specifier at start of pref definition"); &gt;+ token, &gt;+ "expected pref specifier at start of pref definition", &gt;+ ); &gt; continue; &gt; } &gt; }; &gt; &gt; // "(" &gt; token = self.get_token(&amp;mut none_str); &gt; if token != Token::SingleChar(b'(') { &gt; token = self.error_and_recover(token, "expected '(' after pref specifier"); &gt;@@ -368,72 +424,77 @@ impl&lt;'t&gt; Parser&lt;'t&gt; { &gt; if token != Token::SingleChar(b',') { &gt; token = self.error_and_recover(token, "expected ',' after pref name"); &gt; continue; &gt; } &gt; &gt; // &lt;pref-value&gt; &gt; token = self.get_token(&amp;mut value_str); &gt; let (pref_type, pref_value) = match token { &gt;- Token::True =&gt; { &gt;- (PrefType::Bool, PrefValue { bool_val: true }) &gt;- } &gt;- Token::False =&gt; { &gt;- (PrefType::Bool, PrefValue { bool_val: false }) &gt;- } &gt;- Token::String =&gt; { &gt;- (PrefType::String, &gt;- PrefValue { string_val: value_str.as_ptr() as *const c_char }) &gt;- } &gt;+ Token::True =&gt; (PrefType::Bool, PrefValue { bool_val: true }), &gt;+ Token::False =&gt; (PrefType::Bool, PrefValue { bool_val: false }), &gt;+ Token::String =&gt; ( &gt;+ PrefType::String, &gt;+ PrefValue { &gt;+ string_val: value_str.as_ptr() as *const c_char, &gt;+ }, &gt;+ ), &gt; Token::Int(u) =&gt; { &gt; // Accept u &lt;= 2147483647; anything larger will overflow i32. &gt; if u &lt;= std::i32::MAX as u32 { &gt; (PrefType::Int, PrefValue { int_val: u as i32 }) &gt; } else { &gt;- token = self.error_and_recover( &gt;- Token::Error("integer literal overflowed"), ""); &gt;+ token = &gt;+ self.error_and_recover(Token::Error("integer literal overflowed"), ""); &gt; continue; &gt; } &gt; } &gt; Token::SingleChar(b'-') =&gt; { &gt; token = self.get_token(&amp;mut none_str); &gt; if let Token::Int(u) = token { &gt; // Accept u &lt;= 2147483648; anything larger will overflow i32 once negated. &gt; if u &lt;= std::i32::MAX as u32 { &gt;- (PrefType::Int, PrefValue { int_val: -(u as i32) }) &gt;+ ( &gt;+ PrefType::Int, &gt;+ PrefValue { &gt;+ int_val: -(u as i32), &gt;+ }, &gt;+ ) &gt; } else if u == std::i32::MAX as u32 + 1 { &gt;- (PrefType::Int, PrefValue { int_val: std::i32::MIN }) &gt;+ ( &gt;+ PrefType::Int, &gt;+ PrefValue { &gt;+ int_val: std::i32::MIN, &gt;+ }, &gt;+ ) &gt; } else { &gt;- token = self.error_and_recover( &gt;- Token::Error("integer literal overflowed"), ""); &gt;+ token = self &gt;+ .error_and_recover(Token::Error("integer literal overflowed"), ""); &gt; continue; &gt; } &gt; } else { &gt;- token = self.error_and_recover( &gt;- token, "expected integer literal after '-'"); &gt;+ token = self.error_and_recover(token, "expected integer literal after '-'"); &gt; continue; &gt; } &gt;- &gt; } &gt; Token::SingleChar(b'+') =&gt; { &gt; token = self.get_token(&amp;mut none_str); &gt; if let Token::Int(u) = token { &gt; // Accept u &lt;= 2147483647; anything larger will overflow i32. &gt; if u &lt;= std::i32::MAX as u32 { &gt; (PrefType::Int, PrefValue { int_val: u as i32 }) &gt; } else { &gt;- token = self.error_and_recover( &gt;- Token::Error("integer literal overflowed"), ""); &gt;+ token = self &gt;+ .error_and_recover(Token::Error("integer literal overflowed"), ""); &gt; continue; &gt; } &gt; } else { &gt; token = self.error_and_recover(token, "expected integer literal after '+'"); &gt; continue; &gt; } &gt;- &gt; } &gt; _ =&gt; { &gt; token = self.error_and_recover(token, "expected pref value after ','"); &gt; continue; &gt; } &gt; }; &gt; &gt; // ("," &lt;pref-attr&gt;)* // default pref files only &gt;@@ -449,17 +510,17 @@ impl&lt;'t&gt; Parser&lt;'t&gt; { &gt; &gt; // &lt;pref-attr&gt; &gt; token = self.get_token(&amp;mut none_str); &gt; match token { &gt; Token::Sticky =&gt; is_sticky = true, &gt; Token::Locked =&gt; is_locked = true, &gt; _ =&gt; { &gt; token = &gt;- self.error_and_recover(token, "expected pref attribute after ','"); &gt;+ self.error_and_recover(token, "expected pref attribute after ','"); &gt; break false; &gt; } &gt; } &gt; has_attrs = true; &gt; }; &gt; if !ok { &gt; continue; &gt; } &gt;@@ -484,18 +545,26 @@ impl&lt;'t&gt; Parser&lt;'t&gt; { &gt; &gt; // ";" &gt; token = self.get_token(&amp;mut none_str); &gt; if token != Token::SingleChar(b';') { &gt; token = self.error_and_recover(token, "expected ';' after ')'"); &gt; continue; &gt; } &gt; &gt;- unsafe { (self.pref_fn)(pref_name.as_ptr() as *const c_char, pref_type, pref_value_kind, &gt;- pref_value, is_sticky, is_locked) }; &gt;+ unsafe { &gt;+ (self.pref_fn)( &gt;+ pref_name.as_ptr() as *const c_char, &gt;+ pref_type, &gt;+ pref_value_kind, &gt;+ pref_value, &gt;+ is_sticky, &gt;+ is_locked, &gt;+ ) &gt;+ }; &gt; &gt; token = self.get_token(&amp;mut none_str); &gt; } &gt; } &gt; &gt; fn error_and_recover(&amp;mut self, token: Token, msg: &amp;str) -&gt; Token { &gt; self.has_errors = true; &gt; &gt;@@ -587,24 +656,23 @@ impl&lt;'t&gt; Parser&lt;'t&gt; { &gt; self.match_char(b'\n'); &gt; break; &gt; } &gt; EOF =&gt; { &gt; // Unget EOF so subsequent calls to get_char() are safe. &gt; self.unget_char(); &gt; break; &gt; } &gt;- _ =&gt; continue &gt;+ _ =&gt; continue, &gt; } &gt; } &gt; } &gt; &gt; // Returns false if we hit EOF without closing the comment. &gt;- fn match_multi_line_comment(&amp;mut self) -&gt; bool &gt;- { &gt;+ fn match_multi_line_comment(&amp;mut self) -&gt; bool { &gt; loop { &gt; match self.get_char() { &gt; b'*' =&gt; { &gt; if self.match_char(b'/') { &gt; return true; &gt; } &gt; } &gt; b'\n' =&gt; { &gt;@@ -612,30 +680,30 @@ impl&lt;'t&gt; Parser&lt;'t&gt; { &gt; } &gt; b'\r' =&gt; { &gt; self.line_num += 1; &gt; self.match_char(b'\n'); &gt; } &gt; EOF =&gt; { &gt; // Unget EOF so subsequent calls to get_char() are safe. &gt; self.unget_char(); &gt;- return false &gt;+ return false; &gt; } &gt;- _ =&gt; continue &gt;+ _ =&gt; continue, &gt; } &gt; } &gt; } &gt; &gt; fn match_hex_digits(&amp;mut self, ndigits: i32) -&gt; Option&lt;u16&gt; { &gt; debug_assert!(ndigits == 2 || ndigits == 4); &gt; let mut value: u16 = 0; &gt; for _ in 0..ndigits { &gt; value = value &lt;&lt; 4; &gt; match self.get_char() { &gt;- c @ b'0'... b'9' =&gt; value += (c - b'0') as u16, &gt;+ c @ b'0'...b'9' =&gt; value += (c - b'0') as u16, &gt; c @ b'A'...b'F' =&gt; value += (c - b'A') as u16 + 10, &gt; c @ b'a'...b'f' =&gt; value += (c - b'a') as u16 + 10, &gt; _ =&gt; { &gt; // Unget in case the char was a closing quote or EOF. &gt; self.unget_char(); &gt; return None; &gt; } &gt; } &gt;@@ -711,17 +779,17 @@ impl&lt;'t&gt; Parser&lt;'t&gt; { &gt; b'/' =&gt; { &gt; self.match_single_line_comment(); &gt; } &gt; b'*' =&gt; { &gt; if !self.match_multi_line_comment() { &gt; return Token::Error("unterminated /* comment"); &gt; } &gt; } &gt;- _ =&gt; return Token::Error("expected '/' or '*' after '/'") &gt;+ _ =&gt; return Token::Error("expected '/' or '*' after '/'"), &gt; } &gt; continue; &gt; } &gt; CharKind::Digit =&gt; { &gt; let mut value = Some((c - b'0') as u32); &gt; loop { &gt; let c = self.get_char(); &gt; match Parser::char_kind(c) { &gt;@@ -753,17 +821,17 @@ impl&lt;'t&gt; Parser&lt;'t&gt; { &gt; continue; &gt; } &gt; CharKind::CR =&gt; { &gt; self.match_char(b'\n'); &gt; self.line_num += 1; &gt; continue; &gt; } &gt; // Error recovery will retokenize from the next character. &gt;- _ =&gt; return Token::Error("unexpected character") &gt;+ _ =&gt; return Token::Error("unexpected character"), &gt; } &gt; } &gt; } &gt; &gt; fn string_error_token(&amp;self, token: &amp;mut Token, msg: &amp;'static str) { &gt; // We only want to capture the first tokenization error within a string. &gt; if *token == Token::String { &gt; *token = Token::ErrorAtLine(msg, self.line_num); &gt;@@ -787,45 +855,43 @@ impl&lt;'t&gt; Parser&lt;'t&gt; { &gt; }; &gt; &gt; // Clear str_buf's contents without changing its capacity. &gt; str_buf.clear(); &gt; &gt; // If there are no special chars (the common case), we can bulk copy it &gt; // to str_buf. This is a lot faster than the char-by-char loop below. &gt; if !has_special_chars { &gt;- str_buf.extend(&amp;self.buf[start..self.i - 1]); &gt;- str_buf.push(b'\0'); &gt;- return Token::String; &gt;+ str_buf.extend(&amp;self.buf[start..self.i - 1]); &gt;+ str_buf.push(b'\0'); &gt;+ return Token::String; &gt; } &gt; &gt; // There were special chars. Re-scan the string, filling in str_buf one &gt; // char at a time. &gt; // &gt; // On error, we change `token` to an error token and then keep going to &gt; // the end of the string literal. `str_buf` won't be used in that case. &gt; self.i = start; &gt; let mut token = Token::String; &gt; &gt; loop { &gt; let c = self.get_char(); &gt; let c2 = if !Parser::is_special_string_char(c) { &gt; c &gt;- &gt; } else if c == quote_char { &gt; break; &gt;- &gt; } else if c == b'\\' { &gt; match self.get_char() { &gt; b'\"' =&gt; b'\"', &gt; b'\'' =&gt; b'\'', &gt; b'\\' =&gt; b'\\', &gt;- b'n' =&gt; b'\n', &gt;- b'r' =&gt; b'\r', &gt;- b'x' =&gt; { &gt;+ b'n' =&gt; b'\n', &gt;+ b'r' =&gt; b'\r', &gt;+ b'x' =&gt; { &gt; if let Some(value) = self.match_hex_digits(2) { &gt; debug_assert!(value &lt;= 0xff); &gt; if value != 0 { &gt; value as u8 &gt; } else { &gt; self.string_error_token(&amp;mut token, "\\x00 is not allowed"); &gt; continue; &gt; } &gt;@@ -842,24 +908,27 @@ impl&lt;'t&gt; Parser&lt;'t&gt; { &gt; if self.match_char(b'\\') &amp;&amp; self.match_char(b'u') { &gt; if let Some(lo) = self.match_hex_digits(4) { &gt; if 0xdc00 == (0xfc00 &amp; lo) { &gt; // Found a valid low surrogate. &gt; utf16.push(lo); &gt; } else { &gt; self.string_error_token( &gt; &amp;mut token, &gt;- "invalid low surrogate value after high surrogate"); &gt;+ "invalid low surrogate value after high surrogate", &gt;+ ); &gt; continue; &gt; } &gt; } &gt; } &gt; if utf16.len() != 2 { &gt; self.string_error_token( &gt;- &amp;mut token, "expected low surrogate after high surrogate"); &gt;+ &amp;mut token, &gt;+ "expected low surrogate after high surrogate", &gt;+ ); &gt; continue; &gt; } &gt; } else if value == 0 { &gt; self.string_error_token(&amp;mut token, "\\u0000 is not allowed"); &gt; continue; &gt; } &gt; &gt; // Insert the UTF-16 sequence as UTF-8. &gt;@@ -870,40 +939,38 @@ impl&lt;'t&gt; Parser&lt;'t&gt; { &gt; continue; &gt; } &gt; continue; // We don't want to str_buf.push(c2) below. &gt; } &gt; _ =&gt; { &gt; // Unget in case the char is an EOF. &gt; self.unget_char(); &gt; self.string_error_token( &gt;- &amp;mut token, "unexpected escape sequence character after '\\'"); &gt;+ &amp;mut token, &gt;+ "unexpected escape sequence character after '\\'", &gt;+ ); &gt; continue; &gt; } &gt; } &gt;- &gt; } else if c == b'\n' { &gt; self.line_num += 1; &gt; c &gt;- &gt; } else if c == b'\r' { &gt; self.line_num += 1; &gt; if self.match_char(b'\n') { &gt; str_buf.push(b'\r'); &gt; b'\n' &gt; } else { &gt; c &gt; } &gt;- &gt; } else if c == EOF { &gt; // Unget EOF so subsequent calls to get_char() are safe. &gt; self.unget_char(); &gt; self.string_error_token(&amp;mut token, "unterminated string literal"); &gt; break; &gt;- &gt; } else { &gt; // This case is only hit for the non-closing quote char. &gt; debug_assert!((c == b'\'' || c == b'\"') &amp;&amp; c != quote_char); &gt; c &gt; }; &gt; str_buf.push(c2); &gt; } &gt; str_buf.push(b'\0'); &gt;diff --git a/netwerk/base/mozurl/src/lib.rs b/netwerk/base/mozurl/src/lib.rs &gt;index 87392e0993b0..ce06790caa4c 100644 &gt;--- a/netwerk/base/mozurl/src/lib.rs &gt;+++ b/netwerk/base/mozurl/src/lib.rs &gt;@@ -1,412 +1,417 @@ &gt; /* -*- Mode: rust; rust-indent-offset: 2 -*- */ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; extern crate url; &gt;-use url::{Url, ParseOptions, Position}; &gt; use url::quirks; &gt;+use url::{ParseOptions, Position, Url}; &gt; &gt; extern crate nsstring; &gt;-use nsstring::{nsCString, nsACString}; &gt;+use nsstring::{nsACString, nsCString}; &gt; &gt; extern crate nserror; &gt; use nserror::*; &gt; &gt; extern crate xpcom; &gt;-use xpcom::{AtomicRefcnt, RefPtr, RefCounted}; &gt; use xpcom::interfaces::nsrefcnt; &gt;+use xpcom::{AtomicRefcnt, RefCounted, RefPtr}; &gt; &gt;-use std::str; &gt;-use std::ptr; &gt;-use std::ops; &gt;-use std::marker::PhantomData; &gt; use std::fmt::Write; &gt;+use std::marker::PhantomData; &gt;+use std::ops; &gt;+use std::ptr; &gt;+use std::str; &gt; &gt; /// Helper macro. If the expression $e is Ok(t) evaluates to t, otherwise, &gt; /// returns NS_ERROR_MALFORMED_URI. &gt; macro_rules! try_or_malformed { &gt;- ($e:expr) =&gt; ( &gt;- match $e { &gt;- Ok(v) =&gt; v, &gt;- Err(_) =&gt; return NS_ERROR_MALFORMED_URI, &gt;- } &gt;- ) &gt;+ ($e:expr) =&gt; { &gt;+ match $e { &gt;+ Ok(v) =&gt; v, &gt;+ Err(_) =&gt; return NS_ERROR_MALFORMED_URI, &gt;+ } &gt;+ }; &gt; } &gt; &gt; fn parser&lt;'a&gt;() -&gt; ParseOptions&lt;'a&gt; { &gt;- Url::options() &gt;+ Url::options() &gt; } &gt; &gt; fn default_port(scheme: &amp;str) -&gt; Option&lt;u16&gt; { &gt;- match scheme { &gt;- "ftp" =&gt; Some(21), &gt;- "gopher" =&gt; Some(70), &gt;- "http" =&gt; Some(80), &gt;- "https" =&gt; Some(443), &gt;- "ws" =&gt; Some(80), &gt;- "wss" =&gt; Some(443), &gt;- "rtsp" =&gt; Some(443), &gt;- "moz-anno" =&gt; Some(443), &gt;- "android" =&gt; Some(443), &gt;- _ =&gt; None, &gt;- } &gt;+ match scheme { &gt;+ "ftp" =&gt; Some(21), &gt;+ "gopher" =&gt; Some(70), &gt;+ "http" =&gt; Some(80), &gt;+ "https" =&gt; Some(443), &gt;+ "ws" =&gt; Some(80), &gt;+ "wss" =&gt; Some(443), &gt;+ "rtsp" =&gt; Some(443), &gt;+ "moz-anno" =&gt; Some(443), &gt;+ "android" =&gt; Some(443), &gt;+ _ =&gt; None, &gt;+ } &gt; } &gt; &gt; /// A slice into the backing string. This type is only valid as long as the &gt; /// MozURL which it was pulled from is valid. In C++, this type implicitly &gt; /// converts to a nsDependentCString, and is an implementation detail. &gt; /// &gt; /// This type exists because, unlike &amp;str, this type is safe to return over FFI. &gt; #[repr(C)] &gt; pub struct SpecSlice&lt;'a&gt; { &gt;- data: *const u8, &gt;- len: u32, &gt;- _marker: PhantomData&lt;&amp;'a [u8]&gt;, &gt;+ data: *const u8, &gt;+ len: u32, &gt;+ _marker: PhantomData&lt;&amp;'a [u8]&gt;, &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a str&gt; for SpecSlice&lt;'a&gt; { &gt;- fn from(s: &amp;'a str) -&gt; SpecSlice&lt;'a&gt; { &gt;- assert!(s.len() &lt; u32::max_value() as usize); &gt;- SpecSlice { &gt;- data: s.as_ptr(), &gt;- len: s.len() as u32, &gt;- _marker: PhantomData, &gt;+ fn from(s: &amp;'a str) -&gt; SpecSlice&lt;'a&gt; { &gt;+ assert!(s.len() &lt; u32::max_value() as usize); &gt;+ SpecSlice { &gt;+ data: s.as_ptr(), &gt;+ len: s.len() as u32, &gt;+ _marker: PhantomData, &gt;+ } &gt; } &gt;- } &gt; } &gt; &gt; /// The MozURL reference-counted threadsafe URL type. This type intentionally &gt; /// implements no XPCOM interfaces, and all method calls are non-virtual. &gt; #[repr(C)] &gt; pub struct MozURL { &gt;- pub url: Url, &gt;- refcnt: AtomicRefcnt, &gt;+ pub url: Url, &gt;+ refcnt: AtomicRefcnt, &gt; } &gt; &gt; impl MozURL { &gt;- pub fn from_url(url: Url) -&gt; RefPtr&lt;MozURL&gt; { &gt;- // Actually allocate the URL on the heap. This is the only place we actually &gt;- // create a MozURL, other than in clone(). &gt;- unsafe { &gt;- RefPtr::from_raw(Box::into_raw(Box::new(MozURL { &gt;- url: url, &gt;- refcnt: AtomicRefcnt::new(), &gt;- }))).unwrap() &gt;+ pub fn from_url(url: Url) -&gt; RefPtr&lt;MozURL&gt; { &gt;+ // Actually allocate the URL on the heap. This is the only place we actually &gt;+ // create a MozURL, other than in clone(). &gt;+ unsafe { &gt;+ RefPtr::from_raw(Box::into_raw(Box::new(MozURL { &gt;+ url: url, &gt;+ refcnt: AtomicRefcnt::new(), &gt;+ }))).unwrap() &gt;+ } &gt; } &gt;- } &gt; } &gt; &gt; impl ops::Deref for MozURL { &gt;- type Target = Url; &gt;- fn deref(&amp;self) -&gt; &amp;Url { &gt;- &amp;self.url &gt;- } &gt;+ type Target = Url; &gt;+ fn deref(&amp;self) -&gt; &amp;Url { &gt;+ &amp;self.url &gt;+ } &gt; } &gt; impl ops::DerefMut for MozURL { &gt;- fn deref_mut(&amp;mut self) -&gt; &amp;mut Url { &gt;- &amp;mut self.url &gt;- } &gt;+ fn deref_mut(&amp;mut self) -&gt; &amp;mut Url { &gt;+ &amp;mut self.url &gt;+ } &gt; } &gt; &gt; // Memory Management for MozURL &gt; #[no_mangle] &gt; pub unsafe extern "C" fn mozurl_addref(url: &amp;MozURL) -&gt; nsrefcnt { &gt;- url.refcnt.inc() &gt;+ url.refcnt.inc() &gt; } &gt; &gt; #[no_mangle] &gt; pub unsafe extern "C" fn mozurl_release(url: &amp;MozURL) -&gt; nsrefcnt { &gt;- let rc = url.refcnt.dec(); &gt;- if rc == 0 { &gt;- Box::from_raw(url as *const MozURL as *mut MozURL); &gt;- } &gt;- rc &gt;+ let rc = url.refcnt.dec(); &gt;+ if rc == 0 { &gt;+ Box::from_raw(url as *const MozURL as *mut MozURL); &gt;+ } &gt;+ rc &gt; } &gt; &gt; // xpcom::RefPtr support &gt; unsafe impl RefCounted for MozURL { &gt;- unsafe fn addref(&amp;self) { &gt;- mozurl_addref(self); &gt;- } &gt;- unsafe fn release(&amp;self) { &gt;- mozurl_release(self); &gt;- } &gt;+ unsafe fn addref(&amp;self) { &gt;+ mozurl_addref(self); &gt;+ } &gt;+ unsafe fn release(&amp;self) { &gt;+ mozurl_release(self); &gt;+ } &gt; } &gt; &gt; // Allocate a new MozURL object with a RefCnt of 1, and store a pointer to it &gt; // into url. &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_new( &gt;- result: &amp;mut *const MozURL, &gt;- spec: &amp;nsACString, &gt;- base: Option&lt;&amp;MozURL&gt;, &gt;+ result: &amp;mut *const MozURL, &gt;+ spec: &amp;nsACString, &gt;+ base: Option&lt;&amp;MozURL&gt;, &gt; ) -&gt; nsresult { &gt;- *result = ptr::null_mut(); &gt;+ *result = ptr::null_mut(); &gt; &gt;- let spec = try_or_malformed!(str::from_utf8(spec)); &gt;- let url = if let Some(base) = base { &gt;- try_or_malformed!(base.url.join(spec)) &gt;- } else { &gt;- try_or_malformed!(parser().parse(spec)) &gt;- }; &gt;+ let spec = try_or_malformed!(str::from_utf8(spec)); &gt;+ let url = if let Some(base) = base { &gt;+ try_or_malformed!(base.url.join(spec)) &gt;+ } else { &gt;+ try_or_malformed!(parser().parse(spec)) &gt;+ }; &gt; &gt;- MozURL::from_url(url).forget(result); &gt;- NS_OK &gt;+ MozURL::from_url(url).forget(result); &gt;+ NS_OK &gt; } &gt; &gt; /// Allocate a new MozURL object which is a clone of the original, and store a &gt; /// pointer to it into newurl. &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_clone(url: &amp;MozURL, newurl: &amp;mut *const MozURL) { &gt;- MozURL::from_url(url.url.clone()).forget(newurl); &gt;+ MozURL::from_url(url.url.clone()).forget(newurl); &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_spec(url: &amp;MozURL) -&gt; SpecSlice { &gt;- url.as_ref().into() &gt;+ url.as_ref().into() &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_scheme(url: &amp;MozURL) -&gt; SpecSlice { &gt;- url.scheme().into() &gt;+ url.scheme().into() &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_username(url: &amp;MozURL) -&gt; SpecSlice { &gt;- if url.cannot_be_a_base() { &gt;- "".into() &gt;- } else { &gt;- url.username().into() &gt;- } &gt;+ if url.cannot_be_a_base() { &gt;+ "".into() &gt;+ } else { &gt;+ url.username().into() &gt;+ } &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_password(url: &amp;MozURL) -&gt; SpecSlice { &gt;- url.password().unwrap_or("").into() &gt;+ url.password().unwrap_or("").into() &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_host(url: &amp;MozURL) -&gt; SpecSlice { &gt;- url.host_str().unwrap_or("").into() &gt;+ url.host_str().unwrap_or("").into() &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_port(url: &amp;MozURL) -&gt; i32 { &gt;- // NOTE: Gecko uses -1 to represent the default port. &gt;- url.port().map(|p| p as i32).unwrap_or(-1) &gt;+ // NOTE: Gecko uses -1 to represent the default port. &gt;+ url.port().map(|p| p as i32).unwrap_or(-1) &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_host_port(url: &amp;MozURL) -&gt; SpecSlice { &gt;- (&amp;url[Position::BeforeHost..Position::BeforePath]).into() &gt;+ (&amp;url[Position::BeforeHost..Position::BeforePath]).into() &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_filepath(url: &amp;MozURL) -&gt; SpecSlice { &gt;- url.path().into() &gt;+ url.path().into() &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_path(url: &amp;MozURL) -&gt; SpecSlice { &gt;- (&amp;url[Position::BeforePath..]).into() &gt;+ (&amp;url[Position::BeforePath..]).into() &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_query(url: &amp;MozURL) -&gt; SpecSlice { &gt;- url.query().unwrap_or("").into() &gt;+ url.query().unwrap_or("").into() &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_fragment(url: &amp;MozURL) -&gt; SpecSlice { &gt;- url.fragment().unwrap_or("").into() &gt;+ url.fragment().unwrap_or("").into() &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_has_fragment(url: &amp;MozURL) -&gt; bool { &gt;- url.fragment().is_some() &gt;+ url.fragment().is_some() &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_origin(url: &amp;MozURL, origin: &amp;mut nsACString) { &gt;- // NOTE: Try to re-use the allocation we got from rust-url, and transfer &gt;- // ownership of the buffer to C++. &gt;- let mut o = nsCString::from(url.origin().ascii_serialization()); &gt;- origin.take_from(&amp;mut o); &gt;+ // NOTE: Try to re-use the allocation we got from rust-url, and transfer &gt;+ // ownership of the buffer to C++. &gt;+ let mut o = nsCString::from(url.origin().ascii_serialization()); &gt;+ origin.take_from(&amp;mut o); &gt; } &gt; &gt; // Helper macro for debug asserting that we're the only reference to MozURL. &gt; macro_rules! debug_assert_mut { &gt;- ($e:expr) =&gt; { &gt;- debug_assert_eq!( &gt;- $e.refcnt.get(), 1, &gt;- "Cannot mutate an aliased MozURL!" &gt;- ); &gt;- } &gt;+ ($e:expr) =&gt; { &gt;+ debug_assert_eq!($e.refcnt.get(), 1, "Cannot mutate an aliased MozURL!"); &gt;+ }; &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_set_scheme(url: &amp;mut MozURL, scheme: &amp;nsACString) -&gt; nsresult { &gt;- debug_assert_mut!(url); &gt;- let scheme = try_or_malformed!(str::from_utf8(scheme)); &gt;- try_or_malformed!(quirks::set_protocol(url, scheme)); &gt;- NS_OK &gt;+ debug_assert_mut!(url); &gt;+ let scheme = try_or_malformed!(str::from_utf8(scheme)); &gt;+ try_or_malformed!(quirks::set_protocol(url, scheme)); &gt;+ NS_OK &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_set_username(url: &amp;mut MozURL, username: &amp;nsACString) -&gt; nsresult { &gt;- debug_assert_mut!(url); &gt;- let username = try_or_malformed!(str::from_utf8(username)); &gt;- try_or_malformed!(quirks::set_username(url, username)); &gt;- NS_OK &gt;+ debug_assert_mut!(url); &gt;+ let username = try_or_malformed!(str::from_utf8(username)); &gt;+ try_or_malformed!(quirks::set_username(url, username)); &gt;+ NS_OK &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_set_password(url: &amp;mut MozURL, password: &amp;nsACString) -&gt; nsresult { &gt;- debug_assert_mut!(url); &gt;- let password = try_or_malformed!(str::from_utf8(password)); &gt;- try_or_malformed!(quirks::set_password(url, password)); &gt;- NS_OK &gt;+ debug_assert_mut!(url); &gt;+ let password = try_or_malformed!(str::from_utf8(password)); &gt;+ try_or_malformed!(quirks::set_password(url, password)); &gt;+ NS_OK &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_set_host_port(url: &amp;mut MozURL, hostport: &amp;nsACString) -&gt; nsresult { &gt;- debug_assert_mut!(url); &gt;- let hostport = try_or_malformed!(str::from_utf8(hostport)); &gt;- try_or_malformed!(quirks::set_host(url, hostport)); &gt;- NS_OK &gt;+ debug_assert_mut!(url); &gt;+ let hostport = try_or_malformed!(str::from_utf8(hostport)); &gt;+ try_or_malformed!(quirks::set_host(url, hostport)); &gt;+ NS_OK &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_set_hostname(url: &amp;mut MozURL, host: &amp;nsACString) -&gt; nsresult { &gt;- debug_assert_mut!(url); &gt;- let host = try_or_malformed!(str::from_utf8(host)); &gt;- try_or_malformed!(quirks::set_hostname(url, host)); &gt;- NS_OK &gt;+ debug_assert_mut!(url); &gt;+ let host = try_or_malformed!(str::from_utf8(host)); &gt;+ try_or_malformed!(quirks::set_hostname(url, host)); &gt;+ NS_OK &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_set_port_no(url: &amp;mut MozURL, new_port: i32) -&gt; nsresult { &gt;- debug_assert_mut!(url); &gt;- if url.cannot_be_a_base() { &gt;- return NS_ERROR_MALFORMED_URI; &gt;- } &gt;+ debug_assert_mut!(url); &gt;+ if url.cannot_be_a_base() { &gt;+ return NS_ERROR_MALFORMED_URI; &gt;+ } &gt; &gt;- let port = match new_port { &gt;- new if new &lt; 0 || u16::max_value() as i32 &gt; new =&gt; None, &gt;- new if Some(new as u16) == default_port(url.scheme()) =&gt; None, &gt;- new =&gt; Some(new as u16), &gt;- }; &gt;- try_or_malformed!(url.set_port(port)); &gt;- NS_OK &gt;+ let port = match new_port { &gt;+ new if new &lt; 0 || u16::max_value() as i32 &gt; new =&gt; None, &gt;+ new if Some(new as u16) == default_port(url.scheme()) =&gt; None, &gt;+ new =&gt; Some(new as u16), &gt;+ }; &gt;+ try_or_malformed!(url.set_port(port)); &gt;+ NS_OK &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_set_pathname(url: &amp;mut MozURL, path: &amp;nsACString) -&gt; nsresult { &gt;- debug_assert_mut!(url); &gt;- let path = try_or_malformed!(str::from_utf8(path)); &gt;- quirks::set_pathname(url, path); &gt;- NS_OK &gt;+ debug_assert_mut!(url); &gt;+ let path = try_or_malformed!(str::from_utf8(path)); &gt;+ quirks::set_pathname(url, path); &gt;+ NS_OK &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_set_query(url: &amp;mut MozURL, query: &amp;nsACString) -&gt; nsresult { &gt;- debug_assert_mut!(url); &gt;- let query = try_or_malformed!(str::from_utf8(query)); &gt;- quirks::set_search(url, query); &gt;- NS_OK &gt;+ debug_assert_mut!(url); &gt;+ let query = try_or_malformed!(str::from_utf8(query)); &gt;+ quirks::set_search(url, query); &gt;+ NS_OK &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn mozurl_set_fragment(url: &amp;mut MozURL, fragment: &amp;nsACString) -&gt; nsresult { &gt;- debug_assert_mut!(url); &gt;- let fragment = try_or_malformed!(str::from_utf8(fragment)); &gt;- quirks::set_hash(url, fragment); &gt;- NS_OK &gt;+ debug_assert_mut!(url); &gt;+ let fragment = try_or_malformed!(str::from_utf8(fragment)); &gt;+ quirks::set_hash(url, fragment); &gt;+ NS_OK &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern "C" fn mozurl_common_base(url1: &amp;MozURL, url2: &amp;MozURL, result: &amp;mut *const MozURL) -&gt; nsresult { &gt;- *result = ptr::null(); &gt;- if url1.url == url2.url { &gt;- RefPtr::new(url1).forget(result); &gt;- return NS_OK; &gt;- } &gt;- &gt;- if url1.scheme() != url2.scheme() || &gt;- url1.host() != url2.host() || &gt;- url1.username() != url2.username() || &gt;- url1.password() != url2.password() || &gt;- url1.port() != url2.port() { &gt;- return NS_OK; &gt;- } &gt;+pub extern "C" fn mozurl_common_base( &gt;+ url1: &amp;MozURL, &gt;+ url2: &amp;MozURL, &gt;+ result: &amp;mut *const MozURL, &gt;+) -&gt; nsresult { &gt;+ *result = ptr::null(); &gt;+ if url1.url == url2.url { &gt;+ RefPtr::new(url1).forget(result); &gt;+ return NS_OK; &gt;+ } &gt; &gt;- match (url1.path_segments(), url2.path_segments()) { &gt;- (Some(path1), Some(path2)) =&gt; { &gt;- // Take the shared prefix of path segments &gt;- let mut url = url1.url.clone(); &gt;- if let Ok(mut segs) = url.path_segments_mut() { &gt;- segs.clear(); &gt;- segs.extend(path1.zip(path2) &gt;- .take_while(|&amp;(a, b)| a == b) &gt;- .map(|p| p.0)); &gt;- } else { &gt;+ if url1.scheme() != url2.scheme() &gt;+ || url1.host() != url2.host() &gt;+ || url1.username() != url2.username() &gt;+ || url1.password() != url2.password() &gt;+ || url1.port() != url2.port() &gt;+ { &gt; return NS_OK; &gt;- } &gt;+ } &gt; &gt;- MozURL::from_url(url).forget(result); &gt;- NS_OK &gt;+ match (url1.path_segments(), url2.path_segments()) { &gt;+ (Some(path1), Some(path2)) =&gt; { &gt;+ // Take the shared prefix of path segments &gt;+ let mut url = url1.url.clone(); &gt;+ if let Ok(mut segs) = url.path_segments_mut() { &gt;+ segs.clear(); &gt;+ segs.extend(path1.zip(path2).take_while(|&amp;(a, b)| a == b).map(|p| p.0)); &gt;+ } else { &gt;+ return NS_OK; &gt;+ } &gt;+ &gt;+ MozURL::from_url(url).forget(result); &gt;+ NS_OK &gt;+ } &gt;+ _ =&gt; NS_OK, &gt; } &gt;- _ =&gt; NS_OK, &gt;- } &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern "C" fn mozurl_relative(url1: &amp;MozURL, url2: &amp;MozURL, result: &amp;mut nsACString) -&gt; nsresult { &gt;- if url1.url == url2.url { &gt;- result.truncate(); &gt;- return NS_OK; &gt;- } &gt;+pub extern "C" fn mozurl_relative( &gt;+ url1: &amp;MozURL, &gt;+ url2: &amp;MozURL, &gt;+ result: &amp;mut nsACString, &gt;+) -&gt; nsresult { &gt;+ if url1.url == url2.url { &gt;+ result.truncate(); &gt;+ return NS_OK; &gt;+ } &gt; &gt;- if url1.scheme() != url2.scheme() || &gt;- url1.host() != url2.host() || &gt;- url1.username() != url2.username() || &gt;- url1.password() != url2.password() || &gt;- url1.port() != url2.port() { &gt;- result.assign(url2.as_ref()); &gt;- return NS_OK; &gt;- } &gt;+ if url1.scheme() != url2.scheme() &gt;+ || url1.host() != url2.host() &gt;+ || url1.username() != url2.username() &gt;+ || url1.password() != url2.password() &gt;+ || url1.port() != url2.port() &gt;+ { &gt;+ result.assign(url2.as_ref()); &gt;+ return NS_OK; &gt;+ } &gt; &gt;- match (url1.path_segments(), url2.path_segments()) { &gt;- (Some(mut path1), Some(mut path2)) =&gt; { &gt;- // Exhaust the part of the iterators that match &gt;- while let (Some(ref p1), Some(ref p2)) = (path1.next(), path2.next()) { &gt;- if p1 != p2 { &gt;- break; &gt;- } &gt;- } &gt;+ match (url1.path_segments(), url2.path_segments()) { &gt;+ (Some(mut path1), Some(mut path2)) =&gt; { &gt;+ // Exhaust the part of the iterators that match &gt;+ while let (Some(ref p1), Some(ref p2)) = (path1.next(), path2.next()) { &gt;+ if p1 != p2 { &gt;+ break; &gt;+ } &gt;+ } &gt; &gt;- result.truncate(); &gt;- for _ in path1 { &gt;- result.append("../"); &gt;- } &gt;- for p2 in path2 { &gt;- result.append(p2); &gt;- result.append("/"); &gt;- } &gt;- } &gt;- _ =&gt; { &gt;- result.assign(url2.as_ref()); &gt;+ result.truncate(); &gt;+ for _ in path1 { &gt;+ result.append("../"); &gt;+ } &gt;+ for p2 in path2 { &gt;+ result.append(p2); &gt;+ result.append("/"); &gt;+ } &gt;+ } &gt;+ _ =&gt; { &gt;+ result.assign(url2.as_ref()); &gt;+ } &gt; } &gt;- } &gt;- NS_OK &gt;+ NS_OK &gt; } &gt; &gt; /// This type is used by nsStandardURL &gt; #[no_mangle] &gt; pub extern "C" fn rusturl_parse_ipv6addr(input: &amp;nsACString, addr: &amp;mut nsACString) -&gt; nsresult { &gt;- let ip6 = try_or_malformed!(str::from_utf8(input)); &gt;- let host = try_or_malformed!(url::Host::parse(ip6)); &gt;- let _ = write!(addr, "{}", host); &gt;- NS_OK &gt;+ let ip6 = try_or_malformed!(str::from_utf8(input)); &gt;+ let host = try_or_malformed!(url::Host::parse(ip6)); &gt;+ let _ = write!(addr, "{}", host); &gt;+ NS_OK &gt; } &gt;diff --git a/netwerk/base/rust-helper/src/lib.rs b/netwerk/base/rust-helper/src/lib.rs &gt;index 24455e097a2a..2845c6ebbe13 100644 &gt;--- a/netwerk/base/rust-helper/src/lib.rs &gt;+++ b/netwerk/base/rust-helper/src/lib.rs &gt;@@ -6,17 +6,18 @@ use self::nsstring::nsACString; &gt; &gt; /// HTTP leading whitespace, defined in netwerk/protocol/http/nsHttp.h &gt; static HTTP_LWS: &amp;'static [u8] = &amp;[' ' as u8, '\t' as u8]; &gt; &gt; /// Trim leading whitespace, trailing whitespace, and quality-value &gt; /// from a token. &gt; fn trim_token(token: &amp;[u8]) -&gt; &amp;[u8] { &gt; // Trim left whitespace &gt;- let ltrim = token.iter() &gt;+ let ltrim = token &gt;+ .iter() &gt; .take_while(|c| HTTP_LWS.iter().any(|ws| &amp;ws == c)) &gt; .count(); &gt; &gt; // Trim right whitespace &gt; // remove "; q=..." if present &gt; let rtrim = token[ltrim..] &gt; .iter() &gt; .take_while(|c| **c != (';' as u8) &amp;&amp; HTTP_LWS.iter().all(|ws| ws != *c)) &gt;@@ -33,33 +34,34 @@ fn trim_token(token: &amp;[u8]) -&gt; &amp;[u8] { &gt; /// the langs implies the q value. The q values are calculated by dividing &gt; /// 1.0 amongst the number of languages present. &gt; /// &gt; /// Ex: passing: "en, ja" &gt; /// returns: "en,ja;q=0.5" &gt; /// &gt; /// passing: "en, ja, fr_CA" &gt; /// returns: "en,ja;q=0.7,fr_CA;q=0.3" &gt;-pub extern "C" fn rust_prepare_accept_languages&lt;'a, 'b&gt;(i_accept_languages: &amp;'a nsACString, &gt;- o_accept_languages: &amp;'b mut nsACString) &gt;- -&gt; nsresult { &gt;+pub extern "C" fn rust_prepare_accept_languages&lt;'a, 'b&gt;( &gt;+ i_accept_languages: &amp;'a nsACString, &gt;+ o_accept_languages: &amp;'b mut nsACString, &gt;+) -&gt; nsresult { &gt; if i_accept_languages.is_empty() { &gt; return NS_OK; &gt; } &gt; &gt; let make_tokens = || { &gt;- i_accept_languages.split(|c| *c == (',' as u8)) &gt;+ i_accept_languages &gt;+ .split(|c| *c == (',' as u8)) &gt; .map(|token| trim_token(token)) &gt; .filter(|token| token.len() != 0) &gt; }; &gt; &gt; let n = make_tokens().count(); &gt; &gt; for (count_n, i_token) in make_tokens().enumerate() { &gt;- &gt; // delimiter if not first item &gt; if count_n != 0 { &gt; o_accept_languages.append(","); &gt; } &gt; &gt; let token_pos = o_accept_languages.len(); &gt; o_accept_languages.append(&amp;i_token as &amp;[u8]); &gt; &gt;@@ -125,17 +127,17 @@ fn canonicalize_language_tag(token: &amp;mut [u8]) { &gt; // Singleton tag, like "x" or "i". These signify a &gt; // non-standard language, so we stop capitalizing after &gt; // these. &gt; 1 =&gt; break, &gt; // ISO 3166-1 Country code, like "US" &gt; 2 =&gt; { &gt; sub_tag[0] = sub_tag[0].to_ascii_uppercase(); &gt; sub_tag[1] = sub_tag[1].to_ascii_uppercase(); &gt;- }, &gt;+ } &gt; // ISO 15924 script code, like "Nkoo" &gt;- 4 =&gt; { &gt;+ 4 =&gt; { &gt; sub_tag[0] = sub_tag[0].to_ascii_uppercase(); &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; }; &gt; } &gt; } &gt;diff --git a/servo/components/fallible/lib.rs b/servo/components/fallible/lib.rs &gt;index c220699a7861..f807bc9ce7a6 100644 &gt;--- a/servo/components/fallible/lib.rs &gt;+++ b/servo/components/fallible/lib.rs &gt;@@ -1,29 +1,28 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; extern crate hashglobe; &gt; extern crate smallvec; &gt; &gt;-use hashglobe::FailedAllocationError; &gt; #[cfg(feature = "known_system_malloc")] &gt; use hashglobe::alloc; &gt;+use hashglobe::FailedAllocationError; &gt; use smallvec::Array; &gt; use smallvec::SmallVec; &gt; use std::vec::Vec; &gt; &gt; pub trait FallibleVec&lt;T&gt; { &gt; /// Append |val| to the end of |vec|. Returns Ok(()) on success, &gt; /// Err(reason) if it fails, with |reason| describing the failure. &gt; fn try_push(&amp;mut self, value: T) -&gt; Result&lt;(), FailedAllocationError&gt;; &gt; } &gt; &gt;- &gt; ///////////////////////////////////////////////////////////////// &gt; // Vec &gt; &gt; impl&lt;T&gt; FallibleVec&lt;T&gt; for Vec&lt;T&gt; { &gt; #[inline(always)] &gt; fn try_push(&amp;mut self, val: T) -&gt; Result&lt;(), FailedAllocationError&gt; { &gt; #[cfg(feature = "known_system_malloc")] &gt; { &gt;@@ -47,48 +46,45 @@ fn try_double_vec&lt;T&gt;(vec: &amp;mut Vec&lt;T&gt;) -&gt; Result&lt;(), FailedAllocationError&gt; { &gt; &gt; let old_ptr = vec.as_mut_ptr(); &gt; let old_len = vec.len(); &gt; &gt; let old_cap: usize = vec.capacity(); &gt; let new_cap: usize = if old_cap == 0 { &gt; 4 &gt; } else { &gt;- old_cap.checked_mul(2).ok_or(FailedAllocationError::new( &gt;- "capacity overflow for Vec", &gt;- ))? &gt;+ old_cap &gt;+ .checked_mul(2) &gt;+ .ok_or(FailedAllocationError::new("capacity overflow for Vec"))? &gt; }; &gt; &gt;- let new_size_bytes = new_cap.checked_mul(mem::size_of::&lt;T&gt;()).ok_or( &gt;- FailedAllocationError::new("capacity overflow for Vec"), &gt;- )?; &gt;+ let new_size_bytes = new_cap &gt;+ .checked_mul(mem::size_of::&lt;T&gt;()) &gt;+ .ok_or(FailedAllocationError::new("capacity overflow for Vec"))?; &gt; &gt; let new_ptr = unsafe { &gt; if old_cap == 0 { &gt; alloc::alloc(new_size_bytes, 0) &gt; } else { &gt; alloc::realloc(old_ptr as *mut u8, new_size_bytes) &gt; } &gt; }; &gt; &gt; if new_ptr.is_null() { &gt; return Err(FailedAllocationError::new( &gt; "out of memory when allocating Vec", &gt; )); &gt; } &gt; &gt;- let new_vec = unsafe { &gt;- Vec::from_raw_parts(new_ptr as *mut T, old_len, new_cap) &gt;- }; &gt;+ let new_vec = unsafe { Vec::from_raw_parts(new_ptr as *mut T, old_len, new_cap) }; &gt; &gt; mem::forget(mem::replace(vec, new_vec)); &gt; Ok(()) &gt; } &gt; &gt;- &gt; ///////////////////////////////////////////////////////////////// &gt; // SmallVec &gt; &gt; impl&lt;T: Array&gt; FallibleVec&lt;T::Item&gt; for SmallVec&lt;T&gt; { &gt; #[inline(always)] &gt; fn try_push(&amp;mut self, val: T::Item) -&gt; Result&lt;(), FailedAllocationError&gt; { &gt; #[cfg(feature = "known_system_malloc")] &gt; { &gt;@@ -102,70 +98,66 @@ impl&lt;T: Array&gt; FallibleVec&lt;T::Item&gt; for SmallVec&lt;T&gt; { &gt; } &gt; } &gt; &gt; // Double the capacity of |svec|, or fail to do so due to lack of memory. &gt; // Returns Ok(()) on success, Err(..) on failure. &gt; #[cfg(feature = "known_system_malloc")] &gt; #[inline(never)] &gt; #[cold] &gt;-fn try_double_small_vec&lt;T&gt;(svec: &amp;mut SmallVec&lt;T&gt;) &gt;--&gt; Result&lt;(), FailedAllocationError&gt; &gt;+fn try_double_small_vec&lt;T&gt;(svec: &amp;mut SmallVec&lt;T&gt;) -&gt; Result&lt;(), FailedAllocationError&gt; &gt; where &gt; T: Array, &gt; { &gt; use std::mem; &gt; use std::ptr::copy_nonoverlapping; &gt; &gt; let old_ptr = svec.as_mut_ptr(); &gt; let old_len = svec.len(); &gt; &gt; let old_cap: usize = svec.capacity(); &gt; let new_cap: usize = if old_cap == 0 { &gt; 4 &gt; } else { &gt;- old_cap.checked_mul(2).ok_or(FailedAllocationError::new( &gt;- "capacity overflow for SmallVec", &gt;- ))? &gt;+ old_cap &gt;+ .checked_mul(2) &gt;+ .ok_or(FailedAllocationError::new("capacity overflow for SmallVec"))? &gt; }; &gt; &gt; // This surely shouldn't fail, if |old_cap| was previously accepted as a &gt; // valid value. But err on the side of caution. &gt;- let old_size_bytes = old_cap.checked_mul(mem::size_of::&lt;T&gt;()).ok_or( &gt;- FailedAllocationError::new("capacity overflow for SmallVec"), &gt;- )?; &gt;+ let old_size_bytes = old_cap &gt;+ .checked_mul(mem::size_of::&lt;T&gt;()) &gt;+ .ok_or(FailedAllocationError::new("capacity overflow for SmallVec"))?; &gt; &gt;- let new_size_bytes = new_cap.checked_mul(mem::size_of::&lt;T&gt;()).ok_or( &gt;- FailedAllocationError::new("capacity overflow for SmallVec"), &gt;- )?; &gt;+ let new_size_bytes = new_cap &gt;+ .checked_mul(mem::size_of::&lt;T&gt;()) &gt;+ .ok_or(FailedAllocationError::new("capacity overflow for SmallVec"))?; &gt; &gt; let new_ptr; &gt; if svec.spilled() { &gt; // There's an old block to free, and, presumably, old contents to &gt; // copy. realloc takes care of both aspects. &gt; unsafe { &gt; new_ptr = alloc::realloc(old_ptr as *mut u8, new_size_bytes); &gt; } &gt; } else { &gt; // There's no old block to free. There may be old contents to copy. &gt; unsafe { &gt; new_ptr = alloc::alloc(new_size_bytes, 0); &gt; if !new_ptr.is_null() &amp;&amp; old_size_bytes &gt; 0 { &gt;- copy_nonoverlapping(old_ptr as *const u8, &gt;- new_ptr as *mut u8, old_size_bytes); &gt;+ copy_nonoverlapping(old_ptr as *const u8, new_ptr as *mut u8, old_size_bytes); &gt; } &gt; } &gt; } &gt; &gt; if new_ptr.is_null() { &gt; return Err(FailedAllocationError::new( &gt; "out of memory when allocating SmallVec", &gt; )); &gt; } &gt; &gt;- let new_vec = unsafe { &gt;- Vec::from_raw_parts(new_ptr as *mut T::Item, old_len, new_cap) &gt;- }; &gt;+ let new_vec = unsafe { Vec::from_raw_parts(new_ptr as *mut T::Item, old_len, new_cap) }; &gt; &gt; let new_svec = SmallVec::from_vec(new_vec); &gt; mem::forget(mem::replace(svec, new_svec)); &gt; Ok(()) &gt; } &gt;diff --git a/servo/components/hashglobe/src/alloc.rs b/servo/components/hashglobe/src/alloc.rs &gt;index b0d622972db1..b1c7a6eca5ee 100644 &gt;--- a/servo/components/hashglobe/src/alloc.rs &gt;+++ b/servo/components/hashglobe/src/alloc.rs &gt;@@ -1,30 +1,31 @@ &gt; // FORK NOTE: Copied from liballoc_system, removed unnecessary APIs, &gt; // APIs take size/align directly instead of Layout &gt; &gt;- &gt;- &gt;- &gt; // The minimum alignment guaranteed by the architecture. This value is used to &gt; // add fast paths for low alignment values. In practice, the alignment is a &gt; // constant at the call site and the branch will be optimized out. &gt;-#[cfg(all(any(target_arch = "x86", &gt;- target_arch = "arm", &gt;- target_arch = "mips", &gt;- target_arch = "powerpc", &gt;- target_arch = "powerpc64", &gt;- target_arch = "asmjs", &gt;- target_arch = "wasm32")))] &gt;+#[cfg(all(any( &gt;+ target_arch = "x86", &gt;+ target_arch = "arm", &gt;+ target_arch = "mips", &gt;+ target_arch = "powerpc", &gt;+ target_arch = "powerpc64", &gt;+ target_arch = "asmjs", &gt;+ target_arch = "wasm32" &gt;+)))] &gt; const MIN_ALIGN: usize = 8; &gt;-#[cfg(all(any(target_arch = "x86_64", &gt;- target_arch = "aarch64", &gt;- target_arch = "mips64", &gt;- target_arch = "s390x", &gt;- target_arch = "sparc64")))] &gt;+#[cfg(all(any( &gt;+ target_arch = "x86_64", &gt;+ target_arch = "aarch64", &gt;+ target_arch = "mips64", &gt;+ target_arch = "s390x", &gt;+ target_arch = "sparc64" &gt;+)))] &gt; const MIN_ALIGN: usize = 16; &gt; &gt; pub use self::platform::{alloc, dealloc, realloc}; &gt; &gt; #[cfg(any(unix, target_os = "redox"))] &gt; mod platform { &gt; extern crate libc; &gt; &gt;@@ -95,17 +96,16 @@ mod platform { &gt; &gt; use super::MIN_ALIGN; &gt; type LPVOID = *mut u8; &gt; type HANDLE = LPVOID; &gt; type SIZE_T = usize; &gt; type DWORD = u32; &gt; type BOOL = i32; &gt; &gt;- &gt; extern "system" { &gt; fn GetProcessHeap() -&gt; HANDLE; &gt; fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -&gt; LPVOID; &gt; fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -&gt; LPVOID; &gt; fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -&gt; BOOL; &gt; fn GetLastError() -&gt; DWORD; &gt; } &gt; &gt;@@ -118,18 +118,17 @@ mod platform { &gt; &gt; unsafe fn align_ptr(ptr: *mut u8, align: usize) -&gt; *mut u8 { &gt; let aligned = ptr.offset((align - (ptr as usize &amp; (align - 1))) as isize); &gt; *get_header(aligned) = Header(ptr); &gt; aligned &gt; } &gt; &gt; #[inline] &gt;- unsafe fn allocate_with_flags(size: usize, align: usize, flags: DWORD) -&gt; *mut u8 &gt;- { &gt;+ unsafe fn allocate_with_flags(size: usize, align: usize, flags: DWORD) -&gt; *mut u8 { &gt; if align &lt;= MIN_ALIGN { &gt; HeapAlloc(GetProcessHeap(), flags, size) &gt; } else { &gt; let size = size + align; &gt; let ptr = HeapAlloc(GetProcessHeap(), flags, size); &gt; if ptr.is_null() { &gt; ptr &gt; } else { &gt;@@ -142,26 +141,21 @@ mod platform { &gt; pub unsafe fn alloc(size: usize, align: usize) -&gt; *mut u8 { &gt; allocate_with_flags(size, align, 0) &gt; } &gt; &gt; #[inline] &gt; pub unsafe fn dealloc(ptr: *mut u8, align: usize) { &gt; if align &lt;= MIN_ALIGN { &gt; let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); &gt;- debug_assert!(err != 0, "Failed to free heap memory: {}", &gt;- GetLastError()); &gt;+ debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); &gt; } else { &gt; let header = get_header(ptr); &gt; let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); &gt;- debug_assert!(err != 0, "Failed to free heap memory: {}", &gt;- GetLastError()); &gt;+ debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); &gt; } &gt; } &gt; &gt; #[inline] &gt; pub unsafe fn realloc(ptr: *mut u8, new_size: usize) -&gt; *mut u8 { &gt;- HeapReAlloc(GetProcessHeap(), &gt;- 0, &gt;- ptr as LPVOID, &gt;- new_size) as *mut u8 &gt;+ HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8 &gt; } &gt; } &gt;diff --git a/servo/components/hashglobe/src/fake.rs b/servo/components/hashglobe/src/fake.rs &gt;index eba21e041488..d2cdd549e48d 100644 &gt;--- a/servo/components/hashglobe/src/fake.rs &gt;+++ b/servo/components/hashglobe/src/fake.rs &gt;@@ -15,59 +15,62 @@ &gt; //! it smooth to switch between hashmap impls in a codebase. &gt; &gt; use std::collections::HashMap as StdMap; &gt; use std::collections::HashSet as StdSet; &gt; use std::fmt; &gt; use std::hash::{BuildHasher, Hash}; &gt; use std::ops::{Deref, DerefMut}; &gt; &gt;-pub use std::collections::hash_map::{Entry, RandomState, Iter as MapIter, IterMut as MapIterMut}; &gt;-pub use std::collections::hash_set::{Iter as SetIter, IntoIter as SetIntoIter}; &gt;+pub use std::collections::hash_map::{Entry, Iter as MapIter, IterMut as MapIterMut, RandomState}; &gt;+pub use std::collections::hash_set::{IntoIter as SetIntoIter, Iter as SetIter}; &gt; &gt; #[derive(Clone)] &gt; pub struct HashMap&lt;K, V, S = RandomState&gt;(StdMap&lt;K, V, S&gt;); &gt; &gt;- &gt; use FailedAllocationError; &gt; &gt; impl&lt;K, V, S&gt; Deref for HashMap&lt;K, V, S&gt; { &gt; type Target = StdMap&lt;K, V, S&gt;; &gt; fn deref(&amp;self) -&gt; &amp;Self::Target { &gt; &amp;self.0 &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; DerefMut for HashMap&lt;K, V, S&gt; { &gt; fn deref_mut(&amp;mut self) -&gt; &amp;mut Self::Target { &gt; &amp;mut self.0 &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; #[inline] &gt; pub fn try_with_hasher(hash_builder: S) -&gt; Result&lt;HashMap&lt;K, V, S&gt;, FailedAllocationError&gt; { &gt; Ok(HashMap(StdMap::with_hasher(hash_builder))) &gt; } &gt; &gt; #[inline] &gt;- pub fn try_with_capacity_and_hasher(capacity: usize, &gt;- hash_builder: S) &gt;- -&gt; Result&lt;HashMap&lt;K, V, S&gt;, FailedAllocationError&gt; { &gt;- Ok(HashMap(StdMap::with_capacity_and_hasher(capacity, hash_builder))) &gt;+ pub fn try_with_capacity_and_hasher( &gt;+ capacity: usize, &gt;+ hash_builder: S, &gt;+ ) -&gt; Result&lt;HashMap&lt;K, V, S&gt;, FailedAllocationError&gt; { &gt;+ Ok(HashMap(StdMap::with_capacity_and_hasher( &gt;+ capacity, &gt;+ hash_builder, &gt;+ ))) &gt; } &gt; &gt; pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -&gt; HashMap&lt;K, V, S&gt; { &gt; HashMap(StdMap::with_capacity_and_hasher(capacity, hash_builder)) &gt; } &gt; &gt;- &gt; #[inline] &gt; pub fn try_reserve(&amp;mut self, additional: usize) -&gt; Result&lt;(), FailedAllocationError&gt; { &gt; Ok(self.reserve(additional)) &gt; } &gt; &gt; pub fn try_shrink_to_fit(&amp;mut self) -&gt; Result&lt;(), FailedAllocationError&gt; { &gt; Ok(self.shrink_to_fit()) &gt; } &gt;@@ -80,17 +83,16 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; pub fn try_insert(&amp;mut self, k: K, v: V) -&gt; Result&lt;Option&lt;V&gt;, FailedAllocationError&gt; { &gt; Ok(self.insert(k, v)) &gt; } &gt; } &gt; &gt; #[derive(Clone)] &gt; pub struct HashSet&lt;T, S = RandomState&gt;(StdSet&lt;T, S&gt;); &gt; &gt;- &gt; impl&lt;T, S&gt; Deref for HashSet&lt;T, S&gt; { &gt; type Target = StdSet&lt;T, S&gt;; &gt; fn deref(&amp;self) -&gt; &amp;Self::Target { &gt; &amp;self.0 &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; DerefMut for HashSet&lt;T, S&gt; { &gt;@@ -106,27 +108,26 @@ impl&lt;T: Hash + Eq&gt; HashSet&lt;T, RandomState&gt; { &gt; } &gt; &gt; #[inline] &gt; pub fn with_capacity(capacity: usize) -&gt; HashSet&lt;T, RandomState&gt; { &gt; HashSet(StdSet::with_capacity(capacity)) &gt; } &gt; } &gt; &gt;- &gt; impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; #[inline] &gt; pub fn with_hasher(hasher: S) -&gt; HashSet&lt;T, S&gt; { &gt; HashSet(StdSet::with_hasher(hasher)) &gt; } &gt; &gt;- &gt; #[inline] &gt; pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -&gt; HashSet&lt;T, S&gt; { &gt; HashSet(StdSet::with_capacity_and_hasher(capacity, hasher)) &gt; } &gt; &gt; #[inline] &gt; pub fn try_reserve(&amp;mut self, additional: usize) -&gt; Result&lt;(), FailedAllocationError&gt; { &gt; Ok(self.reserve(additional)) &gt;@@ -148,113 +149,121 @@ impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt; &gt; impl&lt;K: Hash + Eq, V, S: BuildHasher + Default&gt; Default for HashMap&lt;K, V, S&gt; { &gt; fn default() -&gt; Self { &gt; HashMap(Default::default()) &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; fmt::Debug for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash + fmt::Debug, &gt;- V: fmt::Debug, &gt;- S: BuildHasher { &gt;+where &gt;+ K: Eq + Hash + fmt::Debug, &gt;+ V: fmt::Debug, &gt;+ S: BuildHasher, &gt;+{ &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; self.0.fmt(f) &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; PartialEq for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- V: PartialEq, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ V: PartialEq, &gt;+ S: BuildHasher, &gt; { &gt; fn eq(&amp;self, other: &amp;HashMap&lt;K, V, S&gt;) -&gt; bool { &gt; self.0.eq(&amp;other.0) &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; Eq for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- V: Eq, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ V: Eq, &gt;+ S: BuildHasher, &gt; { &gt; } &gt; &gt; impl&lt;'a, K, V, S&gt; IntoIterator for &amp;'a HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = (&amp;'a K, &amp;'a V); &gt; type IntoIter = MapIter&lt;'a, K, V&gt;; &gt; &gt; fn into_iter(self) -&gt; MapIter&lt;'a, K, V&gt; { &gt; self.0.iter() &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V, S&gt; IntoIterator for &amp;'a mut HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = (&amp;'a K, &amp;'a mut V); &gt; type IntoIter = MapIterMut&lt;'a, K, V&gt;; &gt; &gt; fn into_iter(self) -&gt; MapIterMut&lt;'a, K, V&gt; { &gt; self.0.iter_mut() &gt; } &gt; } &gt; &gt; impl&lt;T: Eq + Hash, S: BuildHasher + Default&gt; Default for HashSet&lt;T, S&gt; { &gt; fn default() -&gt; Self { &gt; HashSet(Default::default()) &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; fmt::Debug for HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash + fmt::Debug, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash + fmt::Debug, &gt;+ S: BuildHasher, &gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; self.0.fmt(f) &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; PartialEq for HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn eq(&amp;self, other: &amp;HashSet&lt;T, S&gt;) -&gt; bool { &gt; self.0.eq(&amp;other.0) &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; Eq for HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; } &gt; &gt; impl&lt;'a, T, S&gt; IntoIterator for &amp;'a HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = &amp;'a T; &gt; type IntoIter = SetIter&lt;'a, T&gt;; &gt; &gt; fn into_iter(self) -&gt; SetIter&lt;'a, T&gt; { &gt; self.0.iter() &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; IntoIterator for HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = T; &gt; type IntoIter = SetIntoIter&lt;T&gt;; &gt; &gt;- &gt; fn into_iter(self) -&gt; SetIntoIter&lt;T&gt; { &gt; self.0.into_iter() &gt; } &gt; } &gt;- &gt;- &gt;diff --git a/servo/components/hashglobe/src/hash_map.rs b/servo/components/hashglobe/src/hash_map.rs &gt;index 27077526b3ae..0946ed636903 100644 &gt;--- a/servo/components/hashglobe/src/hash_map.rs &gt;+++ b/servo/components/hashglobe/src/hash_map.rs &gt;@@ -10,27 +10,27 @@ &gt; &gt; use self::Entry::*; &gt; use self::VacantEntryState::*; &gt; &gt; use std::borrow::Borrow; &gt; use std::cmp::max; &gt; use std::fmt::{self, Debug}; &gt; #[allow(deprecated)] &gt;-use std::hash::{Hash, BuildHasher}; &gt;+use std::hash::{BuildHasher, Hash}; &gt; use std::iter::FromIterator; &gt; use std::mem::{self, replace}; &gt; use std::ops::{Deref, Index}; &gt; &gt;-use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; &gt; use super::table::BucketState::{Empty, Full}; &gt;+use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; &gt; &gt; use FailedAllocationError; &gt; &gt;-const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two &gt;+const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two &gt; &gt; /// The default behavior of HashMap implements a maximum load factor of 90.9%. &gt; #[derive(Clone)] &gt; struct DefaultResizePolicy; &gt; &gt; impl DefaultResizePolicy { &gt; fn new() -&gt; DefaultResizePolicy { &gt; DefaultResizePolicy &gt;@@ -45,17 +45,19 @@ impl DefaultResizePolicy { &gt; if len == 0 { &gt; 0 &gt; } else { &gt; // 1. Account for loading: `raw_capacity &gt;= len * 1.1`. &gt; // 2. Ensure it is a power of two. &gt; // 3. Ensure it is at least the minimum size. &gt; let mut raw_cap = len * 11 / 10; &gt; assert!(raw_cap &gt;= len, "raw_cap overflow"); &gt;- raw_cap = raw_cap.checked_next_power_of_two().expect("raw_capacity overflow"); &gt;+ raw_cap = raw_cap &gt;+ .checked_next_power_of_two() &gt;+ .expect("raw_capacity overflow"); &gt; raw_cap = max(MIN_NONZERO_RAW_CAPACITY, raw_cap); &gt; raw_cap &gt; } &gt; } &gt; &gt; /// The capacity of the given raw capacity. &gt; #[inline] &gt; fn capacity(&amp;self, raw_cap: usize) -&gt; usize { &gt;@@ -393,18 +395,19 @@ pub struct HashMap&lt;K, V, S = RandomState&gt; { &gt; table: RawTable&lt;K, V&gt;, &gt; &gt; resize_policy: DefaultResizePolicy, &gt; } &gt; &gt; /// Search for a pre-hashed key. &gt; #[inline] &gt; fn search_hashed&lt;K, V, M, F&gt;(table: M, hash: SafeHash, mut is_match: F) -&gt; InternalEntry&lt;K, V, M&gt; &gt;- where M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt;, &gt;- F: FnMut(&amp;K) -&gt; bool &gt;+where &gt;+ M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt;, &gt;+ F: FnMut(&amp;K) -&gt; bool, &gt; { &gt; // This is the only function where capacity can be zero. To avoid &gt; // undefined behavior when Bucket::new gets the raw bucket in this &gt; // case, immediately return the appropriate search result. &gt; if table.capacity() == 0 { &gt; return InternalEntry::TableIsEmpty; &gt; } &gt; &gt;@@ -444,48 +447,47 @@ fn search_hashed&lt;K, V, M, F&gt;(table: M, hash: SafeHash, mut is_match: F) -&gt; Inter &gt; } &gt; } &gt; displacement += 1; &gt; probe = full.next(); &gt; debug_assert!(displacement &lt;= size); &gt; } &gt; } &gt; &gt;-fn pop_internal&lt;K, V&gt;(starting_bucket: FullBucketMut&lt;K, V&gt;) &gt;- -&gt; (K, V, &amp;mut RawTable&lt;K, V&gt;) &gt;-{ &gt;+fn pop_internal&lt;K, V&gt;(starting_bucket: FullBucketMut&lt;K, V&gt;) -&gt; (K, V, &amp;mut RawTable&lt;K, V&gt;) { &gt; let (empty, retkey, retval) = starting_bucket.take(); &gt; let mut gap = match empty.gap_peek() { &gt; Ok(b) =&gt; b, &gt; Err(b) =&gt; return (retkey, retval, b.into_table()), &gt; }; &gt; &gt; while gap.full().displacement() != 0 { &gt; gap = match gap.shift() { &gt; Ok(b) =&gt; b, &gt; Err(b) =&gt; { &gt; return (retkey, retval, b.into_table()); &gt;- }, &gt;+ } &gt; }; &gt; } &gt; &gt; // Now we've done all our shifting. Return the value we grabbed earlier. &gt; (retkey, retval, gap.into_table()) &gt; } &gt; &gt; /// Perform robin hood bucket stealing at the given `bucket`. You must &gt; /// also pass that bucket's displacement so we don't have to recalculate it. &gt; /// &gt; /// `hash`, `key`, and `val` are the elements to "robin hood" into the hashtable. &gt;-fn robin_hood&lt;'a, K: 'a, V: 'a&gt;(bucket: FullBucketMut&lt;'a, K, V&gt;, &gt;- mut displacement: usize, &gt;- mut hash: SafeHash, &gt;- mut key: K, &gt;- mut val: V) &gt;- -&gt; FullBucketMut&lt;'a, K, V&gt; { &gt;+fn robin_hood&lt;'a, K: 'a, V: 'a&gt;( &gt;+ bucket: FullBucketMut&lt;'a, K, V&gt;, &gt;+ mut displacement: usize, &gt;+ mut hash: SafeHash, &gt;+ mut key: K, &gt;+ mut val: V, &gt;+) -&gt; FullBucketMut&lt;'a, K, V&gt; { &gt; let size = bucket.table().size(); &gt; let raw_capacity = bucket.table().capacity(); &gt; // There can be at most `size - dib` buckets to displace, because &gt; // in the worst case, there are `size` elements and we already are &gt; // `displacement` buckets away from the initial one. &gt; let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity; &gt; // Save the *starting point*. &gt; let mut bucket = bucket.stash(); &gt;@@ -526,41 +528,45 @@ fn robin_hood&lt;'a, K: 'a, V: 'a&gt;(bucket: FullBucketMut&lt;'a, K, V&gt;, &gt; displacement = probe_displacement; &gt; break; &gt; } &gt; } &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn make_hash&lt;X: ?Sized&gt;(&amp;self, x: &amp;X) -&gt; SafeHash &gt;- where X: Hash &gt;+ where &gt;+ X: Hash, &gt; { &gt; table::make_hash(&amp;self.hash_builder, x) &gt; } &gt; &gt; /// Search for a key, yielding the index if it's found in the hashtable. &gt; /// If you already have the hash for the key lying around, use &gt; /// search_hashed. &gt; #[inline] &gt; fn search&lt;'a, Q: ?Sized&gt;(&amp;'a self, q: &amp;Q) -&gt; InternalEntry&lt;K, V, &amp;'a RawTable&lt;K, V&gt;&gt; &gt;- where K: Borrow&lt;Q&gt;, &gt;- Q: Eq + Hash &gt;+ where &gt;+ K: Borrow&lt;Q&gt;, &gt;+ Q: Eq + Hash, &gt; { &gt; let hash = self.make_hash(q); &gt; search_hashed(&amp;self.table, hash, |k| q.eq(k.borrow())) &gt; } &gt; &gt; #[inline] &gt; fn search_mut&lt;'a, Q: ?Sized&gt;(&amp;'a mut self, q: &amp;Q) -&gt; InternalEntry&lt;K, V, &amp;'a mut RawTable&lt;K, V&gt;&gt; &gt;- where K: Borrow&lt;Q&gt;, &gt;- Q: Eq + Hash &gt;+ where &gt;+ K: Borrow&lt;Q&gt;, &gt;+ Q: Eq + Hash, &gt; { &gt; let hash = self.make_hash(q); &gt; search_hashed(&amp;mut self.table, hash, |k| q.eq(k.borrow())) &gt; } &gt; &gt; // The caller should ensure that invariants by Robin Hood Hashing hold &gt; // and that there's space in the underlying table. &gt; fn insert_hashed_ordered(&amp;mut self, hash: SafeHash, k: K, v: V) { &gt;@@ -579,18 +585,19 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; }; &gt; buckets.next(); &gt; debug_assert_ne!(buckets.index(), start_index); &gt; } &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; /// Creates an empty `HashMap` which will use the given hash builder to hash &gt; /// keys. &gt; /// &gt; /// The created map has the default initial capacity. &gt; /// &gt; /// Warning: `hash_builder` is normally randomly generated, and &gt; /// is designed to allow HashMaps to be resistant to attacks that &gt;@@ -638,17 +645,20 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; /// use std::collections::HashMap; &gt; /// use std::collections::hash_map::RandomState; &gt; /// &gt; /// let s = RandomState::new(); &gt; /// let mut map = HashMap::with_capacity_and_hasher(10, s); &gt; /// map.insert(1, 2); &gt; /// ``` &gt; #[inline] &gt;- pub fn try_with_capacity_and_hasher(capacity: usize, hash_builder: S) -&gt; Result&lt;HashMap&lt;K, V, S&gt;, FailedAllocationError&gt; { &gt;+ pub fn try_with_capacity_and_hasher( &gt;+ capacity: usize, &gt;+ hash_builder: S, &gt;+ ) -&gt; Result&lt;HashMap&lt;K, V, S&gt;, FailedAllocationError&gt; { &gt; let resize_policy = DefaultResizePolicy::new(); &gt; let raw_cap = resize_policy.raw_capacity(capacity); &gt; Ok(HashMap { &gt; hash_builder, &gt; resize_policy, &gt; table: RawTable::new(raw_cap)?, &gt; }) &gt; } &gt;@@ -703,22 +713,24 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; /// use std::collections::HashMap; &gt; /// let mut map: HashMap&lt;&amp;str, isize&gt; = HashMap::new(); &gt; /// map.reserve(10); &gt; /// ``` &gt; pub fn reserve(&amp;mut self, additional: usize) { &gt; self.try_reserve(additional).unwrap(); &gt; } &gt; &gt;- &gt; #[inline] &gt; pub fn try_reserve(&amp;mut self, additional: usize) -&gt; Result&lt;(), FailedAllocationError&gt; { &gt; let remaining = self.capacity() - self.len(); // this can't overflow &gt; if remaining &lt; additional { &gt;- let min_cap = self.len().checked_add(additional).expect("reserve overflow"); &gt;+ let min_cap = self &gt;+ .len() &gt;+ .checked_add(additional) &gt;+ .expect("reserve overflow"); &gt; let raw_cap = self.resize_policy.raw_capacity(min_cap); &gt; self.try_resize(raw_cap)?; &gt; } else if self.table.tag() &amp;&amp; remaining &lt;= self.len() { &gt; // Probe sequence is too long and table is half full, &gt; // resize early to reduce probing length. &gt; let new_capacity = self.table.capacity() * 2; &gt; self.try_resize(new_capacity)?; &gt; } &gt;@@ -887,17 +899,19 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; /// *val = *val + 10; &gt; /// } &gt; /// &gt; /// for val in map.values() { &gt; /// println!("{}", val); &gt; /// } &gt; /// ``` &gt; pub fn values_mut(&amp;mut self) -&gt; ValuesMut&lt;K, V&gt; { &gt;- ValuesMut { inner: self.iter_mut() } &gt;+ ValuesMut { &gt;+ inner: self.iter_mut(), &gt;+ } &gt; } &gt; &gt; /// An iterator visiting all key-value pairs in arbitrary order. &gt; /// The iterator element type is `(&amp;'a K, &amp;'a V)`. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt;@@ -908,17 +922,19 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; /// map.insert("b", 2); &gt; /// map.insert("c", 3); &gt; /// &gt; /// for (key, val) in map.iter() { &gt; /// println!("key: {} val: {}", key, val); &gt; /// } &gt; /// ``` &gt; pub fn iter(&amp;self) -&gt; Iter&lt;K, V&gt; { &gt;- Iter { inner: self.table.iter() } &gt;+ Iter { &gt;+ inner: self.table.iter(), &gt;+ } &gt; } &gt; &gt; /// An iterator visiting all key-value pairs in arbitrary order, &gt; /// with mutable references to the values. &gt; /// The iterator element type is `(&amp;'a K, &amp;'a mut V)`. &gt; /// &gt; /// # Examples &gt; /// &gt;@@ -935,17 +951,19 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; /// *val *= 2; &gt; /// } &gt; /// &gt; /// for (key, val) in &amp;map { &gt; /// println!("key: {} val: {}", key, val); &gt; /// } &gt; /// ``` &gt; pub fn iter_mut(&amp;mut self) -&gt; IterMut&lt;K, V&gt; { &gt;- IterMut { inner: self.table.iter_mut() } &gt;+ IterMut { &gt;+ inner: self.table.iter_mut(), &gt;+ } &gt; } &gt; &gt; /// Gets the given key's corresponding entry in the map for in-place manipulation. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt; /// use std::collections::HashMap; &gt;@@ -967,17 +985,18 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; } &gt; &gt; #[inline(always)] &gt; pub fn try_entry(&amp;mut self, key: K) -&gt; Result&lt;Entry&lt;K, V&gt;, FailedAllocationError&gt; { &gt; // Gotta resize now. &gt; self.try_reserve(1)?; &gt; let hash = self.make_hash(&amp;key); &gt; Ok(search_hashed(&amp;mut self.table, hash, |q| q.eq(&amp;key)) &gt;- .into_entry(key).expect("unreachable")) &gt;+ .into_entry(key) &gt;+ .expect("unreachable")) &gt; } &gt; &gt; /// Returns the number of elements in the map. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt; /// use std::collections::HashMap; &gt;@@ -1023,35 +1042,45 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; /// for (k, v) in a.drain().take(1) { &gt; /// assert!(k == 1 || k == 2); &gt; /// assert!(v == "a" || v == "b"); &gt; /// } &gt; /// &gt; /// assert!(a.is_empty()); &gt; /// ``` &gt; #[inline] &gt;- pub fn drain(&amp;mut self) -&gt; Drain&lt;K, V&gt; where K: 'static, V: 'static { &gt;- Drain { inner: self.table.drain() } &gt;+ pub fn drain(&amp;mut self) -&gt; Drain&lt;K, V&gt; &gt;+ where &gt;+ K: 'static, &gt;+ V: 'static, &gt;+ { &gt;+ Drain { &gt;+ inner: self.table.drain(), &gt;+ } &gt; } &gt; &gt; /// Clears the map, removing all key-value pairs. Keeps the allocated memory &gt; /// for reuse. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt; /// use std::collections::HashMap; &gt; /// &gt; /// let mut a = HashMap::new(); &gt; /// a.insert(1, "a"); &gt; /// a.clear(); &gt; /// assert!(a.is_empty()); &gt; /// ``` &gt; #[inline] &gt;- pub fn clear(&amp;mut self) where K: 'static, V: 'static { &gt;+ pub fn clear(&amp;mut self) &gt;+ where &gt;+ K: 'static, &gt;+ V: 'static, &gt;+ { &gt; self.drain(); &gt; } &gt; &gt; /// Returns a reference to the value corresponding to the key. &gt; /// &gt; /// The key may be any borrowed form of the map's key type, but &gt; /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for &gt; /// the key type. &gt;@@ -1065,20 +1094,23 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; /// use std::collections::HashMap; &gt; /// &gt; /// let mut map = HashMap::new(); &gt; /// map.insert(1, "a"); &gt; /// assert_eq!(map.get(&amp;1), Some(&amp;"a")); &gt; /// assert_eq!(map.get(&amp;2), None); &gt; /// ``` &gt; pub fn get&lt;Q: ?Sized&gt;(&amp;self, k: &amp;Q) -&gt; Option&lt;&amp;V&gt; &gt;- where K: Borrow&lt;Q&gt;, &gt;- Q: Hash + Eq &gt;+ where &gt;+ K: Borrow&lt;Q&gt;, &gt;+ Q: Hash + Eq, &gt; { &gt;- self.search(k).into_occupied_bucket().map(|bucket| bucket.into_refs().1) &gt;+ self.search(k) &gt;+ .into_occupied_bucket() &gt;+ .map(|bucket| bucket.into_refs().1) &gt; } &gt; &gt; /// Returns true if the map contains a value for the specified key. &gt; /// &gt; /// The key may be any borrowed form of the map's key type, but &gt; /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for &gt; /// the key type. &gt; /// &gt;@@ -1091,18 +1123,19 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; /// use std::collections::HashMap; &gt; /// &gt; /// let mut map = HashMap::new(); &gt; /// map.insert(1, "a"); &gt; /// assert_eq!(map.contains_key(&amp;1), true); &gt; /// assert_eq!(map.contains_key(&amp;2), false); &gt; /// ``` &gt; pub fn contains_key&lt;Q: ?Sized&gt;(&amp;self, k: &amp;Q) -&gt; bool &gt;- where K: Borrow&lt;Q&gt;, &gt;- Q: Hash + Eq &gt;+ where &gt;+ K: Borrow&lt;Q&gt;, &gt;+ Q: Hash + Eq, &gt; { &gt; self.search(k).into_occupied_bucket().is_some() &gt; } &gt; &gt; /// Returns a mutable reference to the value corresponding to the key. &gt; /// &gt; /// The key may be any borrowed form of the map's key type, but &gt; /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for &gt;@@ -1119,20 +1152,23 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; /// let mut map = HashMap::new(); &gt; /// map.insert(1, "a"); &gt; /// if let Some(x) = map.get_mut(&amp;1) { &gt; /// *x = "b"; &gt; /// } &gt; /// assert_eq!(map[&amp;1], "b"); &gt; /// ``` &gt; pub fn get_mut&lt;Q: ?Sized&gt;(&amp;mut self, k: &amp;Q) -&gt; Option&lt;&amp;mut V&gt; &gt;- where K: Borrow&lt;Q&gt;, &gt;- Q: Hash + Eq &gt;+ where &gt;+ K: Borrow&lt;Q&gt;, &gt;+ Q: Hash + Eq, &gt; { &gt;- self.search_mut(k).into_occupied_bucket().map(|bucket| bucket.into_mut_refs().1) &gt;+ self.search_mut(k) &gt;+ .into_occupied_bucket() &gt;+ .map(|bucket| bucket.into_mut_refs().1) &gt; } &gt; &gt; /// Inserts a key-value pair into the map. &gt; /// &gt; /// If the map did not have this key present, [`None`] is returned. &gt; /// &gt; /// If the map did have this key present, the value is updated, and the old &gt; /// value is returned. The key is not updated, though; this matters for &gt;@@ -1182,41 +1218,45 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; /// use std::collections::HashMap; &gt; /// &gt; /// let mut map = HashMap::new(); &gt; /// map.insert(1, "a"); &gt; /// assert_eq!(map.remove(&amp;1), Some("a")); &gt; /// assert_eq!(map.remove(&amp;1), None); &gt; /// ``` &gt; pub fn remove&lt;Q: ?Sized&gt;(&amp;mut self, k: &amp;Q) -&gt; Option&lt;V&gt; &gt;- where K: Borrow&lt;Q&gt;, &gt;- Q: Hash + Eq &gt;+ where &gt;+ K: Borrow&lt;Q&gt;, &gt;+ Q: Hash + Eq, &gt; { &gt; if self.table.size() == 0 { &gt; return None; &gt; } &gt; &gt;- self.search_mut(k).into_occupied_bucket().map(|bucket| pop_internal(bucket).1) &gt;+ self.search_mut(k) &gt;+ .into_occupied_bucket() &gt;+ .map(|bucket| pop_internal(bucket).1) &gt; } &gt; &gt; /// Retains only the elements specified by the predicate. &gt; /// &gt; /// In other words, remove all pairs `(k, v)` such that `f(&amp;k,&amp;mut v)` returns `false`. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt; /// use std::collections::HashMap; &gt; /// &gt; /// let mut map: HashMap&lt;isize, isize&gt; = (0..8).map(|x|(x, x*10)).collect(); &gt; /// map.retain(|&amp;k, _| k % 2 == 0); &gt; /// assert_eq!(map.len(), 4); &gt; /// ``` &gt; pub fn retain&lt;F&gt;(&amp;mut self, mut f: F) &gt;- where F: FnMut(&amp;K, &amp;mut V) -&gt; bool &gt;+ where &gt;+ F: FnMut(&amp;K, &amp;mut V) -&gt; bool, &gt; { &gt; if self.table.size() == 0 { &gt; return; &gt; } &gt; let mut elems_left = self.table.size(); &gt; let mut bucket = Bucket::head_bucket(&amp;mut self.table); &gt; bucket.prev(); &gt; let start_index = bucket.index(); &gt;@@ -1230,72 +1270,76 @@ impl&lt;K, V, S&gt; HashMap&lt;K, V, S&gt; &gt; }; &gt; if should_remove { &gt; let prev_raw = full.raw(); &gt; let (_, _, t) = pop_internal(full); &gt; Bucket::new_from(prev_raw, t) &gt; } else { &gt; full.into_bucket() &gt; } &gt;- }, &gt;- Empty(b) =&gt; { &gt;- b.into_bucket() &gt; } &gt;+ Empty(b) =&gt; b.into_bucket(), &gt; }; &gt;- bucket.prev(); // reverse iteration &gt;+ bucket.prev(); // reverse iteration &gt; debug_assert!(elems_left == 0 || bucket.index() != start_index); &gt; } &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; PartialEq for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- V: PartialEq, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ V: PartialEq, &gt;+ S: BuildHasher, &gt; { &gt; fn eq(&amp;self, other: &amp;HashMap&lt;K, V, S&gt;) -&gt; bool { &gt; if self.len() != other.len() { &gt; return false; &gt; } &gt; &gt;- self.iter().all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) &gt;+ self.iter() &gt;+ .all(|(key, value)| other.get(key).map_or(false, |v| *value == *v)) &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; Eq for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- V: Eq, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ V: Eq, &gt;+ S: BuildHasher, &gt; { &gt; } &gt; &gt; impl&lt;K, V, S&gt; Debug for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash + Debug, &gt;- V: Debug, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash + Debug, &gt;+ V: Debug, &gt;+ S: BuildHasher, &gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; f.debug_map().entries(self.iter()).finish() &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; Default for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher + Default &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher + Default, &gt; { &gt; /// Creates an empty `HashMap&lt;K, V, S&gt;`, with the `Default` value for the hasher. &gt; fn default() -&gt; HashMap&lt;K, V, S&gt; { &gt; HashMap::with_hasher(Default::default()) &gt; } &gt; } &gt; &gt; impl&lt;'a, K, Q: ?Sized, V, S&gt; Index&lt;&amp;'a Q&gt; for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash + Borrow&lt;Q&gt;, &gt;- Q: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash + Borrow&lt;Q&gt;, &gt;+ Q: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Output = V; &gt; &gt; #[inline] &gt; fn index(&amp;self, index: &amp;Q) -&gt; &amp;V { &gt; self.get(index).expect("no entry found for key") &gt; } &gt; } &gt;@@ -1309,25 +1353,25 @@ impl&lt;'a, K, Q: ?Sized, V, S&gt; Index&lt;&amp;'a Q&gt; for HashMap&lt;K, V, S&gt; &gt; /// [`HashMap`]: struct.HashMap.html &gt; pub struct Iter&lt;'a, K: 'a, V: 'a&gt; { &gt; inner: table::Iter&lt;'a, K, V&gt;, &gt; } &gt; &gt; // FIXME(#19839) Remove in favor of `#[derive(Clone)]` &gt; impl&lt;'a, K, V&gt; Clone for Iter&lt;'a, K, V&gt; { &gt; fn clone(&amp;self) -&gt; Iter&lt;'a, K, V&gt; { &gt;- Iter { inner: self.inner.clone() } &gt;+ Iter { &gt;+ inner: self.inner.clone(), &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'a, K: Debug, V: Debug&gt; fmt::Debug for Iter&lt;'a, K, V&gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- f.debug_list() &gt;- .entries(self.clone()) &gt;- .finish() &gt;+ f.debug_list().entries(self.clone()).finish() &gt; } &gt; } &gt; &gt; /// A mutable iterator over the entries of a `HashMap`. &gt; /// &gt; /// This `struct` is created by the [`iter_mut`] method on [`HashMap`]. See its &gt; /// documentation for more. &gt; /// &gt;@@ -1357,25 +1401,25 @@ pub struct IntoIter&lt;K, V&gt; { &gt; /// [`HashMap`]: struct.HashMap.html &gt; pub struct Keys&lt;'a, K: 'a, V: 'a&gt; { &gt; inner: Iter&lt;'a, K, V&gt;, &gt; } &gt; &gt; // FIXME(#19839) Remove in favor of `#[derive(Clone)]` &gt; impl&lt;'a, K, V&gt; Clone for Keys&lt;'a, K, V&gt; { &gt; fn clone(&amp;self) -&gt; Keys&lt;'a, K, V&gt; { &gt;- Keys { inner: self.inner.clone() } &gt;+ Keys { &gt;+ inner: self.inner.clone(), &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'a, K: Debug, V&gt; fmt::Debug for Keys&lt;'a, K, V&gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- f.debug_list() &gt;- .entries(self.clone()) &gt;- .finish() &gt;+ f.debug_list().entries(self.clone()).finish() &gt; } &gt; } &gt; &gt; /// An iterator over the values of a `HashMap`. &gt; /// &gt; /// This `struct` is created by the [`values`] method on [`HashMap`]. See its &gt; /// documentation for more. &gt; /// &gt;@@ -1383,25 +1427,25 @@ impl&lt;'a, K: Debug, V&gt; fmt::Debug for Keys&lt;'a, K, V&gt; { &gt; /// [`HashMap`]: struct.HashMap.html &gt; pub struct Values&lt;'a, K: 'a, V: 'a&gt; { &gt; inner: Iter&lt;'a, K, V&gt;, &gt; } &gt; &gt; // FIXME(#19839) Remove in favor of `#[derive(Clone)]` &gt; impl&lt;'a, K, V&gt; Clone for Values&lt;'a, K, V&gt; { &gt; fn clone(&amp;self) -&gt; Values&lt;'a, K, V&gt; { &gt;- Values { inner: self.inner.clone() } &gt;+ Values { &gt;+ inner: self.inner.clone(), &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V: Debug&gt; fmt::Debug for Values&lt;'a, K, V&gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- f.debug_list() &gt;- .entries(self.clone()) &gt;- .finish() &gt;+ f.debug_list().entries(self.clone()).finish() &gt; } &gt; } &gt; &gt; /// A draining iterator over the entries of a `HashMap`. &gt; /// &gt; /// This `struct` is created by the [`drain`] method on [`HashMap`]. See its &gt; /// documentation for more. &gt; /// &gt;@@ -1418,17 +1462,19 @@ pub struct Drain&lt;'a, K: 'static, V: 'static&gt; { &gt; /// &gt; /// [`values_mut`]: struct.HashMap.html#method.values_mut &gt; /// [`HashMap`]: struct.HashMap.html &gt; pub struct ValuesMut&lt;'a, K: 'a, V: 'a&gt; { &gt; inner: IterMut&lt;'a, K, V&gt;, &gt; } &gt; &gt; enum InternalEntry&lt;K, V, M&gt; { &gt;- Occupied { elem: FullBucket&lt;K, V, M&gt; }, &gt;+ Occupied { &gt;+ elem: FullBucket&lt;K, V, M&gt;, &gt;+ }, &gt; Vacant { &gt; hash: SafeHash, &gt; elem: VacantEntryState&lt;K, V, M&gt;, &gt; }, &gt; TableIsEmpty, &gt; } &gt; &gt; impl&lt;K, V, M&gt; InternalEntry&lt;K, V, M&gt; { &gt;@@ -1440,61 +1486,45 @@ impl&lt;K, V, M&gt; InternalEntry&lt;K, V, M&gt; { &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V&gt; InternalEntry&lt;K, V, &amp;'a mut RawTable&lt;K, V&gt;&gt; { &gt; #[inline] &gt; fn into_entry(self, key: K) -&gt; Option&lt;Entry&lt;'a, K, V&gt;&gt; { &gt; match self { &gt;- InternalEntry::Occupied { elem } =&gt; { &gt;- Some(Occupied(OccupiedEntry { &gt;- key: Some(key), &gt;- elem, &gt;- })) &gt;- } &gt;- InternalEntry::Vacant { hash, elem } =&gt; { &gt;- Some(Vacant(VacantEntry { &gt;- hash, &gt;- key, &gt;- elem, &gt;- })) &gt;- } &gt;+ InternalEntry::Occupied { elem } =&gt; Some(Occupied(OccupiedEntry { &gt;+ key: Some(key), &gt;+ elem, &gt;+ })), &gt;+ InternalEntry::Vacant { hash, elem } =&gt; Some(Vacant(VacantEntry { hash, key, elem })), &gt; InternalEntry::TableIsEmpty =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; /// A view into a single entry in a map, which may either be vacant or occupied. &gt; /// &gt; /// This `enum` is constructed from the [`entry`] method on [`HashMap`]. &gt; /// &gt; /// [`HashMap`]: struct.HashMap.html &gt; /// [`entry`]: struct.HashMap.html#method.entry &gt; pub enum Entry&lt;'a, K: 'a, V: 'a&gt; { &gt; /// An occupied entry. &gt;- Occupied( OccupiedEntry&lt;'a, K, V&gt;), &gt;+ Occupied(OccupiedEntry&lt;'a, K, V&gt;), &gt; &gt; /// A vacant entry. &gt;- Vacant( VacantEntry&lt;'a, K, V&gt;), &gt;+ Vacant(VacantEntry&lt;'a, K, V&gt;), &gt; } &gt; &gt; impl&lt;'a, K: 'a + Debug, V: 'a + Debug&gt; Debug for Entry&lt;'a, K, V&gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; match *self { &gt;- Vacant(ref v) =&gt; { &gt;- f.debug_tuple("Entry") &gt;- .field(v) &gt;- .finish() &gt;- } &gt;- Occupied(ref o) =&gt; { &gt;- f.debug_tuple("Entry") &gt;- .field(o) &gt;- .finish() &gt;- } &gt;+ Vacant(ref v) =&gt; f.debug_tuple("Entry").field(v).finish(), &gt;+ Occupied(ref o) =&gt; f.debug_tuple("Entry").field(o).finish(), &gt; } &gt; } &gt; } &gt; &gt; /// A view into an occupied entry in a `HashMap`. &gt; /// It is part of the [`Entry`] enum. &gt; /// &gt; /// [`Entry`]: enum.Entry.html &gt;@@ -1519,58 +1549,59 @@ impl&lt;'a, K: 'a + Debug, V: 'a + Debug&gt; Debug for OccupiedEntry&lt;'a, K, V&gt; { &gt; pub struct VacantEntry&lt;'a, K: 'a, V: 'a&gt; { &gt; hash: SafeHash, &gt; key: K, &gt; elem: VacantEntryState&lt;K, V, &amp;'a mut RawTable&lt;K, V&gt;&gt;, &gt; } &gt; &gt; impl&lt;'a, K: 'a + Debug, V: 'a&gt; Debug for VacantEntry&lt;'a, K, V&gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- f.debug_tuple("VacantEntry") &gt;- .field(self.key()) &gt;- .finish() &gt;+ f.debug_tuple("VacantEntry").field(self.key()).finish() &gt; } &gt; } &gt; &gt; /// Possible states of a VacantEntry. &gt; enum VacantEntryState&lt;K, V, M&gt; { &gt; /// The index is occupied, but the key to insert has precedence, &gt; /// and will kick the current one out on insertion. &gt; NeqElem(FullBucket&lt;K, V, M&gt;, usize), &gt; /// The index is genuinely vacant. &gt; NoElem(EmptyBucket&lt;K, V, M&gt;, usize), &gt; } &gt; &gt; impl&lt;'a, K, V, S&gt; IntoIterator for &amp;'a HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = (&amp;'a K, &amp;'a V); &gt; type IntoIter = Iter&lt;'a, K, V&gt;; &gt; &gt; fn into_iter(self) -&gt; Iter&lt;'a, K, V&gt; { &gt; self.iter() &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V, S&gt; IntoIterator for &amp;'a mut HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = (&amp;'a K, &amp;'a mut V); &gt; type IntoIter = IterMut&lt;'a, K, V&gt;; &gt; &gt; fn into_iter(self) -&gt; IterMut&lt;'a, K, V&gt; { &gt; self.iter_mut() &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; IntoIterator for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = (K, V); &gt; type IntoIter = IntoIter&lt;K, V&gt;; &gt; &gt; /// Creates a consuming iterator, that is, one that moves each key-value &gt; /// pair out of the map in arbitrary order. The map cannot be used after &gt; /// calling this. &gt; /// &gt;@@ -1583,17 +1614,19 @@ impl&lt;K, V, S&gt; IntoIterator for HashMap&lt;K, V, S&gt; &gt; /// map.insert("a", 1); &gt; /// map.insert("b", 2); &gt; /// map.insert("c", 3); &gt; /// &gt; /// // Not possible with .iter() &gt; /// let vec: Vec&lt;(&amp;str, isize)&gt; = map.into_iter().collect(); &gt; /// ``` &gt; fn into_iter(self) -&gt; IntoIter&lt;K, V&gt; { &gt;- IntoIter { inner: self.table.into_iter() } &gt;+ IntoIter { &gt;+ inner: self.table.into_iter(), &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V&gt; Iterator for Iter&lt;'a, K, V&gt; { &gt; type Item = (&amp;'a K, &amp;'a V); &gt; &gt; #[inline] &gt; fn next(&amp;mut self) -&gt; Option&lt;(&amp;'a K, &amp;'a V)&gt; { &gt;@@ -1606,17 +1639,16 @@ impl&lt;'a, K, V&gt; Iterator for Iter&lt;'a, K, V&gt; { &gt; } &gt; impl&lt;'a, K, V&gt; ExactSizeIterator for Iter&lt;'a, K, V&gt; { &gt; #[inline] &gt; fn len(&amp;self) -&gt; usize { &gt; self.inner.len() &gt; } &gt; } &gt; &gt;- &gt; impl&lt;'a, K, V&gt; Iterator for IterMut&lt;'a, K, V&gt; { &gt; type Item = (&amp;'a K, &amp;'a mut V); &gt; &gt; #[inline] &gt; fn next(&amp;mut self) -&gt; Option&lt;(&amp;'a K, &amp;'a mut V)&gt; { &gt; self.inner.next() &gt; } &gt; #[inline] &gt;@@ -1627,23 +1659,22 @@ impl&lt;'a, K, V&gt; Iterator for IterMut&lt;'a, K, V&gt; { &gt; impl&lt;'a, K, V&gt; ExactSizeIterator for IterMut&lt;'a, K, V&gt; { &gt; #[inline] &gt; fn len(&amp;self) -&gt; usize { &gt; self.inner.len() &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V&gt; fmt::Debug for IterMut&lt;'a, K, V&gt; &gt;- where K: fmt::Debug, &gt;- V: fmt::Debug, &gt;+where &gt;+ K: fmt::Debug, &gt;+ V: fmt::Debug, &gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- f.debug_list() &gt;- .entries(self.inner.iter()) &gt;- .finish() &gt;+ f.debug_list().entries(self.inner.iter()).finish() &gt; } &gt; } &gt; &gt; impl&lt;K, V&gt; Iterator for IntoIter&lt;K, V&gt; { &gt; type Item = (K, V); &gt; &gt; #[inline] &gt; fn next(&amp;mut self) -&gt; Option&lt;(K, V)&gt; { &gt;@@ -1658,19 +1689,17 @@ impl&lt;K, V&gt; ExactSizeIterator for IntoIter&lt;K, V&gt; { &gt; #[inline] &gt; fn len(&amp;self) -&gt; usize { &gt; self.inner.len() &gt; } &gt; } &gt; &gt; impl&lt;K: Debug, V: Debug&gt; fmt::Debug for IntoIter&lt;K, V&gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- f.debug_list() &gt;- .entries(self.inner.iter()) &gt;- .finish() &gt;+ f.debug_list().entries(self.inner.iter()).finish() &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V&gt; Iterator for Keys&lt;'a, K, V&gt; { &gt; type Item = &amp;'a K; &gt; &gt; #[inline] &gt; fn next(&amp;mut self) -&gt; Option&lt;(&amp;'a K)&gt; { &gt;@@ -1721,23 +1750,22 @@ impl&lt;'a, K, V&gt; Iterator for ValuesMut&lt;'a, K, V&gt; { &gt; impl&lt;'a, K, V&gt; ExactSizeIterator for ValuesMut&lt;'a, K, V&gt; { &gt; #[inline] &gt; fn len(&amp;self) -&gt; usize { &gt; self.inner.len() &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V&gt; fmt::Debug for ValuesMut&lt;'a, K, V&gt; &gt;- where K: fmt::Debug, &gt;- V: fmt::Debug, &gt;+where &gt;+ K: fmt::Debug, &gt;+ V: fmt::Debug, &gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- f.debug_list() &gt;- .entries(self.inner.inner.iter()) &gt;- .finish() &gt;+ f.debug_list().entries(self.inner.inner.iter()).finish() &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V&gt; Iterator for Drain&lt;'a, K, V&gt; { &gt; type Item = (K, V); &gt; &gt; #[inline] &gt; fn next(&amp;mut self) -&gt; Option&lt;(K, V)&gt; { &gt;@@ -1751,30 +1779,29 @@ impl&lt;'a, K, V&gt; Iterator for Drain&lt;'a, K, V&gt; { &gt; impl&lt;'a, K, V&gt; ExactSizeIterator for Drain&lt;'a, K, V&gt; { &gt; #[inline] &gt; fn len(&amp;self) -&gt; usize { &gt; self.inner.len() &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V&gt; fmt::Debug for Drain&lt;'a, K, V&gt; &gt;- where K: fmt::Debug, &gt;- V: fmt::Debug, &gt;+where &gt;+ K: fmt::Debug, &gt;+ V: fmt::Debug, &gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- f.debug_list() &gt;- .entries(self.inner.iter()) &gt;- .finish() &gt;+ f.debug_list().entries(self.inner.iter()).finish() &gt; } &gt; } &gt; &gt; // FORK NOTE: Removed Placer impl &gt; &gt; impl&lt;'a, K, V&gt; Entry&lt;'a, K, V&gt; { &gt;- /// Ensures a value is in the entry by inserting the default if empty, and returns &gt;+ /// Ensures a value is in the entry by inserting the default if empty, and returns &gt; /// a mutable reference to the value in the entry. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt; /// use std::collections::HashMap; &gt; /// &gt; /// let mut map: HashMap&lt;&amp;str, u32&gt; = HashMap::new(); &gt;@@ -1787,17 +1814,17 @@ impl&lt;'a, K, V&gt; Entry&lt;'a, K, V&gt; { &gt; /// ``` &gt; pub fn or_insert(self, default: V) -&gt; &amp;'a mut V { &gt; match self { &gt; Occupied(entry) =&gt; entry.into_mut(), &gt; Vacant(entry) =&gt; entry.insert(default), &gt; } &gt; } &gt; &gt;- /// Ensures a value is in the entry by inserting the result of the default function if empty, &gt;+ /// Ensures a value is in the entry by inserting the result of the default function if empty, &gt; /// and returns a mutable reference to the value in the entry. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt; /// use std::collections::HashMap; &gt; /// &gt; /// let mut map: HashMap&lt;&amp;str, String&gt; = HashMap::new(); &gt;@@ -1819,17 +1846,17 @@ impl&lt;'a, K, V&gt; Entry&lt;'a, K, V&gt; { &gt; /// # Examples &gt; /// &gt; /// ``` &gt; /// use std::collections::HashMap; &gt; /// &gt; /// let mut map: HashMap&lt;&amp;str, u32&gt; = HashMap::new(); &gt; /// assert_eq!(map.entry("poneyland").key(), &amp;"poneyland"); &gt; /// ``` &gt;- pub fn key(&amp;self) -&gt; &amp;K { &gt;+ pub fn key(&amp;self) -&gt; &amp;K { &gt; match *self { &gt; Occupied(ref entry) =&gt; entry.key(), &gt; Vacant(ref entry) =&gt; entry.key(), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V&gt; OccupiedEntry&lt;'a, K, V&gt; { &gt;@@ -1839,17 +1866,17 @@ impl&lt;'a, K, V&gt; OccupiedEntry&lt;'a, K, V&gt; { &gt; /// &gt; /// ``` &gt; /// use std::collections::HashMap; &gt; /// &gt; /// let mut map: HashMap&lt;&amp;str, u32&gt; = HashMap::new(); &gt; /// map.entry("poneyland").or_insert(12); &gt; /// assert_eq!(map.entry("poneyland").key(), &amp;"poneyland"); &gt; /// ``` &gt;- pub fn key(&amp;self) -&gt; &amp;K { &gt;+ pub fn key(&amp;self) -&gt; &amp;K { &gt; self.elem.read().0 &gt; } &gt; &gt; /// Take the ownership of the key and value from the map. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt;@@ -1861,17 +1888,17 @@ impl&lt;'a, K, V&gt; OccupiedEntry&lt;'a, K, V&gt; { &gt; /// &gt; /// if let Entry::Occupied(o) = map.entry("poneyland") { &gt; /// // We delete the entry from the map. &gt; /// o.remove_entry(); &gt; /// } &gt; /// &gt; /// assert_eq!(map.contains_key("poneyland"), false); &gt; /// ``` &gt;- pub fn remove_entry(self) -&gt; (K, V) { &gt;+ pub fn remove_entry(self) -&gt; (K, V) { &gt; let (k, v, _) = pop_internal(self.elem); &gt; (k, v) &gt; } &gt; &gt; /// Gets a reference to the value in the entry. &gt; /// &gt; /// # Examples &gt; /// &gt;@@ -1881,17 +1908,17 @@ impl&lt;'a, K, V&gt; OccupiedEntry&lt;'a, K, V&gt; { &gt; /// &gt; /// let mut map: HashMap&lt;&amp;str, u32&gt; = HashMap::new(); &gt; /// map.entry("poneyland").or_insert(12); &gt; /// &gt; /// if let Entry::Occupied(o) = map.entry("poneyland") { &gt; /// assert_eq!(o.get(), &amp;12); &gt; /// } &gt; /// ``` &gt;- pub fn get(&amp;self) -&gt; &amp;V { &gt;+ pub fn get(&amp;self) -&gt; &amp;V { &gt; self.elem.read().1 &gt; } &gt; &gt; /// Gets a mutable reference to the value in the entry. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt;@@ -1903,17 +1930,17 @@ impl&lt;'a, K, V&gt; OccupiedEntry&lt;'a, K, V&gt; { &gt; /// &gt; /// assert_eq!(map["poneyland"], 12); &gt; /// if let Entry::Occupied(mut o) = map.entry("poneyland") { &gt; /// *o.get_mut() += 10; &gt; /// } &gt; /// &gt; /// assert_eq!(map["poneyland"], 22); &gt; /// ``` &gt;- pub fn get_mut(&amp;mut self) -&gt; &amp;mut V { &gt;+ pub fn get_mut(&amp;mut self) -&gt; &amp;mut V { &gt; self.elem.read_mut().1 &gt; } &gt; &gt; /// Converts the OccupiedEntry into a mutable reference to the value in the entry &gt; /// with a lifetime bound to the map itself. &gt; /// &gt; /// # Examples &gt; /// &gt;@@ -1926,17 +1953,17 @@ impl&lt;'a, K, V&gt; OccupiedEntry&lt;'a, K, V&gt; { &gt; /// &gt; /// assert_eq!(map["poneyland"], 12); &gt; /// if let Entry::Occupied(o) = map.entry("poneyland") { &gt; /// *o.into_mut() += 10; &gt; /// } &gt; /// &gt; /// assert_eq!(map["poneyland"], 22); &gt; /// ``` &gt;- pub fn into_mut(self) -&gt; &amp;'a mut V { &gt;+ pub fn into_mut(self) -&gt; &amp;'a mut V { &gt; self.elem.into_mut_refs().1 &gt; } &gt; &gt; /// Sets the value of the entry, and returns the entry's old value. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt;@@ -1947,17 +1974,17 @@ impl&lt;'a, K, V&gt; OccupiedEntry&lt;'a, K, V&gt; { &gt; /// map.entry("poneyland").or_insert(12); &gt; /// &gt; /// if let Entry::Occupied(mut o) = map.entry("poneyland") { &gt; /// assert_eq!(o.insert(15), 12); &gt; /// } &gt; /// &gt; /// assert_eq!(map["poneyland"], 15); &gt; /// ``` &gt;- pub fn insert(&amp;mut self, mut value: V) -&gt; V { &gt;+ pub fn insert(&amp;mut self, mut value: V) -&gt; V { &gt; let old_value = self.get_mut(); &gt; mem::swap(&amp;mut value, old_value); &gt; value &gt; } &gt; &gt; /// Takes the value out of the entry, and returns it. &gt; /// &gt; /// # Examples &gt;@@ -1970,17 +1997,17 @@ impl&lt;'a, K, V&gt; OccupiedEntry&lt;'a, K, V&gt; { &gt; /// map.entry("poneyland").or_insert(12); &gt; /// &gt; /// if let Entry::Occupied(o) = map.entry("poneyland") { &gt; /// assert_eq!(o.remove(), 12); &gt; /// } &gt; /// &gt; /// assert_eq!(map.contains_key("poneyland"), false); &gt; /// ``` &gt;- pub fn remove(self) -&gt; V { &gt;+ pub fn remove(self) -&gt; V { &gt; pop_internal(self.elem).1 &gt; } &gt; &gt; /// Returns a key that was used for search. &gt; /// &gt; /// The key was retained for further use. &gt; fn take_key(&amp;mut self) -&gt; Option&lt;K&gt; { &gt; self.key.take() &gt;@@ -1994,17 +2021,17 @@ impl&lt;'a, K: 'a, V: 'a&gt; VacantEntry&lt;'a, K, V&gt; { &gt; /// # Examples &gt; /// &gt; /// ``` &gt; /// use std::collections::HashMap; &gt; /// &gt; /// let mut map: HashMap&lt;&amp;str, u32&gt; = HashMap::new(); &gt; /// assert_eq!(map.entry("poneyland").key(), &amp;"poneyland"); &gt; /// ``` &gt;- pub fn key(&amp;self) -&gt; &amp;K { &gt;+ pub fn key(&amp;self) -&gt; &amp;K { &gt; &amp;self.key &gt; } &gt; &gt; /// Take ownership of the key. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt;@@ -2012,17 +2039,17 @@ impl&lt;'a, K: 'a, V: 'a&gt; VacantEntry&lt;'a, K, V&gt; { &gt; /// use std::collections::hash_map::Entry; &gt; /// &gt; /// let mut map: HashMap&lt;&amp;str, u32&gt; = HashMap::new(); &gt; /// &gt; /// if let Entry::Vacant(v) = map.entry("poneyland") { &gt; /// v.into_key(); &gt; /// } &gt; /// ``` &gt;- pub fn into_key(self) -&gt; K { &gt;+ pub fn into_key(self) -&gt; K { &gt; self.key &gt; } &gt; &gt; /// Sets the value of the entry with the VacantEntry's key, &gt; /// and returns a mutable reference to it. &gt; /// &gt; /// # Examples &gt; /// &gt;@@ -2032,49 +2059,51 @@ impl&lt;'a, K: 'a, V: 'a&gt; VacantEntry&lt;'a, K, V&gt; { &gt; /// &gt; /// let mut map: HashMap&lt;&amp;str, u32&gt; = HashMap::new(); &gt; /// &gt; /// if let Entry::Vacant(o) = map.entry("poneyland") { &gt; /// o.insert(37); &gt; /// } &gt; /// assert_eq!(map["poneyland"], 37); &gt; /// ``` &gt;- pub fn insert(self, value: V) -&gt; &amp;'a mut V { &gt;+ pub fn insert(self, value: V) -&gt; &amp;'a mut V { &gt; let b = match self.elem { &gt; NeqElem(mut bucket, disp) =&gt; { &gt; if disp &gt;= DISPLACEMENT_THRESHOLD { &gt; bucket.table_mut().set_tag(true); &gt; } &gt; robin_hood(bucket, disp, self.hash, self.key, value) &gt;- }, &gt;+ } &gt; NoElem(mut bucket, disp) =&gt; { &gt; if disp &gt;= DISPLACEMENT_THRESHOLD { &gt; bucket.table_mut().set_tag(true); &gt; } &gt; bucket.put(self.hash, self.key, value) &gt;- }, &gt;+ } &gt; }; &gt; b.into_mut_refs().1 &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; FromIterator&lt;(K, V)&gt; for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher + Default &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher + Default, &gt; { &gt; fn from_iter&lt;T: IntoIterator&lt;Item = (K, V)&gt;&gt;(iter: T) -&gt; HashMap&lt;K, V, S&gt; { &gt; let mut map = HashMap::with_hasher(Default::default()); &gt; map.extend(iter); &gt; map &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; Extend&lt;(K, V)&gt; for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn extend&lt;T: IntoIterator&lt;Item = (K, V)&gt;&gt;(&amp;mut self, iter: T) { &gt; // Keys may be already present or show multiple times in the iterator. &gt; // Reserve the entire hint lower bound if the map is empty. &gt; // Otherwise reserve half the hint (rounded up), so the map &gt; // will only resize twice in the worst case. &gt; let iter = iter.into_iter(); &gt; let reserve = if self.is_empty() { &gt;@@ -2085,46 +2114,51 @@ impl&lt;K, V, S&gt; Extend&lt;(K, V)&gt; for HashMap&lt;K, V, S&gt; &gt; self.reserve(reserve); &gt; for (k, v) in iter { &gt; self.insert(k, v); &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V, S&gt; Extend&lt;(&amp;'a K, &amp;'a V)&gt; for HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash + Copy, &gt;- V: Copy, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash + Copy, &gt;+ V: Copy, &gt;+ S: BuildHasher, &gt; { &gt; fn extend&lt;T: IntoIterator&lt;Item = (&amp;'a K, &amp;'a V)&gt;&gt;(&amp;mut self, iter: T) { &gt; self.extend(iter.into_iter().map(|(&amp;key, &amp;value)| (key, value))); &gt; } &gt; } &gt; &gt; // FORK NOTE: These can be reused &gt; pub use std::collections::hash_map::{DefaultHasher, RandomState}; &gt; &gt;- &gt; impl&lt;K, S, Q: ?Sized&gt; super::Recover&lt;Q&gt; for HashMap&lt;K, (), S&gt; &gt;- where K: Eq + Hash + Borrow&lt;Q&gt;, &gt;- S: BuildHasher, &gt;- Q: Eq + Hash &gt;+where &gt;+ K: Eq + Hash + Borrow&lt;Q&gt;, &gt;+ S: BuildHasher, &gt;+ Q: Eq + Hash, &gt; { &gt; type Key = K; &gt; &gt; fn get(&amp;self, key: &amp;Q) -&gt; Option&lt;&amp;K&gt; { &gt;- self.search(key).into_occupied_bucket().map(|bucket| bucket.into_refs().0) &gt;+ self.search(key) &gt;+ .into_occupied_bucket() &gt;+ .map(|bucket| bucket.into_refs().0) &gt; } &gt; &gt; fn take(&amp;mut self, key: &amp;Q) -&gt; Option&lt;K&gt; { &gt; if self.table.size() == 0 { &gt; return None; &gt; } &gt; &gt;- self.search_mut(key).into_occupied_bucket().map(|bucket| pop_internal(bucket).0) &gt;+ self.search_mut(key) &gt;+ .into_occupied_bucket() &gt;+ .map(|bucket| pop_internal(bucket).0) &gt; } &gt; &gt; fn replace(&amp;mut self, key: K) -&gt; Option&lt;K&gt; { &gt; self.reserve(1); &gt; &gt; match self.entry(key) { &gt; Occupied(mut occupied) =&gt; { &gt; let key = occupied.take_key().unwrap(); &gt;@@ -2165,30 +2199,31 @@ fn assert_covariance() { &gt; v &gt; } &gt; fn values_key&lt;'a, 'new&gt;(v: Values&lt;'a, &amp;'static str, u8&gt;) -&gt; Values&lt;'a, &amp;'new str, u8&gt; { &gt; v &gt; } &gt; fn values_val&lt;'a, 'new&gt;(v: Values&lt;'a, u8, &amp;'static str&gt;) -&gt; Values&lt;'a, u8, &amp;'new str&gt; { &gt; v &gt; } &gt;- fn drain&lt;'new&gt;(d: Drain&lt;'static, &amp;'static str, &amp;'static str&gt;) &gt;- -&gt; Drain&lt;'new, &amp;'new str, &amp;'new str&gt; { &gt;+ fn drain&lt;'new&gt;( &gt;+ d: Drain&lt;'static, &amp;'static str, &amp;'static str&gt;, &gt;+ ) -&gt; Drain&lt;'new, &amp;'new str, &amp;'new str&gt; { &gt; d &gt; } &gt; } &gt; &gt; #[cfg(test)] &gt; mod test_map { &gt; extern crate rand; &gt;- use super::HashMap; &gt;+ use self::rand::{thread_rng, Rng}; &gt; use super::Entry::{Occupied, Vacant}; &gt;+ use super::HashMap; &gt; use super::RandomState; &gt; use cell::RefCell; &gt;- use self::rand::{thread_rng, Rng}; &gt; &gt; #[test] &gt; fn test_zero_capacities() { &gt; type HM = HashMap&lt;i32, i32&gt;; &gt; &gt; let m = HM::new(); &gt; assert_eq!(m.capacity(), 0); &gt; &gt;@@ -2314,29 +2349,29 @@ mod test_map { &gt; for i in 0..50 { &gt; let k = Dropable::new(i); &gt; let v = m.remove(&amp;k); &gt; &gt; assert!(v.is_some()); &gt; &gt; DROP_VECTOR.with(|v| { &gt; assert_eq!(v.borrow()[i], 1); &gt;- assert_eq!(v.borrow()[i+100], 1); &gt;+ assert_eq!(v.borrow()[i + 100], 1); &gt; }); &gt; } &gt; &gt; DROP_VECTOR.with(|v| { &gt; for i in 0..50 { &gt; assert_eq!(v.borrow()[i], 0); &gt;- assert_eq!(v.borrow()[i+100], 0); &gt;+ assert_eq!(v.borrow()[i + 100], 0); &gt; } &gt; &gt; for i in 50..100 { &gt; assert_eq!(v.borrow()[i], 1); &gt;- assert_eq!(v.borrow()[i+100], 1); &gt;+ assert_eq!(v.borrow()[i + 100], 1); &gt; } &gt; }); &gt; } &gt; &gt; DROP_VECTOR.with(|v| { &gt; for i in 0..200 { &gt; assert_eq!(v.borrow()[i], 0); &gt; } &gt;@@ -2383,23 +2418,19 @@ mod test_map { &gt; for i in 0..200 { &gt; assert_eq!(v.borrow()[i], 1); &gt; } &gt; }); &gt; &gt; for _ in half.by_ref() {} &gt; &gt; DROP_VECTOR.with(|v| { &gt;- let nk = (0..100) &gt;- .filter(|&amp;i| v.borrow()[i] == 1) &gt;- .count(); &gt;+ let nk = (0..100).filter(|&amp;i| v.borrow()[i] == 1).count(); &gt; &gt;- let nv = (0..100) &gt;- .filter(|&amp;i| v.borrow()[i + 100] == 1) &gt;- .count(); &gt;+ let nv = (0..100).filter(|&amp;i| v.borrow()[i + 100] == 1).count(); &gt; &gt; assert_eq!(nk, 50); &gt; assert_eq!(nv, 50); &gt; }); &gt; }; &gt; &gt; DROP_VECTOR.with(|v| { &gt; for i in 0..200 { &gt;@@ -2569,17 +2600,17 @@ mod test_map { &gt; assert_eq!(m.remove(&amp;1), Some(2)); &gt; assert_eq!(m.remove(&amp;1), None); &gt; } &gt; &gt; #[test] &gt; fn test_iterate() { &gt; let mut m = HashMap::with_capacity(4); &gt; for i in 0..32 { &gt;- assert!(m.insert(i, i*2).is_none()); &gt;+ assert!(m.insert(i, i * 2).is_none()); &gt; } &gt; assert_eq!(m.len(), 32); &gt; &gt; let mut observed: u32 = 0; &gt; &gt; for (k, v) in &amp;m { &gt; assert_eq!(*v, *k * 2); &gt; observed |= 1 &lt;&lt; *k; &gt;@@ -2657,18 +2688,17 @@ mod test_map { &gt; let mut map = HashMap::new(); &gt; let empty: HashMap&lt;i32, i32&gt; = HashMap::new(); &gt; &gt; map.insert(1, 2); &gt; map.insert(3, 4); &gt; &gt; let map_str = format!("{:?}", map); &gt; &gt;- assert!(map_str == "{1: 2, 3: 4}" || &gt;- map_str == "{3: 4, 1: 2}"); &gt;+ assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); &gt; assert_eq!(format!("{:?}", empty), "{}"); &gt; } &gt; &gt; #[test] &gt; fn test_expand() { &gt; let mut m = HashMap::new(); &gt; &gt; assert_eq!(m.len(), 0); &gt;@@ -2876,17 +2906,16 @@ mod test_map { &gt; Occupied(mut view) =&gt; { &gt; assert_eq!(view.get(), &amp;10); &gt; assert_eq!(view.insert(100), 10); &gt; } &gt; } &gt; assert_eq!(map.get(&amp;1).unwrap(), &amp;100); &gt; assert_eq!(map.len(), 6); &gt; &gt;- &gt; // Existing key (update) &gt; match map.entry(2) { &gt; Vacant(_) =&gt; unreachable!(), &gt; Occupied(mut view) =&gt; { &gt; let v = view.get_mut(); &gt; let new_v = (*v) * 10; &gt; *v = new_v; &gt; } &gt;@@ -2899,36 +2928,34 @@ mod test_map { &gt; Vacant(_) =&gt; unreachable!(), &gt; Occupied(view) =&gt; { &gt; assert_eq!(view.remove(), 30); &gt; } &gt; } &gt; assert_eq!(map.get(&amp;3), None); &gt; assert_eq!(map.len(), 5); &gt; &gt;- &gt; // Inexistent key (insert) &gt; match map.entry(10) { &gt; Occupied(_) =&gt; unreachable!(), &gt; Vacant(view) =&gt; { &gt; assert_eq!(*view.insert(1000), 1000); &gt; } &gt; } &gt; assert_eq!(map.get(&amp;10).unwrap(), &amp;1000); &gt; assert_eq!(map.len(), 6); &gt; } &gt; &gt; #[test] &gt; fn test_entry_take_doesnt_corrupt() { &gt; #![allow(deprecated)] //rand &gt;- // Test for #19292 &gt;+ // Test for #19292 &gt; fn check(m: &amp;HashMap&lt;isize, ()&gt;) { &gt; for k in m.keys() { &gt;- assert!(m.contains_key(k), &gt;- "{} is in keys() but not in the map?", k); &gt;+ assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); &gt; } &gt; } &gt; &gt; let mut m = HashMap::new(); &gt; let mut rng = thread_rng(); &gt; &gt; // Populate the map with some items. &gt; for _ in 0..50 { &gt;@@ -3024,17 +3051,17 @@ mod test_map { &gt; } &gt; } &gt; assert_eq!(a.len(), 1); &gt; assert_eq!(a[key], value); &gt; } &gt; &gt; #[test] &gt; fn test_retain() { &gt;- let mut map: HashMap&lt;isize, isize&gt; = (0..100).map(|x|(x, x*10)).collect(); &gt;+ let mut map: HashMap&lt;isize, isize&gt; = (0..100).map(|x| (x, x * 10)).collect(); &gt; &gt; map.retain(|&amp;k, _| k % 2 == 0); &gt; assert_eq!(map.len(), 50); &gt; assert_eq!(map[&amp;2], 20); &gt; assert_eq!(map[&amp;4], 40); &gt; assert_eq!(map[&amp;6], 60); &gt; } &gt; &gt;diff --git a/servo/components/hashglobe/src/hash_set.rs b/servo/components/hashglobe/src/hash_set.rs &gt;index 2139b58a6012..694e01c46eb8 100644 &gt;--- a/servo/components/hashglobe/src/hash_set.rs &gt;+++ b/servo/components/hashglobe/src/hash_set.rs &gt;@@ -5,22 +5,22 @@ &gt; // Licensed under the Apache License, Version 2.0 &lt;LICENSE-APACHE or &gt; // http://www.apache.org/licenses/LICENSE-2.0&gt; or the MIT license &gt; // &lt;LICENSE-MIT or http://opensource.org/licenses/MIT&gt;, at your &gt; // option. This file may not be copied, modified, or distributed &gt; // except according to those terms. &gt; &gt; use std::borrow::Borrow; &gt; use std::fmt; &gt;-use std::hash::{Hash, BuildHasher}; &gt;+use std::hash::{BuildHasher, Hash}; &gt; use std::iter::{Chain, FromIterator}; &gt;-use std::ops::{BitOr, BitAnd, BitXor, Sub}; &gt;+use std::ops::{BitAnd, BitOr, BitXor, Sub}; &gt; &gt;-use super::Recover; &gt; use super::hash_map::{self, HashMap, Keys, RandomState}; &gt;+use super::Recover; &gt; &gt; // Future Optimization (FIXME!) &gt; // ============================= &gt; // &gt; // Iteration over zero sized values is a noop. There is no need &gt; // for `bucket.val` in the case of HashSet. I suppose we would need HKT &gt; // to get rid of it properly. &gt; &gt;@@ -117,18 +117,19 @@ use super::hash_map::{self, HashMap, Keys, RandomState}; &gt; /// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html &gt; /// [`RefCell`]: ../../std/cell/struct.RefCell.html &gt; #[derive(Clone)] &gt; pub struct HashSet&lt;T, S = RandomState&gt; { &gt; map: HashMap&lt;T, (), S&gt;, &gt; } &gt; &gt; impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; /// Creates a new empty hash set which will use the given hasher to hash &gt; /// keys. &gt; /// &gt; /// The hash set is also created with the default initial capacity. &gt; /// &gt; /// Warning: `hasher` is normally randomly generated, and &gt; /// is designed to allow `HashSet`s to be resistant to attacks that &gt;@@ -142,17 +143,19 @@ impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt; /// use std::collections::hash_map::RandomState; &gt; /// &gt; /// let s = RandomState::new(); &gt; /// let mut set = HashSet::with_hasher(s); &gt; /// set.insert(2); &gt; /// ``` &gt; #[inline] &gt; pub fn with_hasher(hasher: S) -&gt; HashSet&lt;T, S&gt; { &gt;- HashSet { map: HashMap::with_hasher(hasher) } &gt;+ HashSet { &gt;+ map: HashMap::with_hasher(hasher), &gt;+ } &gt; } &gt; &gt; /// Creates an empty `HashSet` with with the specified capacity, using &gt; /// `hasher` to hash the keys. &gt; /// &gt; /// The hash set will be able to hold at least `capacity` elements without &gt; /// reallocating. If `capacity` is 0, the hash set will not allocate. &gt; /// &gt;@@ -168,17 +171,19 @@ impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt; /// use std::collections::hash_map::RandomState; &gt; /// &gt; /// let s = RandomState::new(); &gt; /// let mut set = HashSet::with_capacity_and_hasher(10, s); &gt; /// set.insert(1); &gt; /// ``` &gt; #[inline] &gt; pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -&gt; HashSet&lt;T, S&gt; { &gt;- HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } &gt;+ HashSet { &gt;+ map: HashMap::with_capacity_and_hasher(capacity, hasher), &gt;+ } &gt; } &gt; &gt; /// Returns a reference to the set's [`BuildHasher`]. &gt; /// &gt; /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html &gt; /// &gt; /// # Examples &gt; /// &gt;@@ -260,17 +265,19 @@ impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt; /// set.insert("b"); &gt; /// &gt; /// // Will print in an arbitrary order. &gt; /// for x in set.iter() { &gt; /// println!("{}", x); &gt; /// } &gt; /// ``` &gt; pub fn iter(&amp;self) -&gt; Iter&lt;T&gt; { &gt;- Iter { iter: self.map.keys() } &gt;+ Iter { &gt;+ iter: self.map.keys(), &gt;+ } &gt; } &gt; &gt; /// Visits the values representing the difference, &gt; /// i.e. the values that are in `self` but not in `other`. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt;@@ -314,20 +321,23 @@ impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt; /// } &gt; /// &gt; /// let diff1: HashSet&lt;_&gt; = a.symmetric_difference(&amp;b).collect(); &gt; /// let diff2: HashSet&lt;_&gt; = b.symmetric_difference(&amp;a).collect(); &gt; /// &gt; /// assert_eq!(diff1, diff2); &gt; /// assert_eq!(diff1, [1, 4].iter().collect()); &gt; /// ``` &gt;- pub fn symmetric_difference&lt;'a&gt;(&amp;'a self, &gt;- other: &amp;'a HashSet&lt;T, S&gt;) &gt;- -&gt; SymmetricDifference&lt;'a, T, S&gt; { &gt;- SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) } &gt;+ pub fn symmetric_difference&lt;'a&gt;( &gt;+ &amp;'a self, &gt;+ other: &amp;'a HashSet&lt;T, S&gt;, &gt;+ ) -&gt; SymmetricDifference&lt;'a, T, S&gt; { &gt;+ SymmetricDifference { &gt;+ iter: self.difference(other).chain(other.difference(self)), &gt;+ } &gt; } &gt; &gt; /// Visits the values representing the intersection, &gt; /// i.e. the values that are both in `self` and `other`. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt;@@ -364,17 +374,19 @@ impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt; /// for x in a.union(&amp;b) { &gt; /// println!("{}", x); &gt; /// } &gt; /// &gt; /// let union: HashSet&lt;_&gt; = a.union(&amp;b).collect(); &gt; /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); &gt; /// ``` &gt; pub fn union&lt;'a&gt;(&amp;'a self, other: &amp;'a HashSet&lt;T, S&gt;) -&gt; Union&lt;'a, T, S&gt; { &gt;- Union { iter: self.iter().chain(other.difference(self)) } &gt;+ Union { &gt;+ iter: self.iter().chain(other.difference(self)), &gt;+ } &gt; } &gt; &gt; /// Returns the number of elements in the set. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt; /// use std::collections::HashSet; &gt;@@ -418,32 +430,37 @@ impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt; /// for i in set.drain() { &gt; /// println!("{}", i); &gt; /// } &gt; /// &gt; /// assert!(set.is_empty()); &gt; /// ``` &gt; #[inline] &gt; pub fn drain(&amp;mut self) -&gt; Drain&lt;T&gt; { &gt;- Drain { iter: self.map.drain() } &gt;+ Drain { &gt;+ iter: self.map.drain(), &gt;+ } &gt; } &gt; &gt; /// Clears the set, removing all values. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt; /// use std::collections::HashSet; &gt; /// &gt; /// let mut v = HashSet::new(); &gt; /// v.insert(1); &gt; /// v.clear(); &gt; /// assert!(v.is_empty()); &gt; /// ``` &gt;- pub fn clear(&amp;mut self) where T: 'static { &gt;+ pub fn clear(&amp;mut self) &gt;+ where &gt;+ T: 'static, &gt;+ { &gt; self.map.clear() &gt; } &gt; &gt; /// Returns `true` if the set contains a value. &gt; /// &gt; /// The value may be any borrowed form of the set's value type, but &gt; /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for &gt; /// the value type. &gt;@@ -456,33 +473,35 @@ impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt; /// let set: HashSet&lt;_&gt; = [1, 2, 3].iter().cloned().collect(); &gt; /// assert_eq!(set.contains(&amp;1), true); &gt; /// assert_eq!(set.contains(&amp;4), false); &gt; /// ``` &gt; /// &gt; /// [`Eq`]: ../../std/cmp/trait.Eq.html &gt; /// [`Hash`]: ../../std/hash/trait.Hash.html &gt; pub fn contains&lt;Q: ?Sized&gt;(&amp;self, value: &amp;Q) -&gt; bool &gt;- where T: Borrow&lt;Q&gt;, &gt;- Q: Hash + Eq &gt;+ where &gt;+ T: Borrow&lt;Q&gt;, &gt;+ Q: Hash + Eq, &gt; { &gt; self.map.contains_key(value) &gt; } &gt; &gt; /// Returns a reference to the value in the set, if any, that is equal to the given value. &gt; /// &gt; /// The value may be any borrowed form of the set's value type, but &gt; /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for &gt; /// the value type. &gt; /// &gt; /// [`Eq`]: ../../std/cmp/trait.Eq.html &gt; /// [`Hash`]: ../../std/hash/trait.Hash.html &gt; pub fn get&lt;Q: ?Sized&gt;(&amp;self, value: &amp;Q) -&gt; Option&lt;&amp;T&gt; &gt;- where T: Borrow&lt;Q&gt;, &gt;- Q: Hash + Eq &gt;+ where &gt;+ T: Borrow&lt;Q&gt;, &gt;+ Q: Hash + Eq, &gt; { &gt; Recover::get(&amp;self.map, value) &gt; } &gt; &gt; /// Returns `true` if `self` has no elements in common with `other`. &gt; /// This is equivalent to checking for an empty intersection. &gt; /// &gt; /// # Examples &gt;@@ -593,33 +612,35 @@ impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt; /// set.insert(2); &gt; /// assert_eq!(set.remove(&amp;2), true); &gt; /// assert_eq!(set.remove(&amp;2), false); &gt; /// ``` &gt; /// &gt; /// [`Eq`]: ../../std/cmp/trait.Eq.html &gt; /// [`Hash`]: ../../std/hash/trait.Hash.html &gt; pub fn remove&lt;Q: ?Sized&gt;(&amp;mut self, value: &amp;Q) -&gt; bool &gt;- where T: Borrow&lt;Q&gt;, &gt;- Q: Hash + Eq &gt;+ where &gt;+ T: Borrow&lt;Q&gt;, &gt;+ Q: Hash + Eq, &gt; { &gt; self.map.remove(value).is_some() &gt; } &gt; &gt; /// Removes and returns the value in the set, if any, that is equal to the given one. &gt; /// &gt; /// The value may be any borrowed form of the set's value type, but &gt; /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for &gt; /// the value type. &gt; /// &gt; /// [`Eq`]: ../../std/cmp/trait.Eq.html &gt; /// [`Hash`]: ../../std/hash/trait.Hash.html &gt; pub fn take&lt;Q: ?Sized&gt;(&amp;mut self, value: &amp;Q) -&gt; Option&lt;T&gt; &gt;- where T: Borrow&lt;Q&gt;, &gt;- Q: Hash + Eq &gt;+ where &gt;+ T: Borrow&lt;Q&gt;, &gt;+ Q: Hash + Eq, &gt; { &gt; Recover::take(&amp;mut self.map, value) &gt; } &gt; &gt; /// Retains only the elements specified by the predicate. &gt; /// &gt; /// In other words, remove all elements `e` such that `f(&amp;e)` returns `false`. &gt; /// &gt;@@ -629,92 +650,103 @@ impl&lt;T, S&gt; HashSet&lt;T, S&gt; &gt; /// use std::collections::HashSet; &gt; /// &gt; /// let xs = [1,2,3,4,5,6]; &gt; /// let mut set: HashSet&lt;isize&gt; = xs.iter().cloned().collect(); &gt; /// set.retain(|&amp;k| k % 2 == 0); &gt; /// assert_eq!(set.len(), 3); &gt; /// ``` &gt; pub fn retain&lt;F&gt;(&amp;mut self, mut f: F) &gt;- where F: FnMut(&amp;T) -&gt; bool &gt;+ where &gt;+ F: FnMut(&amp;T) -&gt; bool, &gt; { &gt; self.map.retain(|k, _| f(k)); &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; PartialEq for HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn eq(&amp;self, other: &amp;HashSet&lt;T, S&gt;) -&gt; bool { &gt; if self.len() != other.len() { &gt; return false; &gt; } &gt; &gt; self.iter().all(|key| other.contains(key)) &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; Eq for HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; } &gt; &gt; impl&lt;T, S&gt; fmt::Debug for HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash + fmt::Debug, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash + fmt::Debug, &gt;+ S: BuildHasher, &gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; f.debug_set().entries(self.iter()).finish() &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; FromIterator&lt;T&gt; for HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher + Default &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher + Default, &gt; { &gt; fn from_iter&lt;I: IntoIterator&lt;Item = T&gt;&gt;(iter: I) -&gt; HashSet&lt;T, S&gt; { &gt; let mut set = HashSet::with_hasher(Default::default()); &gt; set.extend(iter); &gt; set &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; Extend&lt;T&gt; for HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn extend&lt;I: IntoIterator&lt;Item = T&gt;&gt;(&amp;mut self, iter: I) { &gt; self.map.extend(iter.into_iter().map(|k| (k, ()))); &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; Extend&lt;&amp;'a T&gt; for HashSet&lt;T, S&gt; &gt;- where T: 'a + Eq + Hash + Copy, &gt;- S: BuildHasher &gt;+where &gt;+ T: 'a + Eq + Hash + Copy, &gt;+ S: BuildHasher, &gt; { &gt; fn extend&lt;I: IntoIterator&lt;Item = &amp;'a T&gt;&gt;(&amp;mut self, iter: I) { &gt; self.extend(iter.into_iter().cloned()); &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; Default for HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher + Default &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher + Default, &gt; { &gt; /// Creates an empty `HashSet&lt;T, S&gt;` with the `Default` value for the hasher. &gt; fn default() -&gt; HashSet&lt;T, S&gt; { &gt;- HashSet { map: HashMap::default() } &gt;+ HashSet { &gt;+ map: HashMap::default(), &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'a, 'b, T, S&gt; BitOr&lt;&amp;'b HashSet&lt;T, S&gt;&gt; for &amp;'a HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash + Clone, &gt;- S: BuildHasher + Default &gt;+where &gt;+ T: Eq + Hash + Clone, &gt;+ S: BuildHasher + Default, &gt; { &gt; type Output = HashSet&lt;T, S&gt;; &gt; &gt; /// Returns the union of `self` and `rhs` as a new `HashSet&lt;T, S&gt;`. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt;@@ -734,18 +766,19 @@ impl&lt;'a, 'b, T, S&gt; BitOr&lt;&amp;'b HashSet&lt;T, S&gt;&gt; for &amp;'a HashSet&lt;T, S&gt; &gt; /// assert_eq!(i, expected.len()); &gt; /// ``` &gt; fn bitor(self, rhs: &amp;HashSet&lt;T, S&gt;) -&gt; HashSet&lt;T, S&gt; { &gt; self.union(rhs).cloned().collect() &gt; } &gt; } &gt; &gt; impl&lt;'a, 'b, T, S&gt; BitAnd&lt;&amp;'b HashSet&lt;T, S&gt;&gt; for &amp;'a HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash + Clone, &gt;- S: BuildHasher + Default &gt;+where &gt;+ T: Eq + Hash + Clone, &gt;+ S: BuildHasher + Default, &gt; { &gt; type Output = HashSet&lt;T, S&gt;; &gt; &gt; /// Returns the intersection of `self` and `rhs` as a new `HashSet&lt;T, S&gt;`. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt;@@ -765,18 +798,19 @@ impl&lt;'a, 'b, T, S&gt; BitAnd&lt;&amp;'b HashSet&lt;T, S&gt;&gt; for &amp;'a HashSet&lt;T, S&gt; &gt; /// assert_eq!(i, expected.len()); &gt; /// ``` &gt; fn bitand(self, rhs: &amp;HashSet&lt;T, S&gt;) -&gt; HashSet&lt;T, S&gt; { &gt; self.intersection(rhs).cloned().collect() &gt; } &gt; } &gt; &gt; impl&lt;'a, 'b, T, S&gt; BitXor&lt;&amp;'b HashSet&lt;T, S&gt;&gt; for &amp;'a HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash + Clone, &gt;- S: BuildHasher + Default &gt;+where &gt;+ T: Eq + Hash + Clone, &gt;+ S: BuildHasher + Default, &gt; { &gt; type Output = HashSet&lt;T, S&gt;; &gt; &gt; /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet&lt;T, S&gt;`. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt;@@ -796,18 +830,19 @@ impl&lt;'a, 'b, T, S&gt; BitXor&lt;&amp;'b HashSet&lt;T, S&gt;&gt; for &amp;'a HashSet&lt;T, S&gt; &gt; /// assert_eq!(i, expected.len()); &gt; /// ``` &gt; fn bitxor(self, rhs: &amp;HashSet&lt;T, S&gt;) -&gt; HashSet&lt;T, S&gt; { &gt; self.symmetric_difference(rhs).cloned().collect() &gt; } &gt; } &gt; &gt; impl&lt;'a, 'b, T, S&gt; Sub&lt;&amp;'b HashSet&lt;T, S&gt;&gt; for &amp;'a HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash + Clone, &gt;- S: BuildHasher + Default &gt;+where &gt;+ T: Eq + Hash + Clone, &gt;+ S: BuildHasher + Default, &gt; { &gt; type Output = HashSet&lt;T, S&gt;; &gt; &gt; /// Returns the difference of `self` and `rhs` as a new `HashSet&lt;T, S&gt;`. &gt; /// &gt; /// # Examples &gt; /// &gt; /// ``` &gt;@@ -910,30 +945,32 @@ pub struct SymmetricDifference&lt;'a, T: 'a, S: 'a&gt; { &gt; /// &gt; /// [`HashSet`]: struct.HashSet.html &gt; /// [`union`]: struct.HashSet.html#method.union &gt; pub struct Union&lt;'a, T: 'a, S: 'a&gt; { &gt; iter: Chain&lt;Iter&lt;'a, T&gt;, Difference&lt;'a, T, S&gt;&gt;, &gt; } &gt; &gt; impl&lt;'a, T, S&gt; IntoIterator for &amp;'a HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = &amp;'a T; &gt; type IntoIter = Iter&lt;'a, T&gt;; &gt; &gt; fn into_iter(self) -&gt; Iter&lt;'a, T&gt; { &gt; self.iter() &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; IntoIterator for HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = T; &gt; type IntoIter = IntoIter&lt;T&gt;; &gt; &gt; /// Creates a consuming iterator, that is, one that moves each value out &gt; /// of the set in arbitrary order. The set cannot be used after calling &gt; /// this. &gt; /// &gt;@@ -949,23 +986,27 @@ impl&lt;T, S&gt; IntoIterator for HashSet&lt;T, S&gt; &gt; /// let v: Vec&lt;String&gt; = set.into_iter().collect(); &gt; /// &gt; /// // Will print in an arbitrary order. &gt; /// for x in &amp;v { &gt; /// println!("{}", x); &gt; /// } &gt; /// ``` &gt; fn into_iter(self) -&gt; IntoIter&lt;T&gt; { &gt;- IntoIter { iter: self.map.into_iter() } &gt;+ IntoIter { &gt;+ iter: self.map.into_iter(), &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'a, K&gt; Clone for Iter&lt;'a, K&gt; { &gt; fn clone(&amp;self) -&gt; Iter&lt;'a, K&gt; { &gt;- Iter { iter: self.iter.clone() } &gt;+ Iter { &gt;+ iter: self.iter.clone(), &gt;+ } &gt; } &gt; } &gt; impl&lt;'a, K&gt; Iterator for Iter&lt;'a, K&gt; { &gt; type Item = &amp;'a K; &gt; &gt; fn next(&amp;mut self) -&gt; Option&lt;&amp;'a K&gt; { &gt; self.iter.next() &gt; } &gt;@@ -998,20 +1039,17 @@ impl&lt;K&gt; Iterator for IntoIter&lt;K&gt; { &gt; impl&lt;K&gt; ExactSizeIterator for IntoIter&lt;K&gt; { &gt; fn len(&amp;self) -&gt; usize { &gt; self.iter.len() &gt; } &gt; } &gt; &gt; impl&lt;K: fmt::Debug&gt; fmt::Debug for IntoIter&lt;K&gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- let entries_iter = self.iter &gt;- .inner &gt;- .iter() &gt;- .map(|(k, _)| k); &gt;+ let entries_iter = self.iter.inner.iter().map(|(k, _)| k); &gt; f.debug_list().entries(entries_iter).finish() &gt; } &gt; } &gt; &gt; impl&lt;'a, K&gt; Iterator for Drain&lt;'a, K&gt; { &gt; type Item = K; &gt; &gt; fn next(&amp;mut self) -&gt; Option&lt;K&gt; { &gt;@@ -1024,33 +1062,34 @@ impl&lt;'a, K&gt; Iterator for Drain&lt;'a, K&gt; { &gt; impl&lt;'a, K&gt; ExactSizeIterator for Drain&lt;'a, K&gt; { &gt; fn len(&amp;self) -&gt; usize { &gt; self.iter.len() &gt; } &gt; } &gt; &gt; impl&lt;'a, K: fmt::Debug&gt; fmt::Debug for Drain&lt;'a, K&gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- let entries_iter = self.iter &gt;- .inner &gt;- .iter() &gt;- .map(|(k, _)| k); &gt;+ let entries_iter = self.iter.inner.iter().map(|(k, _)| k); &gt; f.debug_list().entries(entries_iter).finish() &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; Clone for Intersection&lt;'a, T, S&gt; { &gt; fn clone(&amp;self) -&gt; Intersection&lt;'a, T, S&gt; { &gt;- Intersection { iter: self.iter.clone(), ..*self } &gt;+ Intersection { &gt;+ iter: self.iter.clone(), &gt;+ ..*self &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; Iterator for Intersection&lt;'a, T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = &amp;'a T; &gt; &gt; fn next(&amp;mut self) -&gt; Option&lt;&amp;'a T&gt; { &gt; loop { &gt; let elt = self.iter.next()?; &gt; if self.other.contains(elt) { &gt; return Some(elt); &gt;@@ -1060,33 +1099,38 @@ impl&lt;'a, T, S&gt; Iterator for Intersection&lt;'a, T, S&gt; &gt; &gt; fn size_hint(&amp;self) -&gt; (usize, Option&lt;usize&gt;) { &gt; let (_, upper) = self.iter.size_hint(); &gt; (0, upper) &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; fmt::Debug for Intersection&lt;'a, T, S&gt; &gt;- where T: fmt::Debug + Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: fmt::Debug + Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; f.debug_list().entries(self.clone()).finish() &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; Clone for Difference&lt;'a, T, S&gt; { &gt; fn clone(&amp;self) -&gt; Difference&lt;'a, T, S&gt; { &gt;- Difference { iter: self.iter.clone(), ..*self } &gt;+ Difference { &gt;+ iter: self.iter.clone(), &gt;+ ..*self &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; Iterator for Difference&lt;'a, T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = &amp;'a T; &gt; &gt; fn next(&amp;mut self) -&gt; Option&lt;&amp;'a T&gt; { &gt; loop { &gt; let elt = self.iter.next()?; &gt; if !self.other.contains(elt) { &gt; return Some(elt); &gt;@@ -1096,71 +1140,80 @@ impl&lt;'a, T, S&gt; Iterator for Difference&lt;'a, T, S&gt; &gt; &gt; fn size_hint(&amp;self) -&gt; (usize, Option&lt;usize&gt;) { &gt; let (_, upper) = self.iter.size_hint(); &gt; (0, upper) &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; fmt::Debug for Difference&lt;'a, T, S&gt; &gt;- where T: fmt::Debug + Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: fmt::Debug + Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; f.debug_list().entries(self.clone()).finish() &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; Clone for SymmetricDifference&lt;'a, T, S&gt; { &gt; fn clone(&amp;self) -&gt; SymmetricDifference&lt;'a, T, S&gt; { &gt;- SymmetricDifference { iter: self.iter.clone() } &gt;+ SymmetricDifference { &gt;+ iter: self.iter.clone(), &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; Iterator for SymmetricDifference&lt;'a, T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = &amp;'a T; &gt; &gt; fn next(&amp;mut self) -&gt; Option&lt;&amp;'a T&gt; { &gt; self.iter.next() &gt; } &gt; fn size_hint(&amp;self) -&gt; (usize, Option&lt;usize&gt;) { &gt; self.iter.size_hint() &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; fmt::Debug for SymmetricDifference&lt;'a, T, S&gt; &gt;- where T: fmt::Debug + Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: fmt::Debug + Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; f.debug_list().entries(self.clone()).finish() &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; Clone for Union&lt;'a, T, S&gt; { &gt; fn clone(&amp;self) -&gt; Union&lt;'a, T, S&gt; { &gt;- Union { iter: self.iter.clone() } &gt;+ Union { &gt;+ iter: self.iter.clone(), &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; fmt::Debug for Union&lt;'a, T, S&gt; &gt;- where T: fmt::Debug + Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: fmt::Debug + Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; f.debug_list().entries(self.clone()).finish() &gt; } &gt; } &gt; &gt; impl&lt;'a, T, S&gt; Iterator for Union&lt;'a, T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; type Item = &amp;'a T; &gt; &gt; fn next(&amp;mut self) -&gt; Option&lt;&amp;'a T&gt; { &gt; self.iter.next() &gt; } &gt; fn size_hint(&amp;self) -&gt; (usize, Option&lt;usize&gt;) { &gt; self.iter.size_hint() &gt;@@ -1173,41 +1226,45 @@ fn assert_covariance() { &gt; v &gt; } &gt; fn iter&lt;'a, 'new&gt;(v: Iter&lt;'a, &amp;'static str&gt;) -&gt; Iter&lt;'a, &amp;'new str&gt; { &gt; v &gt; } &gt; fn into_iter&lt;'new&gt;(v: IntoIter&lt;&amp;'static str&gt;) -&gt; IntoIter&lt;&amp;'new str&gt; { &gt; v &gt; } &gt;- fn difference&lt;'a, 'new&gt;(v: Difference&lt;'a, &amp;'static str, RandomState&gt;) &gt;- -&gt; Difference&lt;'a, &amp;'new str, RandomState&gt; { &gt;+ fn difference&lt;'a, 'new&gt;( &gt;+ v: Difference&lt;'a, &amp;'static str, RandomState&gt;, &gt;+ ) -&gt; Difference&lt;'a, &amp;'new str, RandomState&gt; { &gt; v &gt; } &gt;- fn symmetric_difference&lt;'a, 'new&gt;(v: SymmetricDifference&lt;'a, &amp;'static str, RandomState&gt;) &gt;- -&gt; SymmetricDifference&lt;'a, &amp;'new str, RandomState&gt; { &gt;+ fn symmetric_difference&lt;'a, 'new&gt;( &gt;+ v: SymmetricDifference&lt;'a, &amp;'static str, RandomState&gt;, &gt;+ ) -&gt; SymmetricDifference&lt;'a, &amp;'new str, RandomState&gt; { &gt; v &gt; } &gt;- fn intersection&lt;'a, 'new&gt;(v: Intersection&lt;'a, &amp;'static str, RandomState&gt;) &gt;- -&gt; Intersection&lt;'a, &amp;'new str, RandomState&gt; { &gt;+ fn intersection&lt;'a, 'new&gt;( &gt;+ v: Intersection&lt;'a, &amp;'static str, RandomState&gt;, &gt;+ ) -&gt; Intersection&lt;'a, &amp;'new str, RandomState&gt; { &gt; v &gt; } &gt;- fn union&lt;'a, 'new&gt;(v: Union&lt;'a, &amp;'static str, RandomState&gt;) &gt;- -&gt; Union&lt;'a, &amp;'new str, RandomState&gt; { &gt;+ fn union&lt;'a, 'new&gt;( &gt;+ v: Union&lt;'a, &amp;'static str, RandomState&gt;, &gt;+ ) -&gt; Union&lt;'a, &amp;'new str, RandomState&gt; { &gt; v &gt; } &gt; fn drain&lt;'new&gt;(d: Drain&lt;'static, &amp;'static str&gt;) -&gt; Drain&lt;'new, &amp;'new str&gt; { &gt; d &gt; } &gt; } &gt; &gt; #[cfg(test)] &gt; mod test_set { &gt;- use super::HashSet; &gt; use super::hash_map::RandomState; &gt;+ use super::HashSet; &gt; &gt; #[test] &gt; fn test_zero_capacities() { &gt; type HS = HashSet&lt;i32&gt;; &gt; &gt; let s = HS::new(); &gt; assert_eq!(s.capacity(), 0); &gt; &gt;diff --git a/servo/components/hashglobe/src/lib.rs b/servo/components/hashglobe/src/lib.rs &gt;index 49038a51859d..cf6e9710f5fe 100644 &gt;--- a/servo/components/hashglobe/src/lib.rs &gt;+++ b/servo/components/hashglobe/src/lib.rs &gt;@@ -39,28 +39,33 @@ pub struct FailedAllocationError { &gt; reason: &amp;'static str, &gt; /// The allocation info we are requesting, if needed. &gt; allocation_info: Option&lt;AllocationInfo&gt;, &gt; } &gt; &gt; impl FailedAllocationError { &gt; #[inline] &gt; pub fn new(reason: &amp;'static str) -&gt; Self { &gt;- Self { reason, allocation_info: None } &gt;+ Self { &gt;+ reason, &gt;+ allocation_info: None, &gt;+ } &gt; } &gt; } &gt; &gt; impl error::Error for FailedAllocationError { &gt; fn description(&amp;self) -&gt; &amp;str { &gt; self.reason &gt; } &gt; } &gt; &gt; impl fmt::Display for FailedAllocationError { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; match self.allocation_info { &gt;- Some(ref info) =&gt; { &gt;- write!(f, "{}, allocation: (size: {}, alignment: {})", self.reason, info.size, info.alignment) &gt;- }, &gt;+ Some(ref info) =&gt; write!( &gt;+ f, &gt;+ "{}, allocation: (size: {}, alignment: {})", &gt;+ self.reason, info.size, info.alignment &gt;+ ), &gt; None =&gt; self.reason.fmt(f), &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/hashglobe/src/shim.rs b/servo/components/hashglobe/src/shim.rs &gt;index 146ff851a0e5..855dbdcfa155 100644 &gt;--- a/servo/components/hashglobe/src/shim.rs &gt;+++ b/servo/components/hashglobe/src/shim.rs &gt;@@ -24,21 +24,21 @@ impl&lt;T: 'static&gt; Unique&lt;T&gt; { &gt; _marker: PhantomData, &gt; } &gt; } &gt; pub fn as_ptr(&amp;self) -&gt; *mut T { &gt; self.ptr.as_ptr() &gt; } &gt; } &gt; &gt;-unsafe impl&lt;T: Send + 'static&gt; Send for Unique&lt;T&gt; { } &gt;+unsafe impl&lt;T: Send + 'static&gt; Send for Unique&lt;T&gt; {} &gt; &gt;-unsafe impl&lt;T: Sync + 'static&gt; Sync for Unique&lt;T&gt; { } &gt;+unsafe impl&lt;T: Sync + 'static&gt; Sync for Unique&lt;T&gt; {} &gt; &gt;-pub struct Shared&lt;T: 'static&gt; { &gt;+pub struct Shared&lt;T: 'static&gt; { &gt; ptr: NonZeroPtr&lt;T&gt;, &gt; _marker: PhantomData&lt;T&gt;, &gt; // force it to be !Send/!Sync &gt; _marker2: PhantomData&lt;*const u8&gt;, &gt; } &gt; &gt; impl&lt;T: 'static&gt; Shared&lt;T&gt; { &gt; pub unsafe fn new_unchecked(ptr: *mut T) -&gt; Self { &gt;diff --git a/servo/components/hashglobe/src/table.rs b/servo/components/hashglobe/src/table.rs &gt;index bd801b43544f..57d5b4ae55dc 100644 &gt;--- a/servo/components/hashglobe/src/table.rs &gt;+++ b/servo/components/hashglobe/src/table.rs &gt;@@ -4,23 +4,23 @@ &gt; // &gt; // Licensed under the Apache License, Version 2.0 &lt;LICENSE-APACHE or &gt; // http://www.apache.org/licenses/LICENSE-2.0&gt; or the MIT license &gt; // &lt;LICENSE-MIT or http://opensource.org/licenses/MIT&gt;, at your &gt; // option. This file may not be copied, modified, or distributed &gt; // except according to those terms. &gt; &gt; use alloc::{alloc, dealloc}; &gt;+use shim::{Shared, Unique}; &gt; use std::cmp; &gt; use std::hash::{BuildHasher, Hash, Hasher}; &gt; use std::marker; &gt; use std::mem::{self, align_of, size_of}; &gt; use std::ops::{Deref, DerefMut}; &gt; use std::ptr; &gt;-use shim::{Unique, Shared}; &gt; &gt; use self::BucketState::*; &gt; use FailedAllocationError; &gt; &gt; /// Integer type used for stored hash values. &gt; /// &gt; /// No more than bit_width(usize) bits are needed to select a bucket. &gt; /// &gt;@@ -198,26 +198,29 @@ impl SafeHash { &gt; pub fn new(hash: u64) -&gt; Self { &gt; // We need to avoid 0 in order to prevent collisions with &gt; // EMPTY_HASH. We can maintain our precious uniform distribution &gt; // of initial indexes by unconditionally setting the MSB, &gt; // effectively reducing the hashes by one bit. &gt; // &gt; // Truncate hash to fit in `HashUint`. &gt; let hash_bits = size_of::&lt;HashUint&gt;() * 8; &gt;- SafeHash { hash: (1 &lt;&lt; (hash_bits - 1)) | (hash as HashUint) } &gt;+ SafeHash { &gt;+ hash: (1 &lt;&lt; (hash_bits - 1)) | (hash as HashUint), &gt;+ } &gt; } &gt; } &gt; &gt; /// We need to remove hashes of 0. That's reserved for empty buckets. &gt; /// This function wraps up `hash_keyed` to be the only way outside this &gt; /// module to generate a SafeHash. &gt; pub fn make_hash&lt;T: ?Sized, S&gt;(hash_state: &amp;S, t: &amp;T) -&gt; SafeHash &gt;- where T: Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Hash, &gt;+ S: BuildHasher, &gt; { &gt; let mut state = hash_state.build_hasher(); &gt; t.hash(&amp;mut state); &gt; SafeHash::new(state.finish()) &gt; } &gt; &gt; // `replace` casts a `*HashUint` to a `*SafeHash`. Since we statically &gt; // ensure that a `FullBucket` points to an index with a non-zero hash, &gt;@@ -289,72 +292,71 @@ impl&lt;K, V, M&gt; Bucket&lt;K, V, M&gt; { &gt; } &gt; /// get the table. &gt; pub fn into_table(self) -&gt; M { &gt; self.table &gt; } &gt; } &gt; &gt; impl&lt;K, V, M&gt; Deref for FullBucket&lt;K, V, M&gt; &gt;- where M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt; &gt;+where &gt;+ M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt;, &gt; { &gt; type Target = RawTable&lt;K, V&gt;; &gt; fn deref(&amp;self) -&gt; &amp;RawTable&lt;K, V&gt; { &gt; &amp;self.table &gt; } &gt; } &gt; &gt; /// `Put` is implemented for types which provide access to a table and cannot be invalidated &gt; /// by filling a bucket. A similar implementation for `Take` is possible. &gt; pub trait Put&lt;K, V&gt; { &gt; unsafe fn borrow_table_mut(&amp;mut self) -&gt; &amp;mut RawTable&lt;K, V&gt;; &gt; } &gt; &gt;- &gt; impl&lt;'t, K, V&gt; Put&lt;K, V&gt; for &amp;'t mut RawTable&lt;K, V&gt; { &gt; unsafe fn borrow_table_mut(&amp;mut self) -&gt; &amp;mut RawTable&lt;K, V&gt; { &gt; *self &gt; } &gt; } &gt; &gt; impl&lt;K, V, M&gt; Put&lt;K, V&gt; for Bucket&lt;K, V, M&gt; &gt;- where M: Put&lt;K, V&gt; &gt;+where &gt;+ M: Put&lt;K, V&gt;, &gt; { &gt; unsafe fn borrow_table_mut(&amp;mut self) -&gt; &amp;mut RawTable&lt;K, V&gt; { &gt; self.table.borrow_table_mut() &gt; } &gt; } &gt; &gt; impl&lt;K, V, M&gt; Put&lt;K, V&gt; for FullBucket&lt;K, V, M&gt; &gt;- where M: Put&lt;K, V&gt; &gt;+where &gt;+ M: Put&lt;K, V&gt;, &gt; { &gt; unsafe fn borrow_table_mut(&amp;mut self) -&gt; &amp;mut RawTable&lt;K, V&gt; { &gt; self.table.borrow_table_mut() &gt; } &gt; } &gt; &gt; impl&lt;K, V, M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt;&gt; Bucket&lt;K, V, M&gt; { &gt; pub fn new(table: M, hash: SafeHash) -&gt; Bucket&lt;K, V, M&gt; { &gt; Bucket::at_index(table, hash.inspect() as usize) &gt; } &gt; &gt;- pub fn new_from(r: RawBucket&lt;K, V&gt;, t: M) &gt;- -&gt; Bucket&lt;K, V, M&gt; &gt;- { &gt;- Bucket { &gt;- raw: r, &gt;- table: t, &gt;- } &gt;+ pub fn new_from(r: RawBucket&lt;K, V&gt;, t: M) -&gt; Bucket&lt;K, V, M&gt; { &gt;+ Bucket { raw: r, table: t } &gt; } &gt; &gt; pub fn at_index(table: M, ib_index: usize) -&gt; Bucket&lt;K, V, M&gt; { &gt; // if capacity is 0, then the RawBucket will be populated with bogus pointers. &gt; // This is an uncommon case though, so avoid it in release builds. &gt;- debug_assert!(table.capacity() &gt; 0, &gt;- "Table should have capacity at this point"); &gt;+ debug_assert!( &gt;+ table.capacity() &gt; 0, &gt;+ "Table should have capacity at this point" &gt;+ ); &gt; let ib_index = ib_index &amp; table.capacity_mask; &gt; Bucket { &gt; raw: table.raw_bucket_at(ib_index), &gt; table, &gt; } &gt; } &gt; &gt; pub fn first(table: M) -&gt; Bucket&lt;K, V, M&gt; { &gt;@@ -399,28 +401,24 @@ impl&lt;K, V, M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt;&gt; Bucket&lt;K, V, M&gt; { &gt; } &gt; &gt; /// Reads a bucket at a given index, returning an enum indicating whether &gt; /// it's initialized or not. You need to match on this enum to get &gt; /// the appropriate types to call most of the other functions in &gt; /// this module. &gt; pub fn peek(self) -&gt; BucketState&lt;K, V, M&gt; { &gt; match unsafe { *self.raw.hash() } { &gt;- EMPTY_BUCKET =&gt; { &gt;- Empty(EmptyBucket { &gt;- raw: self.raw, &gt;- table: self.table, &gt;- }) &gt;- } &gt;- _ =&gt; { &gt;- Full(FullBucket { &gt;- raw: self.raw, &gt;- table: self.table, &gt;- }) &gt;- } &gt;+ EMPTY_BUCKET =&gt; Empty(EmptyBucket { &gt;+ raw: self.raw, &gt;+ table: self.table, &gt;+ }), &gt;+ _ =&gt; Full(FullBucket { &gt;+ raw: self.raw, &gt;+ table: self.table, &gt;+ }), &gt; } &gt; } &gt; &gt; /// Modifies the bucket in place to make it point to the next slot. &gt; pub fn next(&amp;mut self) { &gt; self.raw.idx = self.raw.idx.wrapping_add(1) &amp; self.table.capacity_mask; &gt; } &gt; &gt;@@ -448,29 +446,25 @@ impl&lt;K, V, M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt;&gt; EmptyBucket&lt;K, V, M&gt; { &gt; &gt; pub fn gap_peek(self) -&gt; Result&lt;GapThenFull&lt;K, V, M&gt;, Bucket&lt;K, V, M&gt;&gt; { &gt; let gap = EmptyBucket { &gt; raw: self.raw, &gt; table: (), &gt; }; &gt; &gt; match self.next().peek() { &gt;- Full(bucket) =&gt; { &gt;- Ok(GapThenFull { &gt;- gap, &gt;- full: bucket, &gt;- }) &gt;- } &gt;+ Full(bucket) =&gt; Ok(GapThenFull { gap, full: bucket }), &gt; Empty(e) =&gt; Err(e.into_bucket()), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;K, V, M&gt; EmptyBucket&lt;K, V, M&gt; &gt;- where M: Put&lt;K, V&gt; &gt;+where &gt;+ M: Put&lt;K, V&gt;, &gt; { &gt; /// Puts given key and value pair, along with the key's hash, &gt; /// into this bucket in the hashtable. Note how `self` is 'moved' into &gt; /// this function, because this slot will no longer be empty when &gt; /// we return! A `FullBucket` is returned for later use, pointing to &gt; /// the newly-filled slot in the hashtable. &gt; /// &gt; /// Use `make_hash` to construct a `SafeHash` to pass to this function. &gt;@@ -523,17 +517,21 @@ impl&lt;K, V, M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt;&gt; FullBucket&lt;K, V, M&gt; { &gt; // Calculates the distance one has to travel when going from &gt; // `hash mod capacity` onwards to `idx mod capacity`, wrapping around &gt; // if the destination is not reached before the end of the table. &gt; (self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) &amp; self.table.capacity_mask &gt; } &gt; &gt; #[inline] &gt; pub fn hash(&amp;self) -&gt; SafeHash { &gt;- unsafe { SafeHash { hash: *self.raw.hash() } } &gt;+ unsafe { &gt;+ SafeHash { &gt;+ hash: *self.raw.hash(), &gt;+ } &gt;+ } &gt; } &gt; &gt; /// Gets references to the key and value at a given index. &gt; pub fn read(&amp;self) -&gt; (&amp;K, &amp;V) { &gt; unsafe { &gt; let pair_ptr = self.raw.pair(); &gt; (&amp;(*pair_ptr).0, &amp;(*pair_ptr).1) &gt; } &gt;@@ -549,84 +547,91 @@ impl&lt;'t, K, V&gt; FullBucket&lt;K, V, &amp;'t mut RawTable&lt;K, V&gt;&gt; { &gt; /// This works similarly to `put`, building an `EmptyBucket` out of the &gt; /// taken bucket. &gt; pub fn take(self) -&gt; (EmptyBucket&lt;K, V, &amp;'t mut RawTable&lt;K, V&gt;&gt;, K, V) { &gt; self.table.size -= 1; &gt; &gt; unsafe { &gt; *self.raw.hash() = EMPTY_BUCKET; &gt; let (k, v) = ptr::read(self.raw.pair()); &gt;- (EmptyBucket { &gt;- raw: self.raw, &gt;- table: self.table, &gt;- }, &gt;- k, &gt;- v) &gt;+ ( &gt;+ EmptyBucket { &gt;+ raw: self.raw, &gt;+ table: self.table, &gt;+ }, &gt;+ k, &gt;+ v, &gt;+ ) &gt; } &gt; } &gt; } &gt; &gt; // This use of `Put` is misleading and restrictive, but safe and sufficient for our use cases &gt; // where `M` is a full bucket or table reference type with mutable access to the table. &gt; impl&lt;K, V, M&gt; FullBucket&lt;K, V, M&gt; &gt;- where M: Put&lt;K, V&gt; &gt;+where &gt;+ M: Put&lt;K, V&gt;, &gt; { &gt; pub fn replace(&amp;mut self, h: SafeHash, k: K, v: V) -&gt; (SafeHash, K, V) { &gt; unsafe { &gt; let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h); &gt; let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v)); &gt; &gt; (old_hash, old_key, old_val) &gt; } &gt; } &gt; } &gt; &gt; impl&lt;K, V, M&gt; FullBucket&lt;K, V, M&gt; &gt;- where M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt; + DerefMut &gt;+where &gt;+ M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt; + DerefMut, &gt; { &gt; /// Gets mutable references to the key and value at a given index. &gt; pub fn read_mut(&amp;mut self) -&gt; (&amp;mut K, &amp;mut V) { &gt; unsafe { &gt; let pair_ptr = self.raw.pair(); &gt; (&amp;mut (*pair_ptr).0, &amp;mut (*pair_ptr).1) &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'t, K, V, M&gt; FullBucket&lt;K, V, M&gt; &gt;- where M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt; + 't &gt;+where &gt;+ M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt; + 't, &gt; { &gt; /// Exchange a bucket state for immutable references into the table. &gt; /// Because the underlying reference to the table is also consumed, &gt; /// no further changes to the structure of the table are possible; &gt; /// in exchange for this, the returned references have a longer lifetime &gt; /// than the references returned by `read()`. &gt; pub fn into_refs(self) -&gt; (&amp;'t K, &amp;'t V) { &gt; unsafe { &gt; let pair_ptr = self.raw.pair(); &gt; (&amp;(*pair_ptr).0, &amp;(*pair_ptr).1) &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'t, K, V, M&gt; FullBucket&lt;K, V, M&gt; &gt;- where M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt; + DerefMut + 't &gt;+where &gt;+ M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt; + DerefMut + 't, &gt; { &gt; /// This works similarly to `into_refs`, exchanging a bucket state &gt; /// for mutable references into the table. &gt; pub fn into_mut_refs(self) -&gt; (&amp;'t mut K, &amp;'t mut V) { &gt; unsafe { &gt; let pair_ptr = self.raw.pair(); &gt; (&amp;mut (*pair_ptr).0, &amp;mut (*pair_ptr).1) &gt; } &gt; } &gt; } &gt; &gt; impl&lt;K, V, M&gt; GapThenFull&lt;K, V, M&gt; &gt;- where M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt; &gt;+where &gt;+ M: Deref&lt;Target = RawTable&lt;K, V&gt;&gt;, &gt; { &gt; #[inline] &gt; pub fn full(&amp;self) -&gt; &amp;FullBucket&lt;K, V, M&gt; { &gt; &amp;self.full &gt; } &gt; &gt; pub fn into_table(self) -&gt; M { &gt; self.full.into_table() &gt;@@ -650,17 +655,16 @@ impl&lt;K, V, M&gt; GapThenFull&lt;K, V, M&gt; &gt; &gt; Ok(self) &gt; } &gt; Empty(b) =&gt; Err(b.into_bucket()), &gt; } &gt; } &gt; } &gt; &gt;- &gt; /// Rounds up to a multiple of a power of two. Returns the closest multiple &gt; /// of `target_alignment` that is higher or equal to `unrounded`. &gt; /// &gt; /// # Panics &gt; /// &gt; /// Panics if `target_alignment` is not a power of two. &gt; #[inline] &gt; fn round_up_to_next(unrounded: usize, target_alignment: usize) -&gt; usize { &gt;@@ -676,33 +680,35 @@ fn test_rounding() { &gt; assert_eq!(round_up_to_next(3, 4), 4); &gt; assert_eq!(round_up_to_next(4, 4), 4); &gt; assert_eq!(round_up_to_next(5, 4), 8); &gt; } &gt; &gt; // Returns a tuple of (pairs_offset, end_of_pairs_offset), &gt; // from the start of a mallocated array. &gt; #[inline] &gt;-fn calculate_offsets(hashes_size: usize, &gt;- pairs_size: usize, &gt;- pairs_align: usize) &gt;- -&gt; (usize, usize, bool) { &gt;+fn calculate_offsets( &gt;+ hashes_size: usize, &gt;+ pairs_size: usize, &gt;+ pairs_align: usize, &gt;+) -&gt; (usize, usize, bool) { &gt; let pairs_offset = round_up_to_next(hashes_size, pairs_align); &gt; let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size); &gt; &gt; (pairs_offset, end_of_pairs, oflo) &gt; } &gt; &gt; // Returns a tuple of (minimum required malloc alignment, hash_offset, &gt; // array_size), from the start of a mallocated array. &gt;-fn calculate_allocation(hash_size: usize, &gt;- hash_align: usize, &gt;- pairs_size: usize, &gt;- pairs_align: usize) &gt;- -&gt; (usize, usize, usize, bool) { &gt;+fn calculate_allocation( &gt;+ hash_size: usize, &gt;+ hash_align: usize, &gt;+ pairs_size: usize, &gt;+ pairs_align: usize, &gt;+) -&gt; (usize, usize, usize, bool) { &gt; let hash_offset = 0; &gt; let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align); &gt; &gt; let align = cmp::max(hash_align, pairs_align); &gt; &gt; (align, hash_offset, end_of_pairs, oflo) &gt; } &gt; &gt;@@ -723,17 +729,19 @@ impl&lt;K, V&gt; RawTable&lt;K, V&gt; { &gt; table &gt; } else { &gt; libc::abort(); &gt; } &gt; } &gt; &gt; /// Does not initialize the buckets. The caller should ensure they, &gt; /// at the very least, set every hash to EMPTY_BUCKET. &gt;- unsafe fn try_new_uninitialized(capacity: usize) -&gt; Result&lt;RawTable&lt;K, V&gt;, FailedAllocationError&gt; { &gt;+ unsafe fn try_new_uninitialized( &gt;+ capacity: usize, &gt;+ ) -&gt; Result&lt;RawTable&lt;K, V&gt;, FailedAllocationError&gt; { &gt; if capacity == 0 { &gt; return Ok(RawTable { &gt; size: 0, &gt; capacity_mask: capacity.wrapping_sub(1), &gt; hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint), &gt; marker: marker::PhantomData, &gt; }); &gt; } &gt;@@ -746,39 +754,48 @@ impl&lt;K, V&gt; RawTable&lt;K, V&gt; { &gt; // Allocating hashmaps is a little tricky. We need to allocate two &gt; // arrays, but since we know their sizes and alignments up front, &gt; // we just allocate a single array, and then have the subarrays &gt; // point into it. &gt; // &gt; // This is great in theory, but in practice getting the alignment &gt; // right is a little subtle. Therefore, calculating offsets has been &gt; // factored out into a different function. &gt;- let (alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size, &gt;- align_of::&lt;HashUint&gt;(), &gt;- pairs_size, &gt;- align_of::&lt;(K, V)&gt;()); &gt;+ let (alignment, hash_offset, size, oflo) = calculate_allocation( &gt;+ hashes_size, &gt;+ align_of::&lt;HashUint&gt;(), &gt;+ pairs_size, &gt;+ align_of::&lt;(K, V)&gt;(), &gt;+ ); &gt; &gt; if oflo { &gt;- return Err(FailedAllocationError::new("capacity overflow when allocating RawTable" )); &gt;+ return Err(FailedAllocationError::new( &gt;+ "capacity overflow when allocating RawTable", &gt;+ )); &gt; } &gt; &gt; // One check for overflow that covers calculation and rounding of size. &gt;- let size_of_bucket = size_of::&lt;HashUint&gt;().checked_add(size_of::&lt;(K, V)&gt;()).unwrap(); &gt;+ let size_of_bucket = size_of::&lt;HashUint&gt;() &gt;+ .checked_add(size_of::&lt;(K, V)&gt;()) &gt;+ .unwrap(); &gt; &gt; let cap_bytes = capacity.checked_mul(size_of_bucket); &gt; &gt; if let Some(cap_bytes) = cap_bytes { &gt; if size &lt; cap_bytes { &gt;- return Err(FailedAllocationError::new("capacity overflow when allocating RawTable")); &gt;+ return Err(FailedAllocationError::new( &gt;+ "capacity overflow when allocating RawTable", &gt;+ )); &gt; } &gt; } else { &gt;- return Err(FailedAllocationError::new("capacity overflow when allocating RawTable")); &gt;+ return Err(FailedAllocationError::new( &gt;+ "capacity overflow when allocating RawTable", &gt;+ )); &gt; } &gt; &gt;- &gt; // FORK NOTE: Uses alloc shim instead of Heap.alloc &gt; let buffer = alloc(size, alignment); &gt; &gt; if buffer.is_null() { &gt; use AllocationInfo; &gt; return Err(FailedAllocationError { &gt; reason: "out of memory when allocating RawTable", &gt; allocation_info: Some(AllocationInfo { size, alignment }), &gt;@@ -852,30 +869,34 @@ impl&lt;K, V&gt; RawTable&lt;K, V&gt; { &gt; pub fn iter_mut(&amp;mut self) -&gt; IterMut&lt;K, V&gt; { &gt; IterMut { &gt; iter: self.raw_buckets(), &gt; _marker: marker::PhantomData, &gt; } &gt; } &gt; &gt; pub fn into_iter(self) -&gt; IntoIter&lt;K, V&gt; { &gt;- let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); &gt;+ let RawBuckets { &gt;+ raw, elems_left, .. &gt;+ } = self.raw_buckets(); &gt; // Replace the marker regardless of lifetime bounds on parameters. &gt; IntoIter { &gt; iter: RawBuckets { &gt; raw, &gt; elems_left, &gt; marker: marker::PhantomData, &gt; }, &gt; table: self, &gt; } &gt; } &gt; &gt; pub fn drain(&amp;mut self) -&gt; Drain&lt;K, V&gt; { &gt;- let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); &gt;+ let RawBuckets { &gt;+ raw, elems_left, .. &gt;+ } = self.raw_buckets(); &gt; // Replace the marker regardless of lifetime bounds on parameters. &gt; Drain { &gt; iter: RawBuckets { &gt; raw, &gt; elems_left, &gt; marker: marker::PhantomData, &gt; }, &gt; table: Shared::from(self), &gt;@@ -932,17 +953,16 @@ impl&lt;'a, K, V&gt; Clone for RawBuckets&lt;'a, K, V&gt; { &gt; RawBuckets { &gt; raw: self.raw, &gt; elems_left: self.elems_left, &gt; marker: marker::PhantomData, &gt; } &gt; } &gt; } &gt; &gt;- &gt; impl&lt;'a, K, V&gt; Iterator for RawBuckets&lt;'a, K, V&gt; { &gt; type Item = RawBucket&lt;K, V&gt;; &gt; &gt; fn next(&amp;mut self) -&gt; Option&lt;RawBucket&lt;K, V&gt;&gt; { &gt; if self.elems_left == 0 { &gt; return None; &gt; } &gt; &gt;@@ -1107,22 +1127,26 @@ impl&lt;K, V&gt; ExactSizeIterator for IntoIter&lt;K, V&gt; { &gt; } &gt; } &gt; &gt; impl&lt;'a, K, V&gt; Iterator for Drain&lt;'a, K, V&gt; { &gt; type Item = (SafeHash, K, V); &gt; &gt; #[inline] &gt; fn next(&amp;mut self) -&gt; Option&lt;(SafeHash, K, V)&gt; { &gt;- self.iter.next().map(|raw| { &gt;- unsafe { &gt;- self.table.as_mut().size -= 1; &gt;- let (k, v) = ptr::read(raw.pair()); &gt;- (SafeHash { hash: ptr::replace(&amp;mut *raw.hash(), EMPTY_BUCKET) }, k, v) &gt;- } &gt;+ self.iter.next().map(|raw| unsafe { &gt;+ self.table.as_mut().size -= 1; &gt;+ let (k, v) = ptr::read(raw.pair()); &gt;+ ( &gt;+ SafeHash { &gt;+ hash: ptr::replace(&amp;mut *raw.hash(), EMPTY_BUCKET), &gt;+ }, &gt;+ k, &gt;+ v, &gt;+ ) &gt; }) &gt; } &gt; &gt; fn size_hint(&amp;self) -&gt; (usize, Option&lt;usize&gt;) { &gt; self.iter.size_hint() &gt; } &gt; } &gt; &gt;@@ -1176,27 +1200,29 @@ impl&lt;K, V&gt; Drop for RawTable&lt;K, V&gt; { &gt; // This is done in reverse because we've likely partially taken &gt; // some elements out with `.into_iter()` from the front. &gt; // Check if the size is 0, so we don't do a useless scan when &gt; // dropping empty tables such as on resize. &gt; // Also avoid double drop of elements that have been already moved out. &gt; unsafe { &gt; // FORK NOTE: Can't needs_drop on stable &gt; // if needs_drop::&lt;(K, V)&gt;() { &gt;- // avoid linear runtime for types that don't need drop &gt;- self.rev_drop_buckets(); &gt;+ // avoid linear runtime for types that don't need drop &gt;+ self.rev_drop_buckets(); &gt; // } &gt; } &gt; &gt; let hashes_size = self.capacity() * size_of::&lt;HashUint&gt;(); &gt; let pairs_size = self.capacity() * size_of::&lt;(K, V)&gt;(); &gt;- let (align, _, _, oflo) = calculate_allocation(hashes_size, &gt;- align_of::&lt;HashUint&gt;(), &gt;- pairs_size, &gt;- align_of::&lt;(K, V)&gt;()); &gt;+ let (align, _, _, oflo) = calculate_allocation( &gt;+ hashes_size, &gt;+ align_of::&lt;HashUint&gt;(), &gt;+ pairs_size, &gt;+ align_of::&lt;(K, V)&gt;(), &gt;+ ); &gt; &gt; debug_assert!(!oflo, "should be impossible"); &gt; &gt; unsafe { &gt; dealloc(self.hashes.ptr() as *mut u8, align); &gt; // Remember how everything was allocated out of one buffer &gt; // during initialization? We only need one call to free here. &gt; } &gt;diff --git a/servo/components/malloc_size_of/lib.rs b/servo/components/malloc_size_of/lib.rs &gt;index f4774d66a3e6..2ec2b1ff7756 100644 &gt;--- a/servo/components/malloc_size_of/lib.rs &gt;+++ b/servo/components/malloc_size_of/lib.rs &gt;@@ -73,18 +73,18 @@ extern crate void; &gt; extern crate webrender_api; &gt; #[cfg(feature = "servo")] &gt; extern crate xml5ever; &gt; &gt; #[cfg(feature = "servo")] &gt; use serde_bytes::ByteBuf; &gt; use std::hash::{BuildHasher, Hash}; &gt; use std::mem::size_of; &gt;-use std::ops::{Deref, DerefMut}; &gt; use std::ops::Range; &gt;+use std::ops::{Deref, DerefMut}; &gt; use std::os::raw::c_void; &gt; use void::Void; &gt; &gt; /// A C function that takes a pointer to a heap allocation and returns its size. &gt; type VoidPtrToSizeFn = unsafe extern "C" fn(ptr: *const c_void) -&gt; usize; &gt; &gt; /// A closure implementing a stateful predicate on pointers. &gt; type VoidPtrToBoolFnMut = FnMut(*const c_void) -&gt; bool; &gt;@@ -102,19 +102,21 @@ pub struct MallocSizeOfOps { &gt; &gt; /// Check if a pointer has been seen before, and remember it for next time. &gt; /// Useful when measuring `Rc`s and `Arc`s. Optional, because many places &gt; /// don't need it. &gt; have_seen_ptr_op: Option&lt;Box&lt;VoidPtrToBoolFnMut&gt;&gt;, &gt; } &gt; &gt; impl MallocSizeOfOps { &gt;- pub fn new(size_of: VoidPtrToSizeFn, &gt;- malloc_enclosing_size_of: Option&lt;VoidPtrToSizeFn&gt;, &gt;- have_seen_ptr: Option&lt;Box&lt;VoidPtrToBoolFnMut&gt;&gt;) -&gt; Self { &gt;+ pub fn new( &gt;+ size_of: VoidPtrToSizeFn, &gt;+ malloc_enclosing_size_of: Option&lt;VoidPtrToSizeFn&gt;, &gt;+ have_seen_ptr: Option&lt;Box&lt;VoidPtrToBoolFnMut&gt;&gt;, &gt;+ ) -&gt; Self { &gt; MallocSizeOfOps { &gt; size_of_op: size_of, &gt; enclosing_size_of_op: malloc_enclosing_size_of, &gt; have_seen_ptr_op: have_seen_ptr, &gt; } &gt; } &gt; &gt; /// Check if an allocation is empty. This relies on knowledge of how Rust &gt;@@ -122,17 +124,17 @@ impl MallocSizeOfOps { &gt; fn is_empty&lt;T: ?Sized&gt;(ptr: *const T) -&gt; bool { &gt; // The correct condition is this: &gt; // `ptr as usize &lt;= ::std::mem::align_of::&lt;T&gt;()` &gt; // But we can't call align_of() on a ?Sized T. So we approximate it &gt; // with the following. 256 is large enough that it should always be &gt; // larger than the required alignment, but small enough that it is &gt; // always in the first page of memory and therefore not a legitimate &gt; // address. &gt;- return ptr as *const usize as usize &lt;= 256 &gt;+ return ptr as *const usize as usize &lt;= 256; &gt; } &gt; &gt; /// Call `size_of_op` on `ptr`, first checking that the allocation isn't &gt; /// empty, because some types (such as `Vec`) utilize empty allocations. &gt; pub unsafe fn malloc_size_of&lt;T: ?Sized&gt;(&amp;self, ptr: *const T) -&gt; usize { &gt; if MallocSizeOfOps::is_empty(ptr) { &gt; 0 &gt; } else { &gt;@@ -149,17 +151,20 @@ impl MallocSizeOfOps { &gt; /// must not be empty. &gt; pub unsafe fn malloc_enclosing_size_of&lt;T&gt;(&amp;self, ptr: *const T) -&gt; usize { &gt; assert!(!MallocSizeOfOps::is_empty(ptr)); &gt; (self.enclosing_size_of_op.unwrap())(ptr as *const c_void) &gt; } &gt; &gt; /// Call `have_seen_ptr_op` on `ptr`. &gt; pub fn have_seen_ptr&lt;T&gt;(&amp;mut self, ptr: *const T) -&gt; bool { &gt;- let have_seen_ptr_op = self.have_seen_ptr_op.as_mut().expect("missing have_seen_ptr_op"); &gt;+ let have_seen_ptr_op = self &gt;+ .have_seen_ptr_op &gt;+ .as_mut() &gt;+ .expect("missing have_seen_ptr_op"); &gt; have_seen_ptr_op(ptr as *const c_void) &gt; } &gt; } &gt; &gt; /// Trait for measuring the "deep" heap usage of a data structure. This is the &gt; /// most commonly-used of the traits. &gt; pub trait MallocSizeOf { &gt; /// Measure the heap usage of all descendant heap-allocated structures, but &gt;@@ -252,33 +257,42 @@ impl&lt;T: MallocSizeOf&gt; MallocSizeOf for thin_slice::ThinBoxedSlice&lt;T&gt; { &gt; &gt; impl MallocSizeOf for () { &gt; fn size_of(&amp;self, _ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; 0 &gt; } &gt; } &gt; &gt; impl&lt;T1, T2&gt; MallocSizeOf for (T1, T2) &gt;- where T1: MallocSizeOf, T2: MallocSizeOf &gt;+where &gt;+ T1: MallocSizeOf, &gt;+ T2: MallocSizeOf, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; self.0.size_of(ops) + self.1.size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;T1, T2, T3&gt; MallocSizeOf for (T1, T2, T3) &gt;- where T1: MallocSizeOf, T2: MallocSizeOf, T3: MallocSizeOf &gt;+where &gt;+ T1: MallocSizeOf, &gt;+ T2: MallocSizeOf, &gt;+ T3: MallocSizeOf, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; self.0.size_of(ops) + self.1.size_of(ops) + self.2.size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;T1, T2, T3, T4&gt; MallocSizeOf for (T1, T2, T3, T4) &gt;- where T1: MallocSizeOf, T2: MallocSizeOf, T3: MallocSizeOf, T4: MallocSizeOf &gt;+where &gt;+ T1: MallocSizeOf, &gt;+ T2: MallocSizeOf, &gt;+ T3: MallocSizeOf, &gt;+ T4: MallocSizeOf, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; self.0.size_of(ops) + self.1.size_of(ops) + self.2.size_of(ops) + self.3.size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;T: MallocSizeOf&gt; MallocSizeOf for Option&lt;T&gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt;@@ -307,17 +321,18 @@ impl&lt;T: MallocSizeOf + Copy&gt; MallocSizeOf for std::cell::Cell&lt;T&gt; { &gt; &gt; impl&lt;T: MallocSizeOf&gt; MallocSizeOf for std::cell::RefCell&lt;T&gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; self.borrow().size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;'a, B: ?Sized + ToOwned&gt; MallocSizeOf for std::borrow::Cow&lt;'a, B&gt; &gt;- where B::Owned: MallocSizeOf &gt;+where &gt;+ B::Owned: MallocSizeOf, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; match *self { &gt; std::borrow::Cow::Borrowed(_) =&gt; 0, &gt; std::borrow::Cow::Owned(ref b) =&gt; b.size_of(ops), &gt; } &gt; } &gt; } &gt;@@ -399,178 +414,199 @@ impl&lt;A: smallvec::Array&gt; MallocShallowSizeOf for smallvec::SmallVec&lt;A&gt; { &gt; unsafe { ops.malloc_size_of(self.as_ptr()) } &gt; } else { &gt; 0 &gt; } &gt; } &gt; } &gt; &gt; impl&lt;A&gt; MallocSizeOf for smallvec::SmallVec&lt;A&gt; &gt;- where A: smallvec::Array, &gt;- A::Item: MallocSizeOf &gt;+where &gt;+ A: smallvec::Array, &gt;+ A::Item: MallocSizeOf, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; let mut n = self.shallow_size_of(ops); &gt; for elem in self.iter() { &gt; n += elem.size_of(ops); &gt; } &gt; n &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; MallocShallowSizeOf for std::collections::HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn shallow_size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; if ops.has_malloc_enclosing_size_of() { &gt; // The first value from the iterator gives us an interior pointer. &gt; // `ops.malloc_enclosing_size_of()` then gives us the storage size. &gt; // This assumes that the `HashSet`'s contents (values and hashes) &gt; // are all stored in a single contiguous heap allocation. &gt;- self.iter().next().map_or(0, |t| unsafe { ops.malloc_enclosing_size_of(t) }) &gt;+ self.iter() &gt;+ .next() &gt;+ .map_or(0, |t| unsafe { ops.malloc_enclosing_size_of(t) }) &gt; } else { &gt; // An estimate. &gt; self.capacity() * (size_of::&lt;T&gt;() + size_of::&lt;usize&gt;()) &gt; } &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; MallocSizeOf for std::collections::HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash + MallocSizeOf, &gt;- S: BuildHasher, &gt;+where &gt;+ T: Eq + Hash + MallocSizeOf, &gt;+ S: BuildHasher, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; let mut n = self.shallow_size_of(ops); &gt; for t in self.iter() { &gt; n += t.size_of(ops); &gt; } &gt; n &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; MallocShallowSizeOf for hashglobe::hash_set::HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn shallow_size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; // See the implementation for std::collections::HashSet for details. &gt; if ops.has_malloc_enclosing_size_of() { &gt;- self.iter().next().map_or(0, |t| unsafe { ops.malloc_enclosing_size_of(t) }) &gt;+ self.iter() &gt;+ .next() &gt;+ .map_or(0, |t| unsafe { ops.malloc_enclosing_size_of(t) }) &gt; } else { &gt; self.capacity() * (size_of::&lt;T&gt;() + size_of::&lt;usize&gt;()) &gt; } &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; MallocSizeOf for hashglobe::hash_set::HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash + MallocSizeOf, &gt;- S: BuildHasher, &gt;+where &gt;+ T: Eq + Hash + MallocSizeOf, &gt;+ S: BuildHasher, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; let mut n = self.shallow_size_of(ops); &gt; for t in self.iter() { &gt; n += t.size_of(ops); &gt; } &gt; n &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; MallocShallowSizeOf for hashglobe::fake::HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash, &gt;- S: BuildHasher, &gt;+where &gt;+ T: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn shallow_size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; use std::ops::Deref; &gt; self.deref().shallow_size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;T, S&gt; MallocSizeOf for hashglobe::fake::HashSet&lt;T, S&gt; &gt;- where T: Eq + Hash + MallocSizeOf, &gt;- S: BuildHasher, &gt;+where &gt;+ T: Eq + Hash + MallocSizeOf, &gt;+ S: BuildHasher, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; use std::ops::Deref; &gt; self.deref().size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; MallocShallowSizeOf for std::collections::HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn shallow_size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; // See the implementation for std::collections::HashSet for details. &gt; if ops.has_malloc_enclosing_size_of() { &gt;- self.values().next().map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) }) &gt;+ self.values() &gt;+ .next() &gt;+ .map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) }) &gt; } else { &gt; self.capacity() * (size_of::&lt;V&gt;() + size_of::&lt;K&gt;() + size_of::&lt;usize&gt;()) &gt; } &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; MallocSizeOf for std::collections::HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash + MallocSizeOf, &gt;- V: MallocSizeOf, &gt;- S: BuildHasher, &gt;+where &gt;+ K: Eq + Hash + MallocSizeOf, &gt;+ V: MallocSizeOf, &gt;+ S: BuildHasher, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; let mut n = self.shallow_size_of(ops); &gt; for (k, v) in self.iter() { &gt; n += k.size_of(ops); &gt; n += v.size_of(ops); &gt; } &gt; n &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; MallocShallowSizeOf for hashglobe::hash_map::HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn shallow_size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; // See the implementation for std::collections::HashSet for details. &gt; if ops.has_malloc_enclosing_size_of() { &gt;- self.values().next().map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) }) &gt;+ self.values() &gt;+ .next() &gt;+ .map_or(0, |v| unsafe { ops.malloc_enclosing_size_of(v) }) &gt; } else { &gt; self.capacity() * (size_of::&lt;V&gt;() + size_of::&lt;K&gt;() + size_of::&lt;usize&gt;()) &gt; } &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; MallocSizeOf for hashglobe::hash_map::HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash + MallocSizeOf, &gt;- V: MallocSizeOf, &gt;- S: BuildHasher, &gt;+where &gt;+ K: Eq + Hash + MallocSizeOf, &gt;+ V: MallocSizeOf, &gt;+ S: BuildHasher, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; let mut n = self.shallow_size_of(ops); &gt; for (k, v) in self.iter() { &gt; n += k.size_of(ops); &gt; n += v.size_of(ops); &gt; } &gt; n &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; MallocShallowSizeOf for hashglobe::fake::HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash, &gt;- S: BuildHasher, &gt;+where &gt;+ K: Eq + Hash, &gt;+ S: BuildHasher, &gt; { &gt; fn shallow_size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; use std::ops::Deref; &gt; self.deref().shallow_size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;K, V, S&gt; MallocSizeOf for hashglobe::fake::HashMap&lt;K, V, S&gt; &gt;- where K: Eq + Hash + MallocSizeOf, &gt;- V: MallocSizeOf, &gt;- S: BuildHasher, &gt;+where &gt;+ K: Eq + Hash + MallocSizeOf, &gt;+ V: MallocSizeOf, &gt;+ S: BuildHasher, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; use std::ops::Deref; &gt; self.deref().size_of(ops) &gt; } &gt; } &gt; &gt; // PhantomData is always 0. &gt;@@ -662,63 +698,75 @@ impl&lt;T: MallocSizeOf, U&gt; MallocSizeOf for euclid::TypedPoint2D&lt;T, U&gt; { &gt; impl&lt;T: MallocSizeOf, U&gt; MallocSizeOf for euclid::TypedRect&lt;T, U&gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; self.origin.size_of(ops) + self.size.size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;T: MallocSizeOf, U&gt; MallocSizeOf for euclid::TypedSideOffsets2D&lt;T, U&gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt;- self.top.size_of(ops) + self.right.size_of(ops) + &gt;- self.bottom.size_of(ops) + self.left.size_of(ops) &gt;+ self.top.size_of(ops) &gt;+ + self.right.size_of(ops) &gt;+ + self.bottom.size_of(ops) &gt;+ + self.left.size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;T: MallocSizeOf, U&gt; MallocSizeOf for euclid::TypedSize2D&lt;T, U&gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; self.width.size_of(ops) + self.height.size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;T: MallocSizeOf, Src, Dst&gt; MallocSizeOf for euclid::TypedTransform2D&lt;T, Src, Dst&gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt;- self.m11.size_of(ops) + self.m12.size_of(ops) + &gt;- self.m21.size_of(ops) + self.m22.size_of(ops) + &gt;- self.m31.size_of(ops) + self.m32.size_of(ops) &gt;+ self.m11.size_of(ops) &gt;+ + self.m12.size_of(ops) &gt;+ + self.m21.size_of(ops) &gt;+ + self.m22.size_of(ops) &gt;+ + self.m31.size_of(ops) &gt;+ + self.m32.size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;T: MallocSizeOf, Src, Dst&gt; MallocSizeOf for euclid::TypedTransform3D&lt;T, Src, Dst&gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt;- self.m11.size_of(ops) + self.m12.size_of(ops) + &gt;- self.m13.size_of(ops) + self.m14.size_of(ops) + &gt;- self.m21.size_of(ops) + self.m22.size_of(ops) + &gt;- self.m23.size_of(ops) + self.m24.size_of(ops) + &gt;- self.m31.size_of(ops) + self.m32.size_of(ops) + &gt;- self.m33.size_of(ops) + self.m34.size_of(ops) + &gt;- self.m41.size_of(ops) + self.m42.size_of(ops) + &gt;- self.m43.size_of(ops) + self.m44.size_of(ops) &gt;+ self.m11.size_of(ops) &gt;+ + self.m12.size_of(ops) &gt;+ + self.m13.size_of(ops) &gt;+ + self.m14.size_of(ops) &gt;+ + self.m21.size_of(ops) &gt;+ + self.m22.size_of(ops) &gt;+ + self.m23.size_of(ops) &gt;+ + self.m24.size_of(ops) &gt;+ + self.m31.size_of(ops) &gt;+ + self.m32.size_of(ops) &gt;+ + self.m33.size_of(ops) &gt;+ + self.m34.size_of(ops) &gt;+ + self.m41.size_of(ops) &gt;+ + self.m42.size_of(ops) &gt;+ + self.m43.size_of(ops) &gt;+ + self.m44.size_of(ops) &gt; } &gt; } &gt; &gt; impl&lt;T: MallocSizeOf, U&gt; MallocSizeOf for euclid::TypedVector2D&lt;T, U&gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; self.x.size_of(ops) + self.y.size_of(ops) &gt; } &gt; } &gt; &gt; impl MallocSizeOf for selectors::parser::AncestorHashes { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; let selectors::parser::AncestorHashes { ref packed_hashes } = *self; &gt; packed_hashes.size_of(ops) &gt; } &gt; } &gt; &gt;-impl&lt;Impl: selectors::parser::SelectorImpl&gt; MallocSizeOf &gt;- for selectors::parser::Selector&lt;Impl&gt; &gt;+impl&lt;Impl: selectors::parser::SelectorImpl&gt; MallocSizeOf for selectors::parser::Selector&lt;Impl&gt; &gt; where &gt; Impl::NonTSPseudoClass: MallocSizeOf, &gt; Impl::PseudoElement: MallocSizeOf, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; let mut n = 0; &gt; &gt; // It's OK to measure this ThinArc directly because it's the &gt;@@ -728,67 +776,57 @@ where &gt; for component in self.iter_raw_match_order() { &gt; n += component.size_of(ops); &gt; } &gt; &gt; n &gt; } &gt; } &gt; &gt;-impl&lt;Impl: selectors::parser::SelectorImpl&gt; MallocSizeOf &gt;- for selectors::parser::Component&lt;Impl&gt; &gt;+impl&lt;Impl: selectors::parser::SelectorImpl&gt; MallocSizeOf for selectors::parser::Component&lt;Impl&gt; &gt; where &gt; Impl::NonTSPseudoClass: MallocSizeOf, &gt; Impl::PseudoElement: MallocSizeOf, &gt; { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; use selectors::parser::Component; &gt; &gt; match self { &gt;- Component::AttributeOther(ref attr_selector) =&gt; { &gt;- attr_selector.size_of(ops) &gt;- } &gt;- Component::Negation(ref components) =&gt; { &gt;- components.size_of(ops) &gt;- } &gt;- Component::NonTSPseudoClass(ref pseudo) =&gt; { &gt;- (*pseudo).size_of(ops) &gt;- } &gt;- Component::Slotted(ref selector) | &gt;- Component::Host(Some(ref selector)) =&gt; { &gt;+ Component::AttributeOther(ref attr_selector) =&gt; attr_selector.size_of(ops), &gt;+ Component::Negation(ref components) =&gt; components.size_of(ops), &gt;+ Component::NonTSPseudoClass(ref pseudo) =&gt; (*pseudo).size_of(ops), &gt;+ Component::Slotted(ref selector) | Component::Host(Some(ref selector)) =&gt; { &gt; selector.size_of(ops) &gt; } &gt;- Component::PseudoElement(ref pseudo) =&gt; { &gt;- (*pseudo).size_of(ops) &gt;- } &gt;- Component::Combinator(..) | &gt;- Component::ExplicitAnyNamespace | &gt;- Component::ExplicitNoNamespace | &gt;- Component::DefaultNamespace(..) | &gt;- Component::Namespace(..) | &gt;- Component::ExplicitUniversalType | &gt;- Component::LocalName(..) | &gt;- Component::ID(..) | &gt;- Component::Class(..) | &gt;- Component::AttributeInNoNamespaceExists { .. } | &gt;- Component::AttributeInNoNamespace { .. } | &gt;- Component::FirstChild | &gt;- Component::LastChild | &gt;- Component::OnlyChild | &gt;- Component::Root | &gt;- Component::Empty | &gt;- Component::Scope | &gt;- Component::NthChild(..) | &gt;- Component::NthLastChild(..) | &gt;- Component::NthOfType(..) | &gt;- Component::NthLastOfType(..) | &gt;- Component::FirstOfType | &gt;- Component::LastOfType | &gt;- Component::OnlyOfType | &gt;- Component::Host(None) =&gt; 0, &gt;+ Component::PseudoElement(ref pseudo) =&gt; (*pseudo).size_of(ops), &gt;+ Component::Combinator(..) &gt;+ | Component::ExplicitAnyNamespace &gt;+ | Component::ExplicitNoNamespace &gt;+ | Component::DefaultNamespace(..) &gt;+ | Component::Namespace(..) &gt;+ | Component::ExplicitUniversalType &gt;+ | Component::LocalName(..) &gt;+ | Component::ID(..) &gt;+ | Component::Class(..) &gt;+ | Component::AttributeInNoNamespaceExists { .. } &gt;+ | Component::AttributeInNoNamespace { .. } &gt;+ | Component::FirstChild &gt;+ | Component::LastChild &gt;+ | Component::OnlyChild &gt;+ | Component::Root &gt;+ | Component::Empty &gt;+ | Component::Scope &gt;+ | Component::NthChild(..) &gt;+ | Component::NthLastChild(..) &gt;+ | Component::NthOfType(..) &gt;+ | Component::NthLastOfType(..) &gt;+ | Component::FirstOfType &gt;+ | Component::LastOfType &gt;+ | Component::OnlyOfType &gt;+ | Component::Host(None) =&gt; 0, &gt; } &gt; } &gt; } &gt; &gt; impl&lt;Impl: selectors::parser::SelectorImpl&gt; MallocSizeOf &gt; for selectors::attr::AttrSelectorWithOptionalNamespace&lt;Impl&gt; &gt; { &gt; fn size_of(&amp;self, _ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt;@@ -845,17 +883,20 @@ macro_rules! malloc_size_of_is_0( &gt; ); &gt; &gt; malloc_size_of_is_0!(bool, char, str); &gt; malloc_size_of_is_0!(u8, u16, u32, u64, usize); &gt; malloc_size_of_is_0!(i8, i16, i32, i64, isize); &gt; malloc_size_of_is_0!(f32, f64); &gt; &gt; malloc_size_of_is_0!(std::sync::atomic::AtomicBool); &gt;-malloc_size_of_is_0!(std::sync::atomic::AtomicIsize, std::sync::atomic::AtomicUsize); &gt;+malloc_size_of_is_0!( &gt;+ std::sync::atomic::AtomicIsize, &gt;+ std::sync::atomic::AtomicUsize &gt;+); &gt; &gt; malloc_size_of_is_0!(Range&lt;u8&gt;, Range&lt;u16&gt;, Range&lt;u32&gt;, Range&lt;u64&gt;, Range&lt;usize&gt;); &gt; malloc_size_of_is_0!(Range&lt;i8&gt;, Range&lt;i16&gt;, Range&lt;i32&gt;, Range&lt;i64&gt;, Range&lt;isize&gt;); &gt; malloc_size_of_is_0!(Range&lt;f32&gt;, Range&lt;f64&gt;); &gt; &gt; malloc_size_of_is_0!(app_units::Au); &gt; &gt; malloc_size_of_is_0!(cssparser::RGBA, cssparser::TokenSerializationType); &gt;@@ -914,19 +955,17 @@ malloc_size_of_is_0!(webrender_api::ScrollSensitivity); &gt; #[cfg(feature = "webrender_api")] &gt; malloc_size_of_is_0!(webrender_api::StickyOffsetBounds); &gt; #[cfg(feature = "webrender_api")] &gt; malloc_size_of_is_0!(webrender_api::TransformStyle); &gt; &gt; #[cfg(feature = "servo")] &gt; impl MallocSizeOf for xml5ever::QualName { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt;- self.prefix.size_of(ops) + &gt;- self.ns.size_of(ops) + &gt;- self.local.size_of(ops) &gt;+ self.prefix.size_of(ops) + self.ns.size_of(ops) + self.local.size_of(ops) &gt; } &gt; } &gt; &gt; #[cfg(feature = "servo")] &gt; impl MallocSizeOf for hyper::header::Headers { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; self.iter().fold(0, |acc, x| { &gt; let name = x.name(); &gt;@@ -941,19 +980,17 @@ impl MallocSizeOf for hyper::header::ContentType { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; self.0.size_of(ops) &gt; } &gt; } &gt; &gt; #[cfg(feature = "servo")] &gt; impl MallocSizeOf for hyper::mime::Mime { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt;- self.0.size_of(ops) + &gt;- self.1.size_of(ops) + &gt;- self.2.size_of(ops) &gt;+ self.0.size_of(ops) + self.1.size_of(ops) + self.2.size_of(ops) &gt; } &gt; } &gt; &gt; #[cfg(feature = "servo")] &gt; impl MallocSizeOf for hyper::mime::Attr { &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; match *self { &gt; hyper::mime::Attr::Ext(ref s) =&gt; s.size_of(ops), &gt;@@ -970,20 +1007,22 @@ impl MallocSizeOf for hyper::mime::Value { &gt; } &gt; &gt; #[cfg(feature = "servo")] &gt; malloc_size_of_is_0!(time::Duration); &gt; #[cfg(feature = "servo")] &gt; malloc_size_of_is_0!(time::Tm); &gt; &gt; #[cfg(feature = "servo")] &gt;-impl&lt;T&gt; MallocSizeOf for hyper_serde::Serde&lt;T&gt; where &gt;- for &lt;'de&gt; hyper_serde::De&lt;T&gt;: serde::Deserialize&lt;'de&gt;, &gt;- for &lt;'a&gt; hyper_serde::Ser&lt;'a, T&gt;: serde::Serialize, &gt;- T: MallocSizeOf { &gt;+impl&lt;T&gt; MallocSizeOf for hyper_serde::Serde&lt;T&gt; &gt;+where &gt;+ for&lt;'de&gt; hyper_serde::De&lt;T&gt;: serde::Deserialize&lt;'de&gt;, &gt;+ for&lt;'a&gt; hyper_serde::Ser&lt;'a, T&gt;: serde::Serialize, &gt;+ T: MallocSizeOf, &gt;+{ &gt; fn size_of(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; self.0.size_of(ops) &gt; } &gt; } &gt; &gt; // Placeholder for unique case where internals of Sender cannot be measured. &gt; // malloc size of is 0 macro complains about type supplied! &gt; impl&lt;T&gt; MallocSizeOf for std::sync::mpsc::Sender&lt;T&gt; { &gt;@@ -1000,17 +1039,17 @@ impl MallocSizeOf for hyper::status::StatusCode { &gt; _ =&gt; 0, &gt; } &gt; } &gt; } &gt; &gt; /// Measurable that defers to inner value and used to verify MallocSizeOf implementation in a &gt; /// struct. &gt; #[derive(Clone)] &gt;-pub struct Measurable&lt;T: MallocSizeOf&gt; (pub T); &gt;+pub struct Measurable&lt;T: MallocSizeOf&gt;(pub T); &gt; &gt; impl&lt;T: MallocSizeOf&gt; Deref for Measurable&lt;T&gt; { &gt; type Target = T; &gt; &gt; fn deref(&amp;self) -&gt; &amp;T { &gt; &amp;self.0 &gt; } &gt; } &gt;diff --git a/servo/components/malloc_size_of_derive/lib.rs b/servo/components/malloc_size_of_derive/lib.rs &gt;index 20e9225277ee..042103a98781 100644 &gt;--- a/servo/components/malloc_size_of_derive/lib.rs &gt;+++ b/servo/components/malloc_size_of_derive/lib.rs &gt;@@ -6,35 +6,46 @@ &gt; // http://www.apache.org/licenses/LICENSE-2.0&gt; or the MIT license &gt; // &lt;LICENSE-MIT or http://opensource.org/licenses/MIT&gt;, at your &gt; // option. This file may not be copied, modified, or distributed &gt; // except according to those terms. &gt; &gt; //! A crate for deriving the MallocSizeOf trait. &gt; &gt; extern crate quote; &gt;-#[macro_use] extern crate syn; &gt;-#[macro_use] extern crate synstructure; &gt;+#[macro_use] &gt;+extern crate syn; &gt;+#[macro_use] &gt;+extern crate synstructure; &gt; &gt; #[cfg(not(test))] &gt; decl_derive!([MallocSizeOf, attributes(ignore_malloc_size_of)] =&gt; malloc_size_of_derive); &gt; &gt; fn malloc_size_of_derive(s: synstructure::Structure) -&gt; quote::Tokens { &gt; let match_body = s.each(|binding| { &gt;- let ignore = binding.ast().attrs.iter().any(|attr| match attr.interpret_meta().unwrap() { &gt;- syn::Meta::Word(ref ident) | &gt;- syn::Meta::List(syn::MetaList { ref ident, .. }) if ident == "ignore_malloc_size_of" =&gt; { &gt;- panic!("#[ignore_malloc_size_of] should have an explanation, \ &gt;- e.g. #[ignore_malloc_size_of = \"because reasons\"]"); &gt;- } &gt;- syn::Meta::NameValue(syn::MetaNameValue { ref ident, .. }) if ident == "ignore_malloc_size_of" =&gt; { &gt;- true &gt;- } &gt;- _ =&gt; false, &gt;- }); &gt;+ let ignore = binding &gt;+ .ast() &gt;+ .attrs &gt;+ .iter() &gt;+ .any(|attr| match attr.interpret_meta().unwrap() { &gt;+ syn::Meta::Word(ref ident) | syn::Meta::List(syn::MetaList { ref ident, .. }) &gt;+ if ident == "ignore_malloc_size_of" =&gt; &gt;+ { &gt;+ panic!( &gt;+ "#[ignore_malloc_size_of] should have an explanation, \ &gt;+ e.g. #[ignore_malloc_size_of = \"because reasons\"]" &gt;+ ); &gt;+ } &gt;+ syn::Meta::NameValue(syn::MetaNameValue { ref ident, .. }) &gt;+ if ident == "ignore_malloc_size_of" =&gt; &gt;+ { &gt;+ true &gt;+ } &gt;+ _ =&gt; false, &gt;+ }); &gt; if ignore { &gt; None &gt; } else if let syn::Type::Array(..) = binding.ast().ty { &gt; Some(quote! { &gt; for item in #binding.iter() { &gt; sum += ::malloc_size_of::MallocSizeOf::size_of(item, ops); &gt; } &gt; }) &gt;@@ -46,17 +57,19 @@ fn malloc_size_of_derive(s: synstructure::Structure) -&gt; quote::Tokens { &gt; }); &gt; &gt; let ast = s.ast(); &gt; let name = &amp;ast.ident; &gt; let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); &gt; let mut where_clause = where_clause.unwrap_or(&amp;parse_quote!(where)).clone(); &gt; for param in ast.generics.type_params() { &gt; let ident = param.ident; &gt;- where_clause.predicates.push(parse_quote!(#ident: ::malloc_size_of::MallocSizeOf)); &gt;+ where_clause &gt;+ .predicates &gt;+ .push(parse_quote!(#ident: ::malloc_size_of::MallocSizeOf)); &gt; } &gt; &gt; let tokens = quote! { &gt; impl #impl_generics ::malloc_size_of::MallocSizeOf for #name #ty_generics #where_clause { &gt; #[inline] &gt; #[allow(unused_variables, unused_mut, unreachable_code)] &gt; fn size_of(&amp;self, ops: &amp;mut ::malloc_size_of::MallocSizeOfOps) -&gt; usize { &gt; let mut sum = 0; &gt;@@ -68,28 +81,33 @@ fn malloc_size_of_derive(s: synstructure::Structure) -&gt; quote::Tokens { &gt; } &gt; }; &gt; &gt; tokens &gt; } &gt; &gt; #[test] &gt; fn test_struct() { &gt;- let source = &gt;- syn::parse_str("struct Foo&lt;T&gt; { bar: Bar, baz: T, #[ignore_malloc_size_of = \"\"] z: Arc&lt;T&gt; }").unwrap(); &gt;+ let source = syn::parse_str( &gt;+ "struct Foo&lt;T&gt; { bar: Bar, baz: T, #[ignore_malloc_size_of = \"\"] z: Arc&lt;T&gt; }", &gt;+ ).unwrap(); &gt; let source = synstructure::Structure::new(&amp;source); &gt; &gt; let expanded = malloc_size_of_derive(source).to_string(); &gt; let mut no_space = expanded.replace(" ", ""); &gt; macro_rules! match_count { &gt; ($e: expr, $count: expr) =&gt; { &gt;- assert_eq!(no_space.matches(&amp;$e.replace(" ", "")).count(), $count, &gt;- "counting occurences of {:?} in {:?} (whitespace-insensitive)", &gt;- $e, expanded) &gt;- } &gt;+ assert_eq!( &gt;+ no_space.matches(&amp;$e.replace(" ", "")).count(), &gt;+ $count, &gt;+ "counting occurences of {:?} in {:?} (whitespace-insensitive)", &gt;+ $e, &gt;+ expanded &gt;+ ) &gt;+ }; &gt; } &gt; match_count!("struct", 0); &gt; match_count!("ignore_malloc_size_of", 0); &gt; match_count!("impl&lt;T&gt; ::malloc_size_of::MallocSizeOf for Foo&lt;T&gt; where T: ::malloc_size_of::MallocSizeOf {", 1); &gt; match_count!("sum += ::malloc_size_of::MallocSizeOf::size_of(", 2); &gt; &gt; let source = syn::parse_str("struct Bar([Baz; 3]);").unwrap(); &gt; let source = synstructure::Structure::new(&amp;source); &gt;@@ -99,9 +117,8 @@ fn test_struct() { &gt; } &gt; &gt; #[should_panic(expected = "should have an explanation")] &gt; #[test] &gt; fn test_no_reason() { &gt; let input = syn::parse_str("struct A { #[ignore_malloc_size_of] b: C }").unwrap(); &gt; malloc_size_of_derive(synstructure::Structure::new(&amp;input)); &gt; } &gt;- &gt;diff --git a/servo/components/selectors/attr.rs b/servo/components/selectors/attr.rs &gt;index c0f5fe731859..ce0aa64344cf 100644 &gt;--- a/servo/components/selectors/attr.rs &gt;+++ b/servo/components/selectors/attr.rs &gt;@@ -110,26 +110,26 @@ impl AttrSelectorOperator { &gt; let e = element_attr_value.as_bytes(); &gt; let s = attr_selector_value.as_bytes(); &gt; let case = case_sensitivity; &gt; match self { &gt; AttrSelectorOperator::Equal =&gt; case.eq(e, s), &gt; AttrSelectorOperator::Prefix =&gt; e.len() &gt;= s.len() &amp;&amp; case.eq(&amp;e[..s.len()], s), &gt; AttrSelectorOperator::Suffix =&gt; { &gt; e.len() &gt;= s.len() &amp;&amp; case.eq(&amp;e[(e.len() - s.len())..], s) &gt;- }, &gt;+ } &gt; AttrSelectorOperator::Substring =&gt; { &gt; case.contains(element_attr_value, attr_selector_value) &gt;- }, &gt;+ } &gt; AttrSelectorOperator::Includes =&gt; element_attr_value &gt; .split(SELECTOR_WHITESPACE) &gt; .any(|part| case.eq(part.as_bytes(), s)), &gt; AttrSelectorOperator::DashMatch =&gt; { &gt; case.eq(e, s) || (e.get(s.len()) == Some(&amp;b'-') &amp;&amp; case.eq(&amp;e[..s.len()], s)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// The definition of whitespace per CSS Selectors Level 3 § 4. &gt; pub static SELECTOR_WHITESPACE: &amp;'static [char] = &amp;[' ', '\t', '\n', '\r', '\x0C']; &gt; &gt; #[derive(Clone, Copy, Debug, Eq, PartialEq)] &gt;@@ -141,20 +141,20 @@ pub enum ParsedCaseSensitivity { &gt; &gt; impl ParsedCaseSensitivity { &gt; pub fn to_unconditional(self, is_html_element_in_html_document: bool) -&gt; CaseSensitivity { &gt; match self { &gt; ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument &gt; if is_html_element_in_html_document =&gt; &gt; { &gt; CaseSensitivity::AsciiCaseInsensitive &gt;- }, &gt;+ } &gt; ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument =&gt; { &gt; CaseSensitivity::CaseSensitive &gt;- }, &gt;+ } &gt; ParsedCaseSensitivity::CaseSensitive =&gt; CaseSensitivity::CaseSensitive, &gt; ParsedCaseSensitivity::AsciiCaseInsensitive =&gt; CaseSensitivity::AsciiCaseInsensitive, &gt; } &gt; } &gt; } &gt; &gt; #[derive(Clone, Copy, Debug, Eq, PartialEq)] &gt; pub enum CaseSensitivity { &gt;@@ -185,12 +185,12 @@ impl CaseSensitivity { &gt; Some(haystack_slice) =&gt; haystack_slice.eq_ignore_ascii_case(n_rest), &gt; } &gt; }) &gt; } else { &gt; // any_str.contains("") == true, &gt; // though these cases should be handled with *NeverMatches and never go here. &gt; true &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/selectors/bloom.rs b/servo/components/selectors/bloom.rs &gt;index d9056665ac4d..f868fc7df165 100644 &gt;--- a/servo/components/selectors/bloom.rs &gt;+++ b/servo/components/selectors/bloom.rs &gt;@@ -313,30 +313,33 @@ fn create_and_insert_some_stuff() { &gt; for i in 0_usize..1000 { &gt; bf.insert_hash(hash_as_str(i)); &gt; } &gt; &gt; for i in 0_usize..1000 { &gt; assert!(bf.might_contain_hash(hash_as_str(i))); &gt; } &gt; &gt;- let false_positives = &gt;- (1001_usize..2000).filter(|i| bf.might_contain_hash(hash_as_str(*i))).count(); &gt;+ let false_positives = (1001_usize..2000) &gt;+ .filter(|i| bf.might_contain_hash(hash_as_str(*i))) &gt;+ .count(); &gt; &gt; assert!(false_positives &lt; 190, "{} is not &lt; 190", false_positives); // 19%. &gt; &gt; for i in 0_usize..100 { &gt; bf.remove_hash(hash_as_str(i)); &gt; } &gt; &gt; for i in 100_usize..1000 { &gt; assert!(bf.might_contain_hash(hash_as_str(i))); &gt; } &gt; &gt;- let false_positives = (0_usize..100).filter(|i| bf.might_contain_hash(hash_as_str(*i))).count(); &gt;+ let false_positives = (0_usize..100) &gt;+ .filter(|i| bf.might_contain_hash(hash_as_str(*i))) &gt;+ .count(); &gt; &gt; assert!(false_positives &lt; 20, "{} is not &lt; 20", false_positives); // 20%. &gt; &gt; bf.clear(); &gt; &gt; for i in 0_usize..2000 { &gt; assert!(!bf.might_contain_hash(hash_as_str(i))); &gt; } &gt;diff --git a/servo/components/selectors/builder.rs b/servo/components/selectors/builder.rs &gt;index 29ac822fa033..c6a3bb350540 100644 &gt;--- a/servo/components/selectors/builder.rs &gt;+++ b/servo/components/selectors/builder.rs &gt;@@ -18,17 +18,17 @@ &gt; //! easy-to-use API for the parser. &gt; &gt; use parser::{Combinator, Component, SelectorImpl}; &gt; use servo_arc::{Arc, HeaderWithLength, ThinArc}; &gt; use sink::Push; &gt; use smallvec::{self, SmallVec}; &gt; use std::cmp; &gt; use std::iter; &gt;-use std::ops::{AddAssign, Add}; &gt;+use std::ops::{Add, AddAssign}; &gt; use std::ptr; &gt; use std::slice; &gt; &gt; /// Top-level SelectorBuilder struct. This should be stack-allocated by the &gt; /// consumer and never moved (because it contains a lot of inline data that &gt; /// would be slow to memmov). &gt; /// &gt; /// After instantation, callers may call the push_simple_selector() and &gt;@@ -156,18 +156,19 @@ impl&lt;Impl: SelectorImpl&gt; SelectorBuilder&lt;Impl&gt; { &gt; struct SelectorBuilderIter&lt;'a, Impl: SelectorImpl&gt; { &gt; current_simple_selectors: slice::Iter&lt;'a, Component&lt;Impl&gt;&gt;, &gt; rest_of_simple_selectors: &amp;'a [Component&lt;Impl&gt;], &gt; combinators: iter::Rev&lt;smallvec::Drain&lt;'a, (Combinator, usize)&gt;&gt;, &gt; } &gt; &gt; impl&lt;'a, Impl: SelectorImpl&gt; ExactSizeIterator for SelectorBuilderIter&lt;'a, Impl&gt; { &gt; fn len(&amp;self) -&gt; usize { &gt;- self.current_simple_selectors.len() + self.rest_of_simple_selectors.len() + &gt;- self.combinators.len() &gt;+ self.current_simple_selectors.len() &gt;+ + self.rest_of_simple_selectors.len() &gt;+ + self.combinators.len() &gt; } &gt; } &gt; &gt; impl&lt;'a, Impl: SelectorImpl&gt; Iterator for SelectorBuilderIter&lt;'a, Impl&gt; { &gt; type Item = Component&lt;Impl&gt;; &gt; #[inline(always)] &gt; fn next(&amp;mut self) -&gt; Option&lt;Self::Item&gt; { &gt; if let Some(simple_selector_ref) = self.current_simple_selectors.next() { &gt;@@ -223,17 +224,16 @@ const MAX_10BIT: u32 = (1u32 &lt;&lt; 10) - 1; &gt; &gt; #[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] &gt; struct Specificity { &gt; id_selectors: u32, &gt; class_like_selectors: u32, &gt; element_selectors: u32, &gt; } &gt; &gt;- &gt; impl AddAssign for Specificity { &gt; #[inline] &gt; fn add_assign(&amp;mut self, rhs: Self) { &gt; self.id_selectors += rhs.id_selectors; &gt; self.class_like_selectors += rhs.class_like_selectors; &gt; self.element_selectors += rhs.element_selectors; &gt; } &gt; } &gt;@@ -270,19 +270,19 @@ impl From&lt;u32&gt; for Specificity { &gt; element_selectors: value &amp; MAX_10BIT, &gt; } &gt; } &gt; } &gt; &gt; impl From&lt;Specificity&gt; for u32 { &gt; #[inline] &gt; fn from(specificity: Specificity) -&gt; u32 { &gt;- cmp::min(specificity.id_selectors, MAX_10BIT) &lt;&lt; 20 | &gt;- cmp::min(specificity.class_like_selectors, MAX_10BIT) &lt;&lt; 10 | &gt;- cmp::min(specificity.element_selectors, MAX_10BIT) &gt;+ cmp::min(specificity.id_selectors, MAX_10BIT) &lt;&lt; 20 &gt;+ | cmp::min(specificity.class_like_selectors, MAX_10BIT) &lt;&lt; 10 &gt;+ | cmp::min(specificity.element_selectors, MAX_10BIT) &gt; } &gt; } &gt; &gt; fn specificity&lt;Impl&gt;(builder: &amp;SelectorBuilder&lt;Impl&gt;, iter: slice::Iter&lt;Component&lt;Impl&gt;&gt;) -&gt; u32 &gt; where &gt; Impl: SelectorImpl, &gt; { &gt; complex_selector_specificity(builder, iter).into() &gt;@@ -301,75 +301,74 @@ where &gt; specificity: &amp;mut Specificity, &gt; ) where &gt; Impl: SelectorImpl, &gt; { &gt; match *simple_selector { &gt; Component::Combinator(ref combinator) =&gt; { &gt; unreachable!( &gt; "Found combinator {:?} in simple selectors vector? {:?}", &gt;- combinator, &gt;- builder, &gt;+ combinator, builder, &gt; ); &gt; } &gt; Component::PseudoElement(..) | Component::LocalName(..) =&gt; { &gt; specificity.element_selectors += 1 &gt;- }, &gt;+ } &gt; Component::Slotted(ref selector) =&gt; { &gt; specificity.element_selectors += 1; &gt; // Note that due to the way ::slotted works we only compete with &gt; // other ::slotted rules, so the above rule doesn't really &gt; // matter, but we do it still for consistency with other &gt; // pseudo-elements. &gt; // &gt; // See: https://github.com/w3c/csswg-drafts/issues/1915 &gt; *specificity += Specificity::from(selector.specificity()); &gt;- }, &gt;+ } &gt; Component::Host(ref selector) =&gt; { &gt; specificity.class_like_selectors += 1; &gt; if let Some(ref selector) = *selector { &gt; // See: https://github.com/w3c/csswg-drafts/issues/1915 &gt; *specificity += Specificity::from(selector.specificity()); &gt; } &gt; } &gt; Component::ID(..) =&gt; { &gt; specificity.id_selectors += 1; &gt;- }, &gt;- Component::Class(..) | &gt;- Component::AttributeInNoNamespace { .. } | &gt;- Component::AttributeInNoNamespaceExists { .. } | &gt;- Component::AttributeOther(..) | &gt;- Component::FirstChild | &gt;- Component::LastChild | &gt;- Component::OnlyChild | &gt;- Component::Root | &gt;- Component::Empty | &gt;- Component::Scope | &gt;- Component::NthChild(..) | &gt;- Component::NthLastChild(..) | &gt;- Component::NthOfType(..) | &gt;- Component::NthLastOfType(..) | &gt;- Component::FirstOfType | &gt;- Component::LastOfType | &gt;- Component::OnlyOfType | &gt;- Component::NonTSPseudoClass(..) =&gt; { &gt;+ } &gt;+ Component::Class(..) &gt;+ | Component::AttributeInNoNamespace { .. } &gt;+ | Component::AttributeInNoNamespaceExists { .. } &gt;+ | Component::AttributeOther(..) &gt;+ | Component::FirstChild &gt;+ | Component::LastChild &gt;+ | Component::OnlyChild &gt;+ | Component::Root &gt;+ | Component::Empty &gt;+ | Component::Scope &gt;+ | Component::NthChild(..) &gt;+ | Component::NthLastChild(..) &gt;+ | Component::NthOfType(..) &gt;+ | Component::NthLastOfType(..) &gt;+ | Component::FirstOfType &gt;+ | Component::LastOfType &gt;+ | Component::OnlyOfType &gt;+ | Component::NonTSPseudoClass(..) =&gt; { &gt; specificity.class_like_selectors += 1; &gt;- }, &gt;- Component::ExplicitUniversalType | &gt;- Component::ExplicitAnyNamespace | &gt;- Component::ExplicitNoNamespace | &gt;- Component::DefaultNamespace(..) | &gt;- Component::Namespace(..) =&gt; { &gt;+ } &gt;+ Component::ExplicitUniversalType &gt;+ | Component::ExplicitAnyNamespace &gt;+ | Component::ExplicitNoNamespace &gt;+ | Component::DefaultNamespace(..) &gt;+ | Component::Namespace(..) =&gt; { &gt; // Does not affect specificity &gt;- }, &gt;+ } &gt; Component::Negation(ref negated) =&gt; { &gt; for ss in negated.iter() { &gt; simple_selector_specificity(builder, &amp;ss, specificity); &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; let mut specificity = Default::default(); &gt; for simple_selector in &amp;mut iter { &gt; simple_selector_specificity(builder, &amp;simple_selector, &amp;mut specificity); &gt; } &gt; specificity &gt;diff --git a/servo/components/selectors/context.rs b/servo/components/selectors/context.rs &gt;index 9d1bfeee346d..f0ac93caa9eb 100644 &gt;--- a/servo/components/selectors/context.rs &gt;+++ b/servo/components/selectors/context.rs &gt;@@ -48,27 +48,27 @@ pub enum VisitedHandlingMode { &gt; RelevantLinkVisited, &gt; } &gt; &gt; impl VisitedHandlingMode { &gt; #[inline] &gt; pub fn matches_visited(&amp;self) -&gt; bool { &gt; matches!( &gt; *self, &gt;- VisitedHandlingMode::RelevantLinkVisited | &gt;- VisitedHandlingMode::AllLinksVisitedAndUnvisited &gt;+ VisitedHandlingMode::RelevantLinkVisited &gt;+ | VisitedHandlingMode::AllLinksVisitedAndUnvisited &gt; ) &gt; } &gt; &gt; #[inline] &gt; pub fn matches_unvisited(&amp;self) -&gt; bool { &gt; matches!( &gt; *self, &gt;- VisitedHandlingMode::AllLinksUnvisited | &gt;- VisitedHandlingMode::AllLinksVisitedAndUnvisited &gt;+ VisitedHandlingMode::AllLinksUnvisited &gt;+ | VisitedHandlingMode::AllLinksVisitedAndUnvisited &gt; ) &gt; } &gt; } &gt; &gt; /// Which quirks mode is this document in. &gt; /// &gt; /// See: https://quirks.spec.whatwg.org/ &gt; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] &gt;diff --git a/servo/components/selectors/matching.rs b/servo/components/selectors/matching.rs &gt;index 1fe54b217d23..5e643752ada8 100644 &gt;--- a/servo/components/selectors/matching.rs &gt;+++ b/servo/components/selectors/matching.rs &gt;@@ -46,19 +46,19 @@ bitflags! { &gt; impl ElementSelectorFlags { &gt; /// Returns the subset of flags that apply to the element. &gt; pub fn for_self(self) -&gt; ElementSelectorFlags { &gt; self &amp; (ElementSelectorFlags::HAS_EMPTY_SELECTOR) &gt; } &gt; &gt; /// Returns the subset of flags that apply to the parent. &gt; pub fn for_parent(self) -&gt; ElementSelectorFlags { &gt;- self &amp; (ElementSelectorFlags::HAS_SLOW_SELECTOR | &gt;- ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS | &gt;- ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) &gt;+ self &amp; (ElementSelectorFlags::HAS_SLOW_SELECTOR &gt;+ | ElementSelectorFlags::HAS_SLOW_SELECTOR_LATER_SIBLINGS &gt;+ | ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR) &gt; } &gt; } &gt; &gt; /// Holds per-compound-selector data. &gt; struct LocalMatchingContext&lt;'a, 'b: 'a, Impl: SelectorImpl&gt; { &gt; shared: &amp;'a mut MatchingContext&lt;'b, Impl&gt;, &gt; matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk, &gt; } &gt;@@ -255,22 +255,21 @@ where &gt; from_offset += 1; &gt; } &gt; &gt; debug_assert!(from_offset &gt;= 1); &gt; debug_assert!(from_offset &lt;= selector.len()); &gt; &gt; let iter = selector.iter_from(selector.len() - from_offset); &gt; debug_assert!( &gt;- iter.clone().next().is_some() || &gt;- (from_offset != selector.len() &amp;&amp; &gt;- matches!( &gt;- selector.combinator_at_parse_order(from_offset), &gt;- Combinator::SlotAssignment | Combinator::PseudoElement &gt;- )), &gt;+ iter.clone().next().is_some() &gt;+ || (from_offset != selector.len() &amp;&amp; matches!( &gt;+ selector.combinator_at_parse_order(from_offset), &gt;+ Combinator::SlotAssignment | Combinator::PseudoElement &gt;+ )), &gt; "Got the math wrong: {:?} | {:?} | {} {}", &gt; selector, &gt; selector.iter_raw_match_order().as_slice(), &gt; from_offset, &gt; start_offset &gt; ); &gt; &gt; for component in iter { &gt;@@ -306,24 +305,24 @@ where &gt; // Consume the pseudo. &gt; match *iter.next().unwrap() { &gt; Component::PseudoElement(ref pseudo) =&gt; { &gt; if let Some(ref f) = context.pseudo_element_matching_fn { &gt; if !f(pseudo) { &gt; return false; &gt; } &gt; } &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; debug_assert!( &gt; false, &gt; "Used MatchingMode::ForStatelessPseudoElement \ &gt; in a non-pseudo selector" &gt; ); &gt;- }, &gt;+ } &gt; } &gt; &gt; // The only other parser-allowed Component in this sequence is a state &gt; // class. We just don't match in that case. &gt; if let Some(s) = iter.next() { &gt; debug_assert!( &gt; matches!(*s, Component::NonTSPseudoClass(..)), &gt; "Someone messed up pseudo-element parsing" &gt;@@ -358,42 +357,42 @@ fn matches_hover_and_active_quirk&lt;Impl: SelectorImpl&gt;( &gt; } &gt; &gt; if context.is_nested() { &gt; return MatchesHoverAndActiveQuirk::No; &gt; } &gt; &gt; // This compound selector had a pseudo-element to the right that we &gt; // intentionally skipped. &gt;- if rightmost == Rightmost::Yes &amp;&amp; &gt;- context.matching_mode() == MatchingMode::ForStatelessPseudoElement &gt;+ if rightmost == Rightmost::Yes &gt;+ &amp;&amp; context.matching_mode() == MatchingMode::ForStatelessPseudoElement &gt; { &gt; return MatchesHoverAndActiveQuirk::No; &gt; } &gt; &gt; let all_match = selector_iter.clone().all(|simple| match *simple { &gt;- Component::LocalName(_) | &gt;- Component::AttributeInNoNamespaceExists { .. } | &gt;- Component::AttributeInNoNamespace { .. } | &gt;- Component::AttributeOther(_) | &gt;- Component::ID(_) | &gt;- Component::Class(_) | &gt;- Component::PseudoElement(_) | &gt;- Component::Negation(_) | &gt;- Component::FirstChild | &gt;- Component::LastChild | &gt;- Component::OnlyChild | &gt;- Component::Empty | &gt;- Component::NthChild(_, _) | &gt;- Component::NthLastChild(_, _) | &gt;- Component::NthOfType(_, _) | &gt;- Component::NthLastOfType(_, _) | &gt;- Component::FirstOfType | &gt;- Component::LastOfType | &gt;- Component::OnlyOfType =&gt; false, &gt;+ Component::LocalName(_) &gt;+ | Component::AttributeInNoNamespaceExists { .. } &gt;+ | Component::AttributeInNoNamespace { .. } &gt;+ | Component::AttributeOther(_) &gt;+ | Component::ID(_) &gt;+ | Component::Class(_) &gt;+ | Component::PseudoElement(_) &gt;+ | Component::Negation(_) &gt;+ | Component::FirstChild &gt;+ | Component::LastChild &gt;+ | Component::OnlyChild &gt;+ | Component::Empty &gt;+ | Component::NthChild(_, _) &gt;+ | Component::NthLastChild(_, _) &gt;+ | Component::NthOfType(_, _) &gt;+ | Component::NthLastOfType(_, _) &gt;+ | Component::FirstOfType &gt;+ | Component::LastOfType &gt;+ | Component::OnlyOfType =&gt; false, &gt; Component::NonTSPseudoClass(ref pseudo_class) =&gt; pseudo_class.is_active_or_hover(), &gt; _ =&gt; true, &gt; }); &gt; &gt; if all_match { &gt; MatchesHoverAndActiveQuirk::Yes &gt; } else { &gt; MatchesHoverAndActiveQuirk::No &gt;@@ -415,17 +414,17 @@ fn next_element_for_combinator&lt;E&gt;( &gt; where &gt; E: Element, &gt; { &gt; match combinator { &gt; Combinator::NextSibling | Combinator::LaterSibling =&gt; element.prev_sibling_element(), &gt; Combinator::Child | Combinator::Descendant =&gt; { &gt; match element.parent_element() { &gt; Some(e) =&gt; return Some(e), &gt;- None =&gt; {}, &gt;+ None =&gt; {} &gt; } &gt; &gt; if !element.parent_node_is_shadow_root() { &gt; return None; &gt; } &gt; &gt; // https://drafts.csswg.org/css-scoping/#host-element-in-tree: &gt; // &gt;@@ -443,25 +442,25 @@ where &gt; // Since we know that the parent is a shadow root, we necessarily &gt; // are in a shadow tree of the host, and the next selector will only &gt; // match if the selector is a featureless :host selector. &gt; if !selector.clone().is_featureless_host_selector() { &gt; return None; &gt; } &gt; &gt; element.containing_shadow_host() &gt;- }, &gt;+ } &gt; Combinator::SlotAssignment =&gt; { &gt; debug_assert!( &gt; element &gt; .assigned_slot() &gt; .map_or(true, |s| s.is_html_slot_element()) &gt; ); &gt; element.assigned_slot() &gt;- }, &gt;+ } &gt; Combinator::PseudoElement =&gt; element.pseudo_element_originating_element(), &gt; } &gt; } &gt; &gt; fn matches_complex_selector_internal&lt;E, F&gt;( &gt; mut selector_iter: SelectorIter&lt;E::Impl&gt;, &gt; element: &amp;E, &gt; context: &amp;mut MatchingContext&lt;E::Impl&gt;, &gt;@@ -500,21 +499,21 @@ where &gt; let combinator = match combinator { &gt; None =&gt; return SelectorMatchingResult::Matched, &gt; Some(c) =&gt; c, &gt; }; &gt; &gt; let candidate_not_found = match combinator { &gt; Combinator::NextSibling | Combinator::LaterSibling =&gt; { &gt; SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant &gt;- }, &gt;- Combinator::Child | &gt;- Combinator::Descendant | &gt;- Combinator::SlotAssignment | &gt;- Combinator::PseudoElement =&gt; SelectorMatchingResult::NotMatchedGlobally, &gt;+ } &gt;+ Combinator::Child &gt;+ | Combinator::Descendant &gt;+ | Combinator::SlotAssignment &gt;+ | Combinator::PseudoElement =&gt; SelectorMatchingResult::NotMatchedGlobally, &gt; }; &gt; &gt; let mut next_element = next_element_for_combinator(element, combinator, &amp;selector_iter); &gt; &gt; // Stop matching :visited as soon as we find a link, or a combinator for &gt; // something that isn't an ancestor. &gt; let mut visited_handling = if element.is_link() || combinator.is_sibling() { &gt; VisitedHandlingMode::AllLinksUnvisited &gt;@@ -535,46 +534,46 @@ where &gt; context, &gt; flags_setter, &gt; Rightmost::No, &gt; ) &gt; }); &gt; &gt; match (result, combinator) { &gt; // Return the status immediately. &gt;- (SelectorMatchingResult::Matched, _) | &gt;- (SelectorMatchingResult::NotMatchedGlobally, _) | &gt;- (_, Combinator::NextSibling) =&gt; { &gt;+ (SelectorMatchingResult::Matched, _) &gt;+ | (SelectorMatchingResult::NotMatchedGlobally, _) &gt;+ | (_, Combinator::NextSibling) =&gt; { &gt; return result; &gt;- }, &gt;+ } &gt; &gt; // Upgrade the failure status to &gt; // NotMatchedAndRestartFromClosestDescendant. &gt; (_, Combinator::PseudoElement) | (_, Combinator::Child) =&gt; { &gt; return SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant; &gt;- }, &gt;+ } &gt; &gt; // If the failure status is &gt; // NotMatchedAndRestartFromClosestDescendant and combinator is &gt; // Combinator::LaterSibling, give up this Combinator::LaterSibling &gt; // matching and restart from the closest descendant combinator. &gt; ( &gt; SelectorMatchingResult::NotMatchedAndRestartFromClosestDescendant, &gt; Combinator::LaterSibling, &gt; ) =&gt; { &gt; return result; &gt;- }, &gt;+ } &gt; &gt; // The Combinator::Descendant combinator and the status is &gt; // NotMatchedAndRestartFromClosestLaterSibling or &gt; // NotMatchedAndRestartFromClosestDescendant, or the &gt; // Combinator::LaterSibling combinator and the status is &gt; // NotMatchedAndRestartFromClosestDescendant, we can continue to &gt; // matching on the next candidate element. &gt;- _ =&gt; {}, &gt;+ _ =&gt; {} &gt; } &gt; &gt; if element.is_link() { &gt; visited_handling = VisitedHandlingMode::AllLinksUnvisited; &gt; } &gt; &gt; next_element = next_element_for_combinator(&amp;element, combinator, &amp;selector_iter); &gt; } &gt;@@ -658,50 +657,51 @@ where &gt; F: FnMut(&amp;E, ElementSelectorFlags), &gt; { &gt; debug_assert!(context.shared.is_nested() || !context.shared.in_negation()); &gt; &gt; match *selector { &gt; Component::Combinator(_) =&gt; unreachable!(), &gt; Component::Slotted(ref selector) =&gt; { &gt; // &lt;slots&gt; are never flattened tree slottables. &gt;- !element.is_html_slot_element() &amp;&amp; element.assigned_slot().is_some() &amp;&amp; &gt;- context.shared.nest(|context| { &gt;+ !element.is_html_slot_element() &amp;&amp; element.assigned_slot().is_some() &amp;&amp; context &gt;+ .shared &gt;+ .nest(|context| { &gt; matches_complex_selector(selector.iter(), element, context, flags_setter) &gt; }) &gt;- }, &gt;+ } &gt; Component::PseudoElement(ref pseudo) =&gt; { &gt; element.match_pseudo_element(pseudo, context.shared) &gt;- }, &gt;+ } &gt; Component::LocalName(ref local_name) =&gt; matches_local_name(element, local_name), &gt; Component::ExplicitUniversalType | Component::ExplicitAnyNamespace =&gt; true, &gt; Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) =&gt; { &gt; element.namespace() == url.borrow() &gt;- }, &gt;+ } &gt; Component::ExplicitNoNamespace =&gt; { &gt; let ns = ::parser::namespace_empty_string::&lt;E::Impl&gt;(); &gt; element.namespace() == ns.borrow() &gt;- }, &gt;+ } &gt; Component::ID(ref id) =&gt; { &gt; element.has_id(id, context.shared.classes_and_ids_case_sensitivity()) &gt;- }, &gt;+ } &gt; Component::Class(ref class) =&gt; { &gt; element.has_class(class, context.shared.classes_and_ids_case_sensitivity()) &gt;- }, &gt;+ } &gt; Component::AttributeInNoNamespaceExists { &gt; ref local_name, &gt; ref local_name_lower, &gt; } =&gt; { &gt; let is_html = element.is_html_element_in_html_document(); &gt; element.attr_matches( &gt; &amp;NamespaceConstraint::Specific(&amp;::parser::namespace_empty_string::&lt;E::Impl&gt;()), &gt; select_name(is_html, local_name, local_name_lower), &gt; &amp;AttrSelectorOperation::Exists, &gt; ) &gt;- }, &gt;+ } &gt; Component::AttributeInNoNamespace { &gt; ref local_name, &gt; ref value, &gt; operator, &gt; case_sensitivity, &gt; never_matches, &gt; } =&gt; { &gt; if never_matches { &gt;@@ -712,17 +712,17 @@ where &gt; &amp;NamespaceConstraint::Specific(&amp;::parser::namespace_empty_string::&lt;E::Impl&gt;()), &gt; local_name, &gt; &amp;AttrSelectorOperation::WithValue { &gt; operator: operator, &gt; case_sensitivity: case_sensitivity.to_unconditional(is_html), &gt; expected_value: value, &gt; }, &gt; ) &gt;- }, &gt;+ } &gt; Component::AttributeOther(ref attr_sel) =&gt; { &gt; if attr_sel.never_matches { &gt; return false; &gt; } &gt; let is_html = element.is_html_element_in_html_document(); &gt; let empty_string; &gt; let namespace = match attr_sel.namespace() { &gt; Some(ns) =&gt; ns, &gt;@@ -742,74 +742,75 @@ where &gt; ref expected_value, &gt; } =&gt; AttrSelectorOperation::WithValue { &gt; operator: operator, &gt; case_sensitivity: case_sensitivity.to_unconditional(is_html), &gt; expected_value: expected_value, &gt; }, &gt; }, &gt; ) &gt;- }, &gt;+ } &gt; Component::NonTSPseudoClass(ref pc) =&gt; { &gt;- if context.matches_hover_and_active_quirk == MatchesHoverAndActiveQuirk::Yes &amp;&amp; &gt;- !context.shared.is_nested() &amp;&amp; pc.is_active_or_hover() &amp;&amp; &gt;- !element.is_link() &gt;+ if context.matches_hover_and_active_quirk == MatchesHoverAndActiveQuirk::Yes &gt;+ &amp;&amp; !context.shared.is_nested() &gt;+ &amp;&amp; pc.is_active_or_hover() &gt;+ &amp;&amp; !element.is_link() &gt; { &gt; return false; &gt; } &gt; &gt; element.match_non_ts_pseudo_class(pc, &amp;mut context.shared, flags_setter) &gt;- }, &gt;+ } &gt; Component::FirstChild =&gt; matches_first_child(element, flags_setter), &gt; Component::LastChild =&gt; matches_last_child(element, flags_setter), &gt; Component::OnlyChild =&gt; { &gt; matches_first_child(element, flags_setter) &amp;&amp; matches_last_child(element, flags_setter) &gt;- }, &gt;+ } &gt; Component::Root =&gt; element.is_root(), &gt; Component::Empty =&gt; { &gt; flags_setter(element, ElementSelectorFlags::HAS_EMPTY_SELECTOR); &gt; element.is_empty() &gt;- }, &gt;+ } &gt; Component::Host(ref selector) =&gt; { &gt; context &gt; .shared &gt; .shadow_host() &gt;- .map_or(false, |host| host == element.opaque()) &amp;&amp; &gt;- selector.as_ref().map_or(true, |selector| { &gt;+ .map_or(false, |host| host == element.opaque()) &gt;+ &amp;&amp; selector.as_ref().map_or(true, |selector| { &gt; context.shared.nest(|context| { &gt; matches_complex_selector(selector.iter(), element, context, flags_setter) &gt; }) &gt; }) &gt;- }, &gt;+ } &gt; Component::Scope =&gt; match context.shared.scope_element { &gt; Some(ref scope_element) =&gt; element.opaque() == *scope_element, &gt; None =&gt; element.is_root(), &gt; }, &gt; Component::NthChild(a, b) =&gt; { &gt; matches_generic_nth_child(element, context, a, b, false, false, flags_setter) &gt;- }, &gt;+ } &gt; Component::NthLastChild(a, b) =&gt; { &gt; matches_generic_nth_child(element, context, a, b, false, true, flags_setter) &gt;- }, &gt;+ } &gt; Component::NthOfType(a, b) =&gt; { &gt; matches_generic_nth_child(element, context, a, b, true, false, flags_setter) &gt;- }, &gt;+ } &gt; Component::NthLastOfType(a, b) =&gt; { &gt; matches_generic_nth_child(element, context, a, b, true, true, flags_setter) &gt;- }, &gt;+ } &gt; Component::FirstOfType =&gt; { &gt; matches_generic_nth_child(element, context, 0, 1, true, false, flags_setter) &gt;- }, &gt;+ } &gt; Component::LastOfType =&gt; { &gt; matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter) &gt;- }, &gt;+ } &gt; Component::OnlyOfType =&gt; { &gt;- matches_generic_nth_child(element, context, 0, 1, true, false, flags_setter) &amp;&amp; &gt;- matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter) &gt;- }, &gt;+ matches_generic_nth_child(element, context, 0, 1, true, false, flags_setter) &gt;+ &amp;&amp; matches_generic_nth_child(element, context, 0, 1, true, true, flags_setter) &gt;+ } &gt; Component::Negation(ref negated) =&gt; context.shared.nest_for_negation(|context| { &gt; let mut local_context = LocalMatchingContext { &gt; matches_hover_and_active_quirk: MatchesHoverAndActiveQuirk::No, &gt; shared: context, &gt; }; &gt; !negated &gt; .iter() &gt; .all(|ss| matches_simple_selector(ss, element, &amp;mut local_context, flags_setter)) &gt;diff --git a/servo/components/selectors/parser.rs b/servo/components/selectors/parser.rs &gt;index d0f98cde57bb..5b2d0c746604 100644 &gt;--- a/servo/components/selectors/parser.rs &gt;+++ b/servo/components/selectors/parser.rs &gt;@@ -3,20 +3,20 @@ &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; use attr::{AttrSelectorOperator, AttrSelectorWithOptionalNamespace}; &gt; use attr::{NamespaceConstraint, ParsedAttrSelectorOperation}; &gt; use attr::{ParsedCaseSensitivity, SELECTOR_WHITESPACE}; &gt; use bloom::BLOOM_HASH_MASK; &gt; use builder::{SelectorBuilder, SpecificityAndFlags}; &gt; use context::QuirksMode; &gt;+use cssparser::{parse_nth, serialize_identifier}; &gt; use cssparser::{BasicParseError, BasicParseErrorKind, ParseError, ParseErrorKind}; &gt; use cssparser::{CowRcStr, Delimiter, SourceLocation}; &gt; use cssparser::{CssStringWriter, Parser as CssParser, ToCss, Token}; &gt;-use cssparser::{parse_nth, serialize_identifier}; &gt; use precomputed_hash::PrecomputedHash; &gt; use servo_arc::ThinArc; &gt; use sink::Push; &gt; use smallvec::SmallVec; &gt; use std::borrow::{Borrow, Cow}; &gt; use std::fmt::{self, Debug, Display, Write}; &gt; use std::iter::Rev; &gt; use std::slice; &gt;@@ -226,19 +226,20 @@ impl&lt;Impl: SelectorImpl&gt; SelectorList&lt;Impl&gt; { &gt; parser: &amp;P, &gt; input: &amp;mut CssParser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i, P::Error&gt;&gt; &gt; where &gt; P: Parser&lt;'i, Impl = Impl&gt;, &gt; { &gt; let mut values = SmallVec::new(); &gt; loop { &gt;- values &gt;- .push(input &gt;- .parse_until_before(Delimiter::Comma, |input| parse_selector(parser, input))?); &gt;+ values.push( &gt;+ input &gt;+ .parse_until_before(Delimiter::Comma, |input| parse_selector(parser, input))?, &gt;+ ); &gt; match input.next() { &gt; Err(_) =&gt; return Ok(SelectorList(values)), &gt; Ok(&amp;Token::Comma) =&gt; continue, &gt; Ok(_) =&gt; unreachable!(), &gt; } &gt; } &gt; } &gt; &gt;@@ -340,19 +341,19 @@ impl AncestorHashes { &gt; &gt; AncestorHashes { &gt; packed_hashes: [hashes[0], hashes[1], hashes[2]], &gt; } &gt; } &gt; &gt; /// Returns the fourth hash, reassembled from parts. &gt; pub fn fourth_hash(&amp;self) -&gt; u32 { &gt;- ((self.packed_hashes[0] &amp; 0xff000000) &gt;&gt; 24) | &gt;- ((self.packed_hashes[1] &amp; 0xff000000) &gt;&gt; 16) | &gt;- ((self.packed_hashes[2] &amp; 0xff000000) &gt;&gt; 8) &gt;+ ((self.packed_hashes[0] &amp; 0xff000000) &gt;&gt; 24) &gt;+ | ((self.packed_hashes[1] &amp; 0xff000000) &gt;&gt; 16) &gt;+ | ((self.packed_hashes[2] &amp; 0xff000000) &gt;&gt; 8) &gt; } &gt; } &gt; &gt; impl&lt;Impl: SelectorImpl&gt; Visit for Selector&lt;Impl&gt; &gt; where &gt; Impl::NonTSPseudoClass: Visit&lt;Impl = Impl&gt;, &gt; { &gt; type Impl = Impl; &gt;@@ -399,80 +400,81 @@ where &gt; return false; &gt; } &gt; &gt; match *self { &gt; Slotted(ref selector) =&gt; { &gt; if !selector.visit(visitor) { &gt; return false; &gt; } &gt;- }, &gt;+ } &gt; Host(Some(ref selector)) =&gt; { &gt; if !selector.visit(visitor) { &gt; return false; &gt; } &gt;- }, &gt;+ } &gt; Negation(ref negated) =&gt; { &gt; for component in negated.iter() { &gt; if !component.visit(visitor) { &gt; return false; &gt; } &gt; } &gt;- }, &gt;+ } &gt; &gt; AttributeInNoNamespaceExists { &gt; ref local_name, &gt; ref local_name_lower, &gt; } =&gt; { &gt; if !visitor.visit_attribute_selector( &gt; &amp;NamespaceConstraint::Specific(&amp;namespace_empty_string::&lt;Impl&gt;()), &gt; local_name, &gt; local_name_lower, &gt; ) { &gt; return false; &gt; } &gt;- }, &gt;+ } &gt; AttributeInNoNamespace { &gt; ref local_name, &gt; never_matches, &gt; .. &gt;- } if !never_matches =&gt; &gt;+ } &gt;+ if !never_matches =&gt; &gt; { &gt; if !visitor.visit_attribute_selector( &gt; &amp;NamespaceConstraint::Specific(&amp;namespace_empty_string::&lt;Impl&gt;()), &gt; local_name, &gt; local_name, &gt; ) { &gt; return false; &gt; } &gt;- }, &gt;+ } &gt; AttributeOther(ref attr_selector) if !attr_selector.never_matches =&gt; { &gt; let empty_string; &gt; let namespace = match attr_selector.namespace() { &gt; Some(ns) =&gt; ns, &gt; None =&gt; { &gt; empty_string = ::parser::namespace_empty_string::&lt;Impl&gt;(); &gt; NamespaceConstraint::Specific(&amp;empty_string) &gt; } &gt; }; &gt; if !visitor.visit_attribute_selector( &gt; &amp;namespace, &gt; &amp;attr_selector.local_name, &gt; &amp;attr_selector.local_name_lower, &gt; ) { &gt; return false; &gt; } &gt;- }, &gt;+ } &gt; &gt; NonTSPseudoClass(ref pseudo_class) =&gt; { &gt; if !pseudo_class.visit(visitor) { &gt; return false; &gt; } &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; &gt; true &gt; } &gt; } &gt; &gt; pub fn namespace_empty_string&lt;Impl: SelectorImpl&gt;() -&gt; Impl::NamespaceUrl { &gt; // Rust type’s default, not default namespace &gt;@@ -531,19 +533,20 @@ impl&lt;Impl: SelectorImpl&gt; Selector&lt;Impl&gt; { &gt; /// Whether this selector (pseudo-element part excluded) matches every element. &gt; /// &gt; /// Used for "pre-computed" pseudo-elements in components/style/stylist.rs &gt; #[inline] &gt; pub fn is_universal(&amp;self) -&gt; bool { &gt; self.iter_raw_match_order().all(|c| { &gt; matches!( &gt; *c, &gt;- Component::ExplicitUniversalType | Component::ExplicitAnyNamespace | &gt;- Component::Combinator(Combinator::PseudoElement) | &gt;- Component::PseudoElement(..) &gt;+ Component::ExplicitUniversalType &gt;+ | Component::ExplicitAnyNamespace &gt;+ | Component::Combinator(Combinator::PseudoElement) &gt;+ | Component::PseudoElement(..) &gt; ) &gt; }) &gt; } &gt; &gt; /// Returns an iterator over this selector in matching order (right-to-left). &gt; /// When a combinator is reached, the iterator will return None, and &gt; /// next_sequence() may be called to continue to the next sequence. &gt; #[inline] &gt;@@ -560,17 +563,17 @@ impl&lt;Impl: SelectorImpl&gt; Selector&lt;Impl&gt; { &gt; #[inline] &gt; pub fn is_featureless_host_selector_or_pseudo_element(&amp;self) -&gt; bool { &gt; let mut iter = self.iter(); &gt; if !self.has_pseudo_element() { &gt; return iter.is_featureless_host_selector(); &gt; } &gt; &gt; // Skip the pseudo-element. &gt;- for _ in &amp;mut iter { } &gt;+ for _ in &amp;mut iter {} &gt; &gt; match iter.next_sequence() { &gt; None =&gt; return false, &gt; Some(combinator) =&gt; { &gt; debug_assert_eq!(combinator, Combinator::PseudoElement); &gt; } &gt; } &gt; &gt;@@ -668,18 +671,18 @@ impl&lt;'a, Impl: 'a + SelectorImpl&gt; SelectorIter&lt;'a, Impl&gt; { &gt; pub fn next_sequence(&amp;mut self) -&gt; Option&lt;Combinator&gt; { &gt; self.next_combinator.take() &gt; } &gt; &gt; /// Whether this selector is a featureless host selector, with no &gt; /// combinators to the left. &gt; #[inline] &gt; pub(crate) fn is_featureless_host_selector(&amp;mut self) -&gt; bool { &gt;- self.all(|component| matches!(*component, Component::Host(..))) &amp;&amp; &gt;- self.next_sequence().is_none() &gt;+ self.all(|component| matches!(*component, Component::Host(..))) &gt;+ &amp;&amp; self.next_sequence().is_none() &gt; } &gt; &gt; /// Returns remaining count of the simple selectors and combinators in the Selector. &gt; #[inline] &gt; pub fn selector_length(&amp;self) -&gt; usize { &gt; self.iter.len() &gt; } &gt; } &gt;@@ -692,17 +695,17 @@ impl&lt;'a, Impl: SelectorImpl&gt; Iterator for SelectorIter&lt;'a, Impl&gt; { &gt; debug_assert!( &gt; self.next_combinator.is_none(), &gt; "You should call next_sequence!" &gt; ); &gt; match *self.iter.next()? { &gt; Component::Combinator(c) =&gt; { &gt; self.next_combinator = Some(c); &gt; None &gt;- }, &gt;+ } &gt; ref x =&gt; Some(x), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a, Impl: SelectorImpl&gt; fmt::Debug for SelectorIter&lt;'a, Impl&gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; let iter = self.iter.clone().rev(); &gt;@@ -780,18 +783,20 @@ pub enum Combinator { &gt; } &gt; &gt; impl Combinator { &gt; /// Returns true if this combinator is a child or descendant combinator. &gt; #[inline] &gt; pub fn is_ancestor(&amp;self) -&gt; bool { &gt; matches!( &gt; *self, &gt;- Combinator::Child | Combinator::Descendant | Combinator::PseudoElement | &gt;- Combinator::SlotAssignment &gt;+ Combinator::Child &gt;+ | Combinator::Descendant &gt;+ | Combinator::PseudoElement &gt;+ | Combinator::SlotAssignment &gt; ) &gt; } &gt; &gt; /// Returns true if this combinator is a pseudo-element combinator. &gt; #[inline] &gt; pub fn is_pseudo_element(&amp;self) -&gt; bool { &gt; matches!(*self, Combinator::PseudoElement) &gt; } &gt;@@ -905,28 +910,28 @@ impl&lt;Impl: SelectorImpl&gt; Component&lt;Impl&gt; { &gt; // Only insert the local-name into the filter if it's all &gt; // lowercase. Otherwise we would need to test both hashes, and &gt; // our data structures aren't really set up for that. &gt; if name == lower_name { &gt; Some(name.precomputed_hash()) &gt; } else { &gt; None &gt; } &gt;- }, &gt;+ } &gt; Component::DefaultNamespace(ref url) | Component::Namespace(_, ref url) =&gt; { &gt; Some(url.precomputed_hash()) &gt;- }, &gt;+ } &gt; // In quirks mode, class and id selectors should match &gt; // case-insensitively, so just avoid inserting them into the filter. &gt; Component::ID(ref id) if quirks_mode != QuirksMode::Quirks =&gt; { &gt; Some(id.precomputed_hash()) &gt;- }, &gt;+ } &gt; Component::Class(ref class) if quirks_mode != QuirksMode::Quirks =&gt; { &gt; Some(class.precomputed_hash()) &gt;- }, &gt;+ } &gt; _ =&gt; None, &gt; } &gt; } &gt; &gt; /// Returns true if this is a combinator. &gt; pub fn is_combinator(&amp;self) -&gt; bool { &gt; matches!(*self, Component::Combinator(_)) &gt; } &gt;@@ -971,17 +976,18 @@ impl&lt;Impl: SelectorImpl&gt; Debug for LocalName&lt;Impl&gt; { &gt; } &gt; &gt; impl&lt;Impl: SelectorImpl&gt; ToCss for SelectorList&lt;Impl&gt; { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut W) -&gt; fmt::Result &gt; where &gt; W: fmt::Write, &gt; { &gt; let mut iter = self.0.iter(); &gt;- let first = iter.next() &gt;+ let first = iter &gt;+ .next() &gt; .expect("Empty SelectorList, should contain at least one selector"); &gt; first.to_css(dest)?; &gt; for selector in iter { &gt; dest.write_str(", ")?; &gt; selector.to_css(dest)?; &gt; } &gt; Ok(()) &gt; } &gt;@@ -999,20 +1005,22 @@ impl&lt;Impl: SelectorImpl&gt; ToCss for Selector&lt;Impl&gt; { &gt; // We could do something more clever, but selector serialization probably &gt; // isn't hot enough to justify it, and the stringification likely &gt; // dominates anyway. &gt; // &gt; // NB: A parse-order iterator is a Rev&lt;&gt;, which doesn't expose as_slice(), &gt; // which we need for |split|. So we split by combinators on a match-order &gt; // sequence and then reverse. &gt; &gt;- let mut combinators = self.iter_raw_match_order() &gt;+ let mut combinators = self &gt;+ .iter_raw_match_order() &gt; .rev() &gt; .filter_map(|x| x.as_combinator()); &gt;- let compound_selectors = self.iter_raw_match_order() &gt;+ let compound_selectors = self &gt;+ .iter_raw_match_order() &gt; .as_slice() &gt; .split(|x| x.is_combinator()) &gt; .rev(); &gt; &gt; let mut combinators_exhausted = false; &gt; for compound in compound_selectors { &gt; debug_assert!(!combinators_exhausted); &gt; &gt;@@ -1027,44 +1035,44 @@ impl&lt;Impl: SelectorImpl&gt; ToCss for Selector&lt;Impl&gt; { &gt; // &gt; // Check if `!compound.empty()` first--this can happen if we have &gt; // something like `... &gt; ::before`, because we store `&gt;` and `::` &gt; // both as combinators internally. &gt; // &gt; // If we are in this case, after we have serialized the universal &gt; // selector, we skip Step 2 and continue with the algorithm. &gt; let (can_elide_namespace, first_non_namespace) = match compound[0] { &gt;- Component::ExplicitAnyNamespace | &gt;- Component::ExplicitNoNamespace | &gt;- Component::Namespace(..) =&gt; (false, 1), &gt;+ Component::ExplicitAnyNamespace &gt;+ | Component::ExplicitNoNamespace &gt;+ | Component::Namespace(..) =&gt; (false, 1), &gt; Component::DefaultNamespace(..) =&gt; (true, 1), &gt; _ =&gt; (true, 0), &gt; }; &gt; let mut perform_step_2 = true; &gt; let next_combinator = combinators.next(); &gt; if first_non_namespace == compound.len() - 1 { &gt; match (next_combinator, &amp;compound[first_non_namespace]) { &gt; // We have to be careful here, because if there is a &gt; // pseudo element "combinator" there isn't really just &gt; // the one simple selector. Technically this compound &gt; // selector contains the pseudo element selector as well &gt; // -- Combinator::PseudoElement, just like &gt; // Combinator::SlotAssignment, don't exist in the &gt; // spec. &gt;- (Some(Combinator::PseudoElement), _) | &gt;- (Some(Combinator::SlotAssignment), _) =&gt; (), &gt;+ (Some(Combinator::PseudoElement), _) &gt;+ | (Some(Combinator::SlotAssignment), _) =&gt; (), &gt; (_, &amp;Component::ExplicitUniversalType) =&gt; { &gt; // Iterate over everything so we serialize the namespace &gt; // too. &gt; for simple in compound.iter() { &gt; simple.to_css(dest)?; &gt; } &gt; // Skip step 2, which is an "otherwise". &gt; perform_step_2 = false; &gt;- }, &gt;+ } &gt; _ =&gt; (), &gt; } &gt; } &gt; &gt; // 2. Otherwise, for each simple selector in the compound selectors &gt; // that is not a universal selector of which the namespace prefix &gt; // maps to a namespace that is not the default namespace &gt; // serialize the simple selector and append the result to s. &gt;@@ -1153,139 +1161,139 @@ impl&lt;Impl: SelectorImpl&gt; ToCss for Component&lt;Impl&gt; { &gt; } &gt; &gt; match *self { &gt; Combinator(ref c) =&gt; c.to_css(dest), &gt; Slotted(ref selector) =&gt; { &gt; dest.write_str("::slotted(")?; &gt; selector.to_css(dest)?; &gt; dest.write_char(')') &gt;- }, &gt;+ } &gt; PseudoElement(ref p) =&gt; p.to_css(dest), &gt; ID(ref s) =&gt; { &gt; dest.write_char('#')?; &gt; display_to_css_identifier(s, dest) &gt;- }, &gt;+ } &gt; Class(ref s) =&gt; { &gt; dest.write_char('.')?; &gt; display_to_css_identifier(s, dest) &gt;- }, &gt;+ } &gt; LocalName(ref s) =&gt; s.to_css(dest), &gt; ExplicitUniversalType =&gt; dest.write_char('*'), &gt; &gt; DefaultNamespace(_) =&gt; Ok(()), &gt; ExplicitNoNamespace =&gt; dest.write_char('|'), &gt; ExplicitAnyNamespace =&gt; dest.write_str("*|"), &gt; Namespace(ref prefix, _) =&gt; { &gt; display_to_css_identifier(prefix, dest)?; &gt; dest.write_char('|') &gt;- }, &gt;+ } &gt; &gt; AttributeInNoNamespaceExists { ref local_name, .. } =&gt; { &gt; dest.write_char('[')?; &gt; display_to_css_identifier(local_name, dest)?; &gt; dest.write_char(']') &gt;- }, &gt;+ } &gt; AttributeInNoNamespace { &gt; ref local_name, &gt; operator, &gt; ref value, &gt; case_sensitivity, &gt; .. &gt; } =&gt; { &gt; dest.write_char('[')?; &gt; display_to_css_identifier(local_name, dest)?; &gt; operator.to_css(dest)?; &gt; dest.write_char('"')?; &gt; write!(CssStringWriter::new(dest), "{}", value)?; &gt; dest.write_char('"')?; &gt; match case_sensitivity { &gt;- ParsedCaseSensitivity::CaseSensitive | &gt;- ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument =&gt; {}, &gt;+ ParsedCaseSensitivity::CaseSensitive &gt;+ | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument =&gt; {} &gt; ParsedCaseSensitivity::AsciiCaseInsensitive =&gt; dest.write_str(" i")?, &gt; } &gt; dest.write_char(']') &gt;- }, &gt;+ } &gt; AttributeOther(ref attr_selector) =&gt; attr_selector.to_css(dest), &gt; &gt; // Pseudo-classes &gt; Negation(ref arg) =&gt; { &gt; dest.write_str(":not(")?; &gt; for component in arg.iter() { &gt; component.to_css(dest)?; &gt; } &gt; dest.write_str(")") &gt;- }, &gt;+ } &gt; &gt; FirstChild =&gt; dest.write_str(":first-child"), &gt; LastChild =&gt; dest.write_str(":last-child"), &gt; OnlyChild =&gt; dest.write_str(":only-child"), &gt; Root =&gt; dest.write_str(":root"), &gt; Empty =&gt; dest.write_str(":empty"), &gt; Scope =&gt; dest.write_str(":scope"), &gt; Host(ref selector) =&gt; { &gt; dest.write_str(":host")?; &gt; if let Some(ref selector) = *selector { &gt; dest.write_char('(')?; &gt; selector.to_css(dest)?; &gt; dest.write_char(')')?; &gt; } &gt; Ok(()) &gt;- }, &gt;+ } &gt; FirstOfType =&gt; dest.write_str(":first-of-type"), &gt; LastOfType =&gt; dest.write_str(":last-of-type"), &gt; OnlyOfType =&gt; dest.write_str(":only-of-type"), &gt; NthChild(a, b) | NthLastChild(a, b) | NthOfType(a, b) | NthLastOfType(a, b) =&gt; { &gt; match *self { &gt; NthChild(_, _) =&gt; dest.write_str(":nth-child(")?, &gt; NthLastChild(_, _) =&gt; dest.write_str(":nth-last-child(")?, &gt; NthOfType(_, _) =&gt; dest.write_str(":nth-of-type(")?, &gt; NthLastOfType(_, _) =&gt; dest.write_str(":nth-last-of-type(")?, &gt; _ =&gt; unreachable!(), &gt; } &gt; write_affine(dest, a, b)?; &gt; dest.write_char(')') &gt;- }, &gt;+ } &gt; NonTSPseudoClass(ref pseudo) =&gt; pseudo.to_css(dest), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;Impl: SelectorImpl&gt; ToCss for AttrSelectorWithOptionalNamespace&lt;Impl&gt; { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut W) -&gt; fmt::Result &gt; where &gt; W: fmt::Write, &gt; { &gt; dest.write_char('[')?; &gt; match self.namespace { &gt; Some(NamespaceConstraint::Specific((ref prefix, _))) =&gt; { &gt; display_to_css_identifier(prefix, dest)?; &gt; dest.write_char('|')? &gt;- }, &gt;+ } &gt; Some(NamespaceConstraint::Any) =&gt; dest.write_str("*|")?, &gt; None =&gt; {} &gt; } &gt; display_to_css_identifier(&amp;self.local_name, dest)?; &gt; match self.operation { &gt;- ParsedAttrSelectorOperation::Exists =&gt; {}, &gt;+ ParsedAttrSelectorOperation::Exists =&gt; {} &gt; ParsedAttrSelectorOperation::WithValue { &gt; operator, &gt; case_sensitivity, &gt; ref expected_value, &gt; } =&gt; { &gt; operator.to_css(dest)?; &gt; dest.write_char('"')?; &gt; write!(CssStringWriter::new(dest), "{}", expected_value)?; &gt; dest.write_char('"')?; &gt; match case_sensitivity { &gt;- ParsedCaseSensitivity::CaseSensitive | &gt;- ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument =&gt; {}, &gt;+ ParsedCaseSensitivity::CaseSensitive &gt;+ | ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument =&gt; {} &gt; ParsedCaseSensitivity::AsciiCaseInsensitive =&gt; dest.write_str(" i")?, &gt; } &gt;- }, &gt;+ } &gt; } &gt; dest.write_char(']') &gt; } &gt; } &gt; &gt; impl&lt;Impl: SelectorImpl&gt; ToCss for LocalName&lt;Impl&gt; { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut W) -&gt; fmt::Result &gt; where &gt;@@ -1331,24 +1339,24 @@ where &gt; let mut has_pseudo_element; &gt; let mut slotted; &gt; 'outer_loop: loop { &gt; // Parse a sequence of simple selectors. &gt; match parse_compound_selector(parser, input, &amp;mut builder)? { &gt; Some((has_pseudo, slot)) =&gt; { &gt; has_pseudo_element = has_pseudo; &gt; slotted = slot; &gt;- }, &gt;+ } &gt; None =&gt; { &gt; return Err(input.new_custom_error(if builder.has_combinators() { &gt; SelectorParseErrorKind::DanglingCombinator &gt; } else { &gt; SelectorParseErrorKind::EmptySelector &gt; })) &gt;- }, &gt;+ } &gt; }; &gt; &gt; if has_pseudo_element || slotted { &gt; break; &gt; } &gt; &gt; // Parse a combinator. &gt; let combinator; &gt;@@ -1356,34 +1364,34 @@ where &gt; loop { &gt; let before_this_token = input.state(); &gt; match input.next_including_whitespace() { &gt; Err(_e) =&gt; break 'outer_loop, &gt; Ok(&amp;Token::WhiteSpace(_)) =&gt; any_whitespace = true, &gt; Ok(&amp;Token::Delim('&gt;')) =&gt; { &gt; combinator = Combinator::Child; &gt; break; &gt;- }, &gt;+ } &gt; Ok(&amp;Token::Delim('+')) =&gt; { &gt; combinator = Combinator::NextSibling; &gt; break; &gt;- }, &gt;+ } &gt; Ok(&amp;Token::Delim('~')) =&gt; { &gt; combinator = Combinator::LaterSibling; &gt; break; &gt;- }, &gt;+ } &gt; Ok(_) =&gt; { &gt; input.reset(&amp;before_this_token); &gt; if any_whitespace { &gt; combinator = Combinator::Descendant; &gt; break; &gt; } else { &gt; break 'outer_loop; &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; builder.push_combinator(combinator); &gt; } &gt; &gt; Ok(Selector(builder.build(has_pseudo_element, slotted))) &gt; } &gt; &gt;@@ -1417,63 +1425,63 @@ where &gt; P: Parser&lt;'i, Impl = Impl&gt;, &gt; Impl: SelectorImpl, &gt; S: Push&lt;Component&lt;Impl&gt;&gt;, &gt; { &gt; match parse_qualified_name(parser, input, /* in_attr_selector = */ false) { &gt; Err(ParseError { &gt; kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput), &gt; .. &gt;- }) | &gt;- Ok(OptionalQName::None(_)) =&gt; Ok(false), &gt;+ }) &gt;+ | Ok(OptionalQName::None(_)) =&gt; Ok(false), &gt; Ok(OptionalQName::Some(namespace, local_name)) =&gt; { &gt; match namespace { &gt;- QNamePrefix::ImplicitAnyNamespace =&gt; {}, &gt;+ QNamePrefix::ImplicitAnyNamespace =&gt; {} &gt; QNamePrefix::ImplicitDefaultNamespace(url) =&gt; { &gt; sink.push(Component::DefaultNamespace(url)) &gt;- }, &gt;+ } &gt; QNamePrefix::ExplicitNamespace(prefix, url) =&gt; { &gt; sink.push(match parser.default_namespace() { &gt; Some(ref default_url) if url == *default_url =&gt; { &gt; Component::DefaultNamespace(url) &gt;- }, &gt;+ } &gt; _ =&gt; Component::Namespace(prefix, url), &gt; }) &gt;- }, &gt;+ } &gt; QNamePrefix::ExplicitNoNamespace =&gt; sink.push(Component::ExplicitNoNamespace), &gt; QNamePrefix::ExplicitAnyNamespace =&gt; { &gt; match parser.default_namespace() { &gt; // Element type selectors that have no namespace &gt; // component (no namespace separator) represent elements &gt; // without regard to the element's namespace (equivalent &gt; // to "*|") unless a default namespace has been declared &gt; // for namespaced selectors (e.g. in CSS, in the style &gt; // sheet). If a default namespace has been declared, &gt; // such selectors will represent only elements in the &gt; // default namespace. &gt; // -- Selectors § 6.1.1 &gt; // So we'll have this act the same as the &gt; // QNamePrefix::ImplicitAnyNamespace case. &gt;- None =&gt; {}, &gt;+ None =&gt; {} &gt; Some(_) =&gt; sink.push(Component::ExplicitAnyNamespace), &gt; } &gt;- }, &gt;+ } &gt; QNamePrefix::ImplicitNoNamespace =&gt; { &gt; unreachable!() // Not returned with in_attr_selector = false &gt;- }, &gt;+ } &gt; } &gt; match local_name { &gt; Some(name) =&gt; sink.push(Component::LocalName(LocalName { &gt; lower_name: to_ascii_lowercase(&amp;name).as_ref().into(), &gt; name: name.as_ref().into(), &gt; })), &gt; None =&gt; sink.push(Component::ExplicitUniversalType), &gt; } &gt; Ok(true) &gt;- }, &gt;+ } &gt; Err(e) =&gt; Err(e), &gt; } &gt; } &gt; &gt; #[derive(Debug)] &gt; enum SimpleSelectorParseResult&lt;Impl: SelectorImpl&gt; { &gt; SimpleSelector(Component&lt;Impl&gt;), &gt; PseudoElement(Impl::PseudoElement), &gt;@@ -1517,21 +1525,21 @@ where &gt; }; &gt; &gt; let explicit_namespace = |input: &amp;mut CssParser&lt;'i, 't&gt;, namespace| { &gt; let location = input.current_source_location(); &gt; match input.next_including_whitespace() { &gt; Ok(&amp;Token::Delim('*')) if !in_attr_selector =&gt; Ok(OptionalQName::Some(namespace, None)), &gt; Ok(&amp;Token::Ident(ref local_name)) =&gt; { &gt; Ok(OptionalQName::Some(namespace, Some(local_name.clone()))) &gt;- }, &gt;+ } &gt; Ok(t) if in_attr_selector =&gt; { &gt; let e = SelectorParseErrorKind::InvalidQualNameInAttr(t.clone()); &gt; Err(location.new_custom_error(e)) &gt;- }, &gt;+ } &gt; Ok(t) =&gt; Err(location.new_custom_error( &gt; SelectorParseErrorKind::ExplicitNamespaceUnexpectedToken(t.clone()), &gt; )), &gt; Err(e) =&gt; Err(e.into()), &gt; } &gt; }; &gt; &gt; let start = input.state(); &gt;@@ -1544,61 +1552,61 @@ where &gt; let prefix = value.as_ref().into(); &gt; let result = parser.namespace_for_prefix(&amp;prefix); &gt; let url = result.ok_or( &gt; after_ident &gt; .source_location() &gt; .new_custom_error(SelectorParseErrorKind::ExpectedNamespace(value)), &gt; )?; &gt; explicit_namespace(input, QNamePrefix::ExplicitNamespace(prefix, url)) &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; input.reset(&amp;after_ident); &gt; if in_attr_selector { &gt; Ok(OptionalQName::Some( &gt; QNamePrefix::ImplicitNoNamespace, &gt; Some(value), &gt; )) &gt; } else { &gt; default_namespace(Some(value)) &gt; } &gt;- }, &gt;+ } &gt; } &gt;- }, &gt;+ } &gt; Ok(Token::Delim('*')) =&gt; { &gt; let after_star = input.state(); &gt; // FIXME: remove clone() when lifetimes are non-lexical &gt; match input.next_including_whitespace().map(|t| t.clone()) { &gt; Ok(Token::Delim('|')) =&gt; { &gt; explicit_namespace(input, QNamePrefix::ExplicitAnyNamespace) &gt;- }, &gt;+ } &gt; result =&gt; { &gt; input.reset(&amp;after_star); &gt; if in_attr_selector { &gt; match result { &gt; Ok(t) =&gt; Err(after_star &gt; .source_location() &gt; .new_custom_error(SelectorParseErrorKind::ExpectedBarInAttr(t))), &gt; Err(e) =&gt; Err(e.into()), &gt; } &gt; } else { &gt; default_namespace(None) &gt; } &gt;- }, &gt;+ } &gt; } &gt;- }, &gt;+ } &gt; Ok(Token::Delim('|')) =&gt; explicit_namespace(input, QNamePrefix::ExplicitNoNamespace), &gt; Ok(t) =&gt; { &gt; input.reset(&amp;start); &gt; Ok(OptionalQName::None(t)) &gt;- }, &gt;+ } &gt; Err(e) =&gt; { &gt; input.reset(&amp;start); &gt; Err(e.into()) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; fn parse_attribute_selector&lt;'i, 't, P, Impl&gt;( &gt; parser: &amp;P, &gt; input: &amp;mut CssParser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Component&lt;Impl&gt;, ParseError&lt;'i, P::Error&gt;&gt; &gt; where &gt;@@ -1610,31 +1618,31 @@ where &gt; &gt; input.skip_whitespace(); &gt; &gt; match parse_qualified_name(parser, input, /* in_attr_selector = */ true)? { &gt; OptionalQName::None(t) =&gt; { &gt; return Err(input.new_custom_error( &gt; SelectorParseErrorKind::NoQualifiedNameInAttributeSelector(t), &gt; )) &gt;- }, &gt;+ } &gt; OptionalQName::Some(_, None) =&gt; unreachable!(), &gt; OptionalQName::Some(ns, Some(ln)) =&gt; { &gt; local_name = ln; &gt; namespace = match ns { &gt; QNamePrefix::ImplicitNoNamespace | QNamePrefix::ExplicitNoNamespace =&gt; None, &gt; QNamePrefix::ExplicitNamespace(prefix, url) =&gt; { &gt; Some(NamespaceConstraint::Specific((prefix, url))) &gt;- }, &gt;+ } &gt; QNamePrefix::ExplicitAnyNamespace =&gt; Some(NamespaceConstraint::Any), &gt; QNamePrefix::ImplicitAnyNamespace | QNamePrefix::ImplicitDefaultNamespace(_) =&gt; { &gt; unreachable!() // Not returned with in_attr_selector = true &gt;- }, &gt;+ } &gt; } &gt;- }, &gt;+ } &gt; } &gt; &gt; let location = input.current_source_location(); &gt; let operator = match input.next() { &gt; // [foo] &gt; Err(_) =&gt; { &gt; let local_name_lower = to_ascii_lowercase(&amp;local_name).as_ref().into(); &gt; let local_name = local_name.as_ref().into(); &gt;@@ -1649,17 +1657,17 @@ where &gt; }, &gt; ))); &gt; } else { &gt; return Ok(Component::AttributeInNoNamespaceExists { &gt; local_name: local_name, &gt; local_name_lower: local_name_lower, &gt; }); &gt; } &gt;- }, &gt;+ } &gt; &gt; // [foo=bar] &gt; Ok(&amp;Token::Delim('=')) =&gt; AttrSelectorOperator::Equal, &gt; // [foo~=bar] &gt; Ok(&amp;Token::IncludeMatch) =&gt; AttrSelectorOperator::Includes, &gt; // [foo|=bar] &gt; Ok(&amp;Token::DashMatch) =&gt; AttrSelectorOperator::DashMatch, &gt; // [foo^=bar] &gt;@@ -1667,50 +1675,49 @@ where &gt; // [foo*=bar] &gt; Ok(&amp;Token::SubstringMatch) =&gt; AttrSelectorOperator::Substring, &gt; // [foo$=bar] &gt; Ok(&amp;Token::SuffixMatch) =&gt; AttrSelectorOperator::Suffix, &gt; Ok(t) =&gt; { &gt; return Err(location.new_custom_error( &gt; SelectorParseErrorKind::UnexpectedTokenInAttributeSelector(t.clone()), &gt; )) &gt;- }, &gt;+ } &gt; }; &gt; &gt; let value = match input.expect_ident_or_string() { &gt; Ok(t) =&gt; t.clone(), &gt; Err(BasicParseError { &gt; kind: BasicParseErrorKind::UnexpectedToken(t), &gt; location, &gt; }) =&gt; return Err(location.new_custom_error(SelectorParseErrorKind::BadValueInAttr(t))), &gt; Err(e) =&gt; return Err(e.into()), &gt; }; &gt; let never_matches = match operator { &gt; AttrSelectorOperator::Equal | AttrSelectorOperator::DashMatch =&gt; false, &gt; &gt; AttrSelectorOperator::Includes =&gt; value.is_empty() || value.contains(SELECTOR_WHITESPACE), &gt; &gt;- AttrSelectorOperator::Prefix | &gt;- AttrSelectorOperator::Substring | &gt;- AttrSelectorOperator::Suffix =&gt; value.is_empty(), &gt;+ AttrSelectorOperator::Prefix &gt;+ | AttrSelectorOperator::Substring &gt;+ | AttrSelectorOperator::Suffix =&gt; value.is_empty(), &gt; }; &gt; &gt; let mut case_sensitivity = parse_attribute_flags(input)?; &gt; &gt; let value = value.as_ref().into(); &gt; let local_name_lower; &gt; let local_name_is_ascii_lowercase; &gt; { &gt; let local_name_lower_cow = to_ascii_lowercase(&amp;local_name); &gt; if let ParsedCaseSensitivity::CaseSensitive = case_sensitivity { &gt;- if namespace.is_none() &amp;&amp; &gt;- include!(concat!( &gt;- env!("OUT_DIR"), &gt;- "/ascii_case_insensitive_html_attributes.rs" &gt;- )).contains(&amp;*local_name_lower_cow) &gt;+ if namespace.is_none() &amp;&amp; include!(concat!( &gt;+ env!("OUT_DIR"), &gt;+ "/ascii_case_insensitive_html_attributes.rs" &gt;+ )).contains(&amp;*local_name_lower_cow) &gt; { &gt; case_sensitivity = &gt; ParsedCaseSensitivity::AsciiCaseInsensitiveIfInHtmlElementInHtmlDocument &gt; } &gt; } &gt; local_name_lower = local_name_lower_cow.as_ref().into(); &gt; local_name_is_ascii_lowercase = matches!(local_name_lower_cow, Cow::Borrowed(..)); &gt; } &gt;@@ -1743,20 +1750,20 @@ where &gt; fn parse_attribute_flags&lt;'i, 't&gt;( &gt; input: &amp;mut CssParser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;ParsedCaseSensitivity, BasicParseError&lt;'i&gt;&gt; { &gt; let location = input.current_source_location(); &gt; match input.next() { &gt; Err(_) =&gt; { &gt; // Selectors spec says language-defined, but HTML says sensitive. &gt; Ok(ParsedCaseSensitivity::CaseSensitive) &gt;- }, &gt;+ } &gt; Ok(&amp;Token::Ident(ref value)) if value.eq_ignore_ascii_case("i") =&gt; { &gt; Ok(ParsedCaseSensitivity::AsciiCaseInsensitive) &gt;- }, &gt;+ } &gt; Ok(t) =&gt; Err(location.new_basic_unexpected_token_error(t.clone())), &gt; } &gt; } &gt; &gt; /// Level 3: Parse **one** simple_selector. (Though we might insert a second &gt; /// implied "&lt;defaultns&gt;|*" type selector.) &gt; fn parse_negation&lt;'i, 't, P, Impl&gt;( &gt; parser: &amp;P, &gt;@@ -1780,30 +1787,32 @@ where &gt; .. &gt; }) =&gt; return Err(input.new_custom_error(SelectorParseErrorKind::EmptyNegation)), &gt; Err(e) =&gt; return Err(e.into()), &gt; }; &gt; if !is_type_sel { &gt; match parse_one_simple_selector(parser, input, /* inside_negation = */ true)? { &gt; Some(SimpleSelectorParseResult::SimpleSelector(s)) =&gt; { &gt; sequence.push(s); &gt;- }, &gt;+ } &gt; None =&gt; { &gt; return Err(input.new_custom_error(SelectorParseErrorKind::EmptyNegation)); &gt;- }, &gt;- Some(SimpleSelectorParseResult::PseudoElement(_)) | &gt;- Some(SimpleSelectorParseResult::SlottedPseudo(_)) =&gt; { &gt;+ } &gt;+ Some(SimpleSelectorParseResult::PseudoElement(_)) &gt;+ | Some(SimpleSelectorParseResult::SlottedPseudo(_)) =&gt; { &gt; let e = SelectorParseErrorKind::NonSimpleSelectorInNegation; &gt; return Err(input.new_custom_error(e)); &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; // Success. &gt;- Ok(Component::Negation(sequence.into_vec().into_boxed_slice().into())) &gt;+ Ok(Component::Negation( &gt;+ sequence.into_vec().into_boxed_slice().into(), &gt;+ )) &gt; } &gt; &gt; /// simple_selector_sequence &gt; /// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]* &gt; /// | [ HASH | class | attrib | pseudo | negation ]+ &gt; /// &gt; /// `Err(())` means invalid selector. &gt; /// `Ok(None)` is an empty selector &gt;@@ -1841,43 +1850,43 @@ where &gt; None =&gt; break, &gt; Some(result) =&gt; result, &gt; }; &gt; &gt; match parse_result { &gt; SimpleSelectorParseResult::SimpleSelector(s) =&gt; { &gt; builder.push_simple_selector(s); &gt; empty = false &gt;- }, &gt;+ } &gt; SimpleSelectorParseResult::PseudoElement(p) =&gt; { &gt; // Try to parse state to its right. There are only 3 allowable &gt; // state selectors that can go on pseudo-elements. &gt; let mut state_selectors = SmallVec::&lt;[Component&lt;Impl&gt;; 3]&gt;::new(); &gt; &gt; loop { &gt; let location = input.current_source_location(); &gt; match input.next_including_whitespace() { &gt;- Ok(&amp;Token::Colon) =&gt; {}, &gt;+ Ok(&amp;Token::Colon) =&gt; {} &gt; Ok(&amp;Token::WhiteSpace(_)) | Err(_) =&gt; break, &gt; Ok(t) =&gt; { &gt; let e = SelectorParseErrorKind::PseudoElementExpectedColon(t.clone()); &gt; return Err(location.new_custom_error(e)); &gt;- }, &gt;+ } &gt; } &gt; &gt; let location = input.current_source_location(); &gt; // TODO(emilio): Functional pseudo-classes too? &gt; // We don't need it for now. &gt; let name = match input.next_including_whitespace()? { &gt; &amp;Token::Ident(ref name) =&gt; name.clone(), &gt; t =&gt; { &gt; return Err(location.new_custom_error( &gt; SelectorParseErrorKind::NoIdentForPseudo(t.clone()), &gt; )) &gt;- }, &gt;+ } &gt; }; &gt; &gt; let pseudo_class = &gt; P::parse_non_ts_pseudo_class(parser, location, name.clone())?; &gt; if !p.supports_pseudo_class(&amp;pseudo_class) { &gt; return Err(input.new_custom_error( &gt; SelectorParseErrorKind::UnsupportedPseudoClassOrElement(name), &gt; )); &gt;@@ -1892,29 +1901,29 @@ where &gt; builder.push_simple_selector(Component::PseudoElement(p)); &gt; for state_selector in state_selectors.drain() { &gt; builder.push_simple_selector(state_selector); &gt; } &gt; &gt; pseudo = true; &gt; empty = false; &gt; break; &gt;- }, &gt;+ } &gt; SimpleSelectorParseResult::SlottedPseudo(selector) =&gt; { &gt; empty = false; &gt; slot = true; &gt; if !builder.is_empty() { &gt; builder.push_combinator(Combinator::SlotAssignment); &gt; } &gt; builder.push_simple_selector(Component::Slotted(selector)); &gt; // FIXME(emilio): ::slotted() should support ::before and &gt; // ::after after it, so we shouldn't break, but we shouldn't &gt; // push more type selectors either. &gt; break; &gt;- }, &gt;+ } &gt; } &gt; } &gt; if empty { &gt; // An empty selector is invalid. &gt; Ok(None) &gt; } else { &gt; Ok(Some((pseudo, slot))) &gt; } &gt;@@ -1987,47 +1996,47 @@ where &gt; Impl: SelectorImpl, &gt; { &gt; let start = input.state(); &gt; // FIXME: remove clone() when lifetimes are non-lexical &gt; match input.next_including_whitespace().map(|t| t.clone()) { &gt; Ok(Token::IDHash(id)) =&gt; { &gt; let id = Component::ID(id.as_ref().into()); &gt; Ok(Some(SimpleSelectorParseResult::SimpleSelector(id))) &gt;- }, &gt;+ } &gt; Ok(Token::Delim('.')) =&gt; { &gt; let location = input.current_source_location(); &gt; match *input.next_including_whitespace()? { &gt; Token::Ident(ref class) =&gt; { &gt; let class = Component::Class(class.as_ref().into()); &gt; Ok(Some(SimpleSelectorParseResult::SimpleSelector(class))) &gt;- }, &gt;+ } &gt; ref t =&gt; { &gt; let e = SelectorParseErrorKind::ClassNeedsIdent(t.clone()); &gt; Err(location.new_custom_error(e)) &gt;- }, &gt;+ } &gt; } &gt;- }, &gt;+ } &gt; Ok(Token::SquareBracketBlock) =&gt; { &gt; let attr = input.parse_nested_block(|input| parse_attribute_selector(parser, input))?; &gt; Ok(Some(SimpleSelectorParseResult::SimpleSelector(attr))) &gt;- }, &gt;+ } &gt; Ok(Token::Colon) =&gt; { &gt; let location = input.current_source_location(); &gt; let (is_single_colon, next_token) = match input.next_including_whitespace()?.clone() { &gt; Token::Colon =&gt; (false, input.next_including_whitespace()?.clone()), &gt; t =&gt; (true, t), &gt; }; &gt; let (name, is_functional) = match next_token { &gt; Token::Ident(name) =&gt; (name, false), &gt; Token::Function(name) =&gt; (name, true), &gt; t =&gt; { &gt; let e = SelectorParseErrorKind::PseudoElementExpectedIdent(t); &gt; return Err(input.new_custom_error(e)); &gt;- }, &gt;+ } &gt; }; &gt; let is_pseudo_element = &gt; !is_single_colon || P::pseudo_element_allows_single_colon(&amp;name); &gt; if is_pseudo_element { &gt; let parse_result = if is_functional { &gt; if P::parse_slotted(parser) &amp;&amp; name.eq_ignore_ascii_case("slotted") { &gt; let selector = input.parse_nested_block(|input| { &gt; parse_inner_compound_selector(parser, input) &gt;@@ -2036,39 +2045,37 @@ where &gt; } else { &gt; let selector = input.parse_nested_block(|input| { &gt; P::parse_functional_pseudo_element(parser, name, input) &gt; })?; &gt; SimpleSelectorParseResult::PseudoElement(selector) &gt; } &gt; } else { &gt; SimpleSelectorParseResult::PseudoElement(P::parse_pseudo_element( &gt;- parser, &gt;- location, &gt;- name, &gt;+ parser, location, name, &gt; )?) &gt; }; &gt; Ok(Some(parse_result)) &gt; } else { &gt; let pseudo_class = if is_functional { &gt; input.parse_nested_block(|input| { &gt; parse_functional_pseudo_class(parser, input, name, inside_negation) &gt; })? &gt; } else { &gt; parse_simple_pseudo_class(parser, location, name)? &gt; }; &gt; Ok(Some(SimpleSelectorParseResult::SimpleSelector( &gt; pseudo_class, &gt; ))) &gt; } &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; input.reset(&amp;start); &gt; Ok(None) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; fn parse_simple_pseudo_class&lt;'i, P, Impl&gt;( &gt; parser: &amp;P, &gt; location: SourceLocation, &gt; name: CowRcStr&lt;'i&gt;, &gt; ) -&gt; Result&lt;Component&lt;Impl&gt;, ParseError&lt;'i, P::Error&gt;&gt; &gt;@@ -2091,22 +2098,22 @@ where &gt; }).or_else(|()| { &gt; P::parse_non_ts_pseudo_class(parser, location, name).map(Component::NonTSPseudoClass) &gt; }) &gt; } &gt; &gt; // NB: pub module in order to access the DummyParser &gt; #[cfg(test)] &gt; pub mod tests { &gt;+ use super::*; &gt; use builder::HAS_PSEUDO_BIT; &gt; use cssparser::{serialize_identifier, Parser as CssParser, ParserInput, ToCss}; &gt; use parser; &gt; use std::collections::HashMap; &gt; use std::fmt; &gt;- use super::*; &gt; &gt; #[derive(Clone, Debug, Eq, PartialEq)] &gt; pub enum PseudoClass { &gt; Hover, &gt; Active, &gt; Lang(String), &gt; } &gt; &gt;@@ -2143,17 +2150,17 @@ pub mod tests { &gt; { &gt; match *self { &gt; PseudoClass::Hover =&gt; dest.write_str(":hover"), &gt; PseudoClass::Active =&gt; dest.write_str(":active"), &gt; PseudoClass::Lang(ref lang) =&gt; { &gt; dest.write_str(":lang(")?; &gt; serialize_identifier(lang, dest)?; &gt; dest.write_char(')') &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl ToCss for PseudoElement { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut W) -&gt; fmt::Result &gt; where &gt; W: fmt::Write, &gt;@@ -2358,521 +2365,452 @@ pub mod tests { &gt; &gt; #[test] &gt; fn test_parsing() { &gt; assert!(parse("").is_err()); &gt; assert!(parse(":lang(4)").is_err()); &gt; assert!(parse(":lang(en US)").is_err()); &gt; assert_eq!( &gt; parse("EeÉ"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::LocalName(LocalName { &gt;- name: DummyAtom::from("EeÉ"), &gt;- lower_name: DummyAtom::from("eeÉ"), &gt;- }), &gt;- ], &gt;- specificity(0, 0, 1), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::LocalName(LocalName { &gt;+ name: DummyAtom::from("EeÉ"), &gt;+ lower_name: DummyAtom::from("eeÉ"), &gt;+ }),], &gt;+ specificity(0, 0, 1), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse("|e"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::ExplicitNoNamespace, &gt;- Component::LocalName(LocalName { &gt;- name: DummyAtom::from("e"), &gt;- lower_name: DummyAtom::from("e"), &gt;- }), &gt;- ], &gt;- specificity(0, 0, 1), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::ExplicitNoNamespace, &gt;+ Component::LocalName(LocalName { &gt;+ name: DummyAtom::from("e"), &gt;+ lower_name: DummyAtom::from("e"), &gt;+ }), &gt;+ ], &gt;+ specificity(0, 0, 1), &gt;+ ),])) &gt; ); &gt; // When the default namespace is not set, *| should be elided. &gt; // https://github.com/servo/servo/pull/17537 &gt; assert_eq!( &gt; parse_expected("*|e", Some("e")), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::LocalName(LocalName { &gt;- name: DummyAtom::from("e"), &gt;- lower_name: DummyAtom::from("e"), &gt;- }), &gt;- ], &gt;- specificity(0, 0, 1), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::LocalName(LocalName { &gt;+ name: DummyAtom::from("e"), &gt;+ lower_name: DummyAtom::from("e"), &gt;+ }),], &gt;+ specificity(0, 0, 1), &gt;+ ),])) &gt; ); &gt; // When the default namespace is set, *| should _not_ be elided (as foo &gt; // is no longer equivalent to *|foo--the former is only for foo in the &gt; // default namespace). &gt; // https://github.com/servo/servo/issues/16020 &gt; assert_eq!( &gt; parse_ns( &gt; "*|e", &gt; &amp;DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")) &gt; ), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::ExplicitAnyNamespace, &gt;- Component::LocalName(LocalName { &gt;- name: DummyAtom::from("e"), &gt;- lower_name: DummyAtom::from("e"), &gt;- }), &gt;- ], &gt;- specificity(0, 0, 1), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::ExplicitAnyNamespace, &gt;+ Component::LocalName(LocalName { &gt;+ name: DummyAtom::from("e"), &gt;+ lower_name: DummyAtom::from("e"), &gt;+ }), &gt;+ ], &gt;+ specificity(0, 0, 1), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse("*"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec(vec![Component::ExplicitUniversalType], specificity(0, 0, 0)), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::ExplicitUniversalType], &gt;+ specificity(0, 0, 0) &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse("|*"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::ExplicitNoNamespace, &gt;- Component::ExplicitUniversalType, &gt;- ], &gt;- specificity(0, 0, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::ExplicitNoNamespace, &gt;+ Component::ExplicitUniversalType, &gt;+ ], &gt;+ specificity(0, 0, 0), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse_expected("*|*", Some("*")), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec(vec![Component::ExplicitUniversalType], specificity(0, 0, 0)), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::ExplicitUniversalType], &gt;+ specificity(0, 0, 0) &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse_ns( &gt; "*|*", &gt; &amp;DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")) &gt; ), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::ExplicitAnyNamespace, &gt;- Component::ExplicitUniversalType, &gt;- ], &gt;- specificity(0, 0, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::ExplicitAnyNamespace, &gt;+ Component::ExplicitUniversalType, &gt;+ ], &gt;+ specificity(0, 0, 0), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse(".foo:lang(en-US)"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::Class(DummyAtom::from("foo")), &gt;- Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())), &gt;- ], &gt;- specificity(0, 2, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::Class(DummyAtom::from("foo")), &gt;+ Component::NonTSPseudoClass(PseudoClass::Lang("en-US".to_owned())), &gt;+ ], &gt;+ specificity(0, 2, 0), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse("#bar"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![Component::ID(DummyAtom::from("bar"))], &gt;- specificity(1, 0, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::ID(DummyAtom::from("bar"))], &gt;+ specificity(1, 0, 0), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse("e.foo#bar"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::LocalName(LocalName { &gt;- name: DummyAtom::from("e"), &gt;- lower_name: DummyAtom::from("e"), &gt;- }), &gt;- Component::Class(DummyAtom::from("foo")), &gt;- Component::ID(DummyAtom::from("bar")), &gt;- ], &gt;- specificity(1, 1, 1), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::LocalName(LocalName { &gt;+ name: DummyAtom::from("e"), &gt;+ lower_name: DummyAtom::from("e"), &gt;+ }), &gt;+ Component::Class(DummyAtom::from("foo")), &gt;+ Component::ID(DummyAtom::from("bar")), &gt;+ ], &gt;+ specificity(1, 1, 1), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse("e.foo #bar"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::LocalName(LocalName { &gt;- name: DummyAtom::from("e"), &gt;- lower_name: DummyAtom::from("e"), &gt;- }), &gt;- Component::Class(DummyAtom::from("foo")), &gt;- Component::Combinator(Combinator::Descendant), &gt;- Component::ID(DummyAtom::from("bar")), &gt;- ], &gt;- specificity(1, 1, 1), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::LocalName(LocalName { &gt;+ name: DummyAtom::from("e"), &gt;+ lower_name: DummyAtom::from("e"), &gt;+ }), &gt;+ Component::Class(DummyAtom::from("foo")), &gt;+ Component::Combinator(Combinator::Descendant), &gt;+ Component::ID(DummyAtom::from("bar")), &gt;+ ], &gt;+ specificity(1, 1, 1), &gt;+ ),])) &gt; ); &gt; // Default namespace does not apply to attribute selectors &gt; // https://github.com/mozilla/servo/pull/1652 &gt; let mut parser = DummyParser::default(); &gt; assert_eq!( &gt; parse_ns("[Foo]", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::AttributeInNoNamespaceExists { &gt;- local_name: DummyAtom::from("Foo"), &gt;- local_name_lower: DummyAtom::from("foo"), &gt;- }, &gt;- ], &gt;- specificity(0, 1, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::AttributeInNoNamespaceExists { &gt;+ local_name: DummyAtom::from("Foo"), &gt;+ local_name_lower: DummyAtom::from("foo"), &gt;+ },], &gt;+ specificity(0, 1, 0), &gt;+ ),])) &gt; ); &gt; assert!(parse_ns("svg|circle", &amp;parser).is_err()); &gt; parser &gt; .ns_prefixes &gt; .insert(DummyAtom("svg".into()), DummyAtom(SVG.into())); &gt; assert_eq!( &gt; parse_ns("svg|circle", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::Namespace(DummyAtom("svg".into()), SVG.into()), &gt;- Component::LocalName(LocalName { &gt;- name: DummyAtom::from("circle"), &gt;- lower_name: DummyAtom::from("circle"), &gt;- }), &gt;- ], &gt;- specificity(0, 0, 1), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::Namespace(DummyAtom("svg".into()), SVG.into()), &gt;+ Component::LocalName(LocalName { &gt;+ name: DummyAtom::from("circle"), &gt;+ lower_name: DummyAtom::from("circle"), &gt;+ }), &gt;+ ], &gt;+ specificity(0, 0, 1), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse_ns("svg|*", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::Namespace(DummyAtom("svg".into()), SVG.into()), &gt;- Component::ExplicitUniversalType, &gt;- ], &gt;- specificity(0, 0, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::Namespace(DummyAtom("svg".into()), SVG.into()), &gt;+ Component::ExplicitUniversalType, &gt;+ ], &gt;+ specificity(0, 0, 0), &gt;+ ),])) &gt; ); &gt; // Default namespace does not apply to attribute selectors &gt; // https://github.com/mozilla/servo/pull/1652 &gt; // but it does apply to implicit type selectors &gt; // https://github.com/servo/rust-selectors/pull/82 &gt; parser.default_ns = Some(MATHML.into()); &gt; assert_eq!( &gt; parse_ns("[Foo]", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::DefaultNamespace(MATHML.into()), &gt;- Component::AttributeInNoNamespaceExists { &gt;- local_name: DummyAtom::from("Foo"), &gt;- local_name_lower: DummyAtom::from("foo"), &gt;- }, &gt;- ], &gt;- specificity(0, 1, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::DefaultNamespace(MATHML.into()), &gt;+ Component::AttributeInNoNamespaceExists { &gt;+ local_name: DummyAtom::from("Foo"), &gt;+ local_name_lower: DummyAtom::from("foo"), &gt;+ }, &gt;+ ], &gt;+ specificity(0, 1, 0), &gt;+ ),])) &gt; ); &gt; // Default namespace does apply to type selectors &gt; assert_eq!( &gt; parse_ns("e", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::DefaultNamespace(MATHML.into()), &gt;- Component::LocalName(LocalName { &gt;- name: DummyAtom::from("e"), &gt;- lower_name: DummyAtom::from("e"), &gt;- }), &gt;- ], &gt;- specificity(0, 0, 1), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::DefaultNamespace(MATHML.into()), &gt;+ Component::LocalName(LocalName { &gt;+ name: DummyAtom::from("e"), &gt;+ lower_name: DummyAtom::from("e"), &gt;+ }), &gt;+ ], &gt;+ specificity(0, 0, 1), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse_ns("*", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::DefaultNamespace(MATHML.into()), &gt;- Component::ExplicitUniversalType, &gt;- ], &gt;- specificity(0, 0, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::DefaultNamespace(MATHML.into()), &gt;+ Component::ExplicitUniversalType, &gt;+ ], &gt;+ specificity(0, 0, 0), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse_ns("*|*", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::ExplicitAnyNamespace, &gt;- Component::ExplicitUniversalType, &gt;- ], &gt;- specificity(0, 0, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::ExplicitAnyNamespace, &gt;+ Component::ExplicitUniversalType, &gt;+ ], &gt;+ specificity(0, 0, 0), &gt;+ ),])) &gt; ); &gt; // Default namespace applies to universal and type selectors inside :not and :matches, &gt; // but not otherwise. &gt; assert_eq!( &gt; parse_ns(":not(.cl)", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::DefaultNamespace(MATHML.into()), &gt;- Component::Negation( &gt;- vec![Component::Class(DummyAtom::from("cl"))].into_boxed_slice().into(), &gt;- ), &gt;- ], &gt;- specificity(0, 1, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::DefaultNamespace(MATHML.into()), &gt;+ Component::Negation( &gt;+ vec![Component::Class(DummyAtom::from("cl"))] &gt;+ .into_boxed_slice() &gt;+ .into(), &gt;+ ), &gt;+ ], &gt;+ specificity(0, 1, 0), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse_ns(":not(*)", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::DefaultNamespace(MATHML.into()), &gt;- Component::Negation( &gt;- vec![ &gt;- Component::DefaultNamespace(MATHML.into()), &gt;- Component::ExplicitUniversalType, &gt;- ].into_boxed_slice().into(), &gt;- ), &gt;- ], &gt;- specificity(0, 0, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::DefaultNamespace(MATHML.into()), &gt;+ Component::Negation( &gt;+ vec![ &gt;+ Component::DefaultNamespace(MATHML.into()), &gt;+ Component::ExplicitUniversalType, &gt;+ ].into_boxed_slice() &gt;+ .into(), &gt;+ ), &gt;+ ], &gt;+ specificity(0, 0, 0), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse_ns(":not(e)", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::DefaultNamespace(MATHML.into()), &gt;- Component::Negation( &gt;- vec![ &gt;- Component::DefaultNamespace(MATHML.into()), &gt;- Component::LocalName(LocalName { &gt;- name: DummyAtom::from("e"), &gt;- lower_name: DummyAtom::from("e"), &gt;- }), &gt;- ].into_boxed_slice().into(), &gt;- ), &gt;- ], &gt;- specificity(0, 0, 1), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::DefaultNamespace(MATHML.into()), &gt;+ Component::Negation( &gt;+ vec![ &gt;+ Component::DefaultNamespace(MATHML.into()), &gt;+ Component::LocalName(LocalName { &gt;+ name: DummyAtom::from("e"), &gt;+ lower_name: DummyAtom::from("e"), &gt;+ }), &gt;+ ].into_boxed_slice() &gt;+ .into(), &gt;+ ), &gt;+ ], &gt;+ specificity(0, 0, 1), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse("[attr|=\"foo\"]"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::AttributeInNoNamespace { &gt;- local_name: DummyAtom::from("attr"), &gt;- operator: AttrSelectorOperator::DashMatch, &gt;- value: DummyAtom::from("foo"), &gt;- never_matches: false, &gt;- case_sensitivity: ParsedCaseSensitivity::CaseSensitive, &gt;- }, &gt;- ], &gt;- specificity(0, 1, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::AttributeInNoNamespace { &gt;+ local_name: DummyAtom::from("attr"), &gt;+ operator: AttrSelectorOperator::DashMatch, &gt;+ value: DummyAtom::from("foo"), &gt;+ never_matches: false, &gt;+ case_sensitivity: ParsedCaseSensitivity::CaseSensitive, &gt;+ },], &gt;+ specificity(0, 1, 0), &gt;+ ),])) &gt; ); &gt; // https://github.com/mozilla/servo/issues/1723 &gt; assert_eq!( &gt; parse("::before"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![Component::PseudoElement(PseudoElement::Before)], &gt;- specificity(0, 0, 1) | HAS_PSEUDO_BIT, &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::PseudoElement(PseudoElement::Before)], &gt;+ specificity(0, 0, 1) | HAS_PSEUDO_BIT, &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse("::before:hover"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::PseudoElement(PseudoElement::Before), &gt;- Component::NonTSPseudoClass(PseudoClass::Hover), &gt;- ], &gt;- specificity(0, 1, 1) | HAS_PSEUDO_BIT, &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::PseudoElement(PseudoElement::Before), &gt;+ Component::NonTSPseudoClass(PseudoClass::Hover), &gt;+ ], &gt;+ specificity(0, 1, 1) | HAS_PSEUDO_BIT, &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse("::before:hover:hover"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::PseudoElement(PseudoElement::Before), &gt;- Component::NonTSPseudoClass(PseudoClass::Hover), &gt;- Component::NonTSPseudoClass(PseudoClass::Hover), &gt;- ], &gt;- specificity(0, 2, 1) | HAS_PSEUDO_BIT, &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::PseudoElement(PseudoElement::Before), &gt;+ Component::NonTSPseudoClass(PseudoClass::Hover), &gt;+ Component::NonTSPseudoClass(PseudoClass::Hover), &gt;+ ], &gt;+ specificity(0, 2, 1) | HAS_PSEUDO_BIT, &gt;+ ),])) &gt; ); &gt; assert!(parse("::before:hover:active").is_err()); &gt; assert!(parse("::before:hover .foo").is_err()); &gt; assert!(parse("::before .foo").is_err()); &gt; assert!(parse("::before ~ bar").is_err()); &gt; assert!(parse("::before:active").is_err()); &gt; &gt; // https://github.com/servo/servo/issues/15335 &gt; assert!(parse(":: before").is_err()); &gt; assert_eq!( &gt; parse("div ::after"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::LocalName(LocalName { &gt;- name: DummyAtom::from("div"), &gt;- lower_name: DummyAtom::from("div"), &gt;- }), &gt;- Component::Combinator(Combinator::Descendant), &gt;- Component::Combinator(Combinator::PseudoElement), &gt;- Component::PseudoElement(PseudoElement::After), &gt;- ], &gt;- specificity(0, 0, 2) | HAS_PSEUDO_BIT, &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::LocalName(LocalName { &gt;+ name: DummyAtom::from("div"), &gt;+ lower_name: DummyAtom::from("div"), &gt;+ }), &gt;+ Component::Combinator(Combinator::Descendant), &gt;+ Component::Combinator(Combinator::PseudoElement), &gt;+ Component::PseudoElement(PseudoElement::After), &gt;+ ], &gt;+ specificity(0, 0, 2) | HAS_PSEUDO_BIT, &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse("#d1 &gt; .ok"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::ID(DummyAtom::from("d1")), &gt;- Component::Combinator(Combinator::Child), &gt;- Component::Class(DummyAtom::from("ok")), &gt;- ], &gt;- (1 &lt;&lt; 20) + (1 &lt;&lt; 10) + (0 &lt;&lt; 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![ &gt;+ Component::ID(DummyAtom::from("d1")), &gt;+ Component::Combinator(Combinator::Child), &gt;+ Component::Class(DummyAtom::from("ok")), &gt;+ ], &gt;+ (1 &lt;&lt; 20) + (1 &lt;&lt; 10) + (0 &lt;&lt; 0), &gt;+ ),])) &gt; ); &gt; parser.default_ns = None; &gt; assert!(parse(":not(#provel.old)").is_err()); &gt; assert!(parse(":not(#provel &gt; old)").is_err()); &gt; assert!(parse("table[rules]:not([rules=\"none\"]):not([rules=\"\"])").is_ok()); &gt; assert_eq!( &gt; parse(":not(#provel)"), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::Negation( &gt;- vec![Component::ID(DummyAtom::from("provel"))].into_boxed_slice().into(), &gt;- ), &gt;- ], &gt;- specificity(1, 0, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::Negation( &gt;+ vec![Component::ID(DummyAtom::from("provel"))] &gt;+ .into_boxed_slice() &gt;+ .into(), &gt;+ ),], &gt;+ specificity(1, 0, 0), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse_ns(":not(svg|circle)", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::Negation( &gt; vec![ &gt;- Component::Negation( &gt;- vec![ &gt;- Component::Namespace(DummyAtom("svg".into()), SVG.into()), &gt;- Component::LocalName(LocalName { &gt;- name: DummyAtom::from("circle"), &gt;- lower_name: DummyAtom::from("circle"), &gt;- }), &gt;- ].into_boxed_slice().into(), &gt;- ), &gt;- ], &gt;- specificity(0, 0, 1), &gt;- ), &gt;- ])) &gt;+ Component::Namespace(DummyAtom("svg".into()), SVG.into()), &gt;+ Component::LocalName(LocalName { &gt;+ name: DummyAtom::from("circle"), &gt;+ lower_name: DummyAtom::from("circle"), &gt;+ }), &gt;+ ].into_boxed_slice() &gt;+ .into(), &gt;+ ),], &gt;+ specificity(0, 0, 1), &gt;+ ),])) &gt; ); &gt; // https://github.com/servo/servo/issues/16017 &gt; assert_eq!( &gt; parse_ns(":not(*)", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::Negation( &gt;- vec![Component::ExplicitUniversalType].into_boxed_slice().into(), &gt;- ), &gt;- ], &gt;- specificity(0, 0, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::Negation( &gt;+ vec![Component::ExplicitUniversalType] &gt;+ .into_boxed_slice() &gt;+ .into(), &gt;+ ),], &gt;+ specificity(0, 0, 0), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse_ns(":not(|*)", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::Negation( &gt; vec![ &gt;- Component::Negation( &gt;- vec![ &gt;- Component::ExplicitNoNamespace, &gt;- Component::ExplicitUniversalType, &gt;- ].into_boxed_slice().into(), &gt;- ), &gt;- ], &gt;- specificity(0, 0, 0), &gt;- ), &gt;- ])) &gt;+ Component::ExplicitNoNamespace, &gt;+ Component::ExplicitUniversalType, &gt;+ ].into_boxed_slice() &gt;+ .into(), &gt;+ ),], &gt;+ specificity(0, 0, 0), &gt;+ ),])) &gt; ); &gt; // *| should be elided if there is no default namespace. &gt; // https://github.com/servo/servo/pull/17537 &gt; assert_eq!( &gt; parse_ns_expected(":not(*|*)", &amp;parser, Some(":not(*)")), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;- vec![ &gt;- Component::Negation( &gt;- vec![Component::ExplicitUniversalType].into_boxed_slice().into(), &gt;- ), &gt;- ], &gt;- specificity(0, 0, 0), &gt;- ), &gt;- ])) &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::Negation( &gt;+ vec![Component::ExplicitUniversalType] &gt;+ .into_boxed_slice() &gt;+ .into(), &gt;+ ),], &gt;+ specificity(0, 0, 0), &gt;+ ),])) &gt; ); &gt; assert_eq!( &gt; parse_ns(":not(svg|*)", &amp;parser), &gt;- Ok(SelectorList::from_vec(vec![ &gt;- Selector::from_vec( &gt;+ Ok(SelectorList::from_vec(vec![Selector::from_vec( &gt;+ vec![Component::Negation( &gt; vec![ &gt;- Component::Negation( &gt;- vec![ &gt;- Component::Namespace(DummyAtom("svg".into()), SVG.into()), &gt;- Component::ExplicitUniversalType, &gt;- ].into_boxed_slice().into(), &gt;- ), &gt;- ], &gt;- specificity(0, 0, 0), &gt;- ), &gt;- ])) &gt;+ Component::Namespace(DummyAtom("svg".into()), SVG.into()), &gt;+ Component::ExplicitUniversalType, &gt;+ ].into_boxed_slice() &gt;+ .into(), &gt;+ ),], &gt;+ specificity(0, 0, 0), &gt;+ ),])) &gt; ); &gt; &gt; assert!(parse("::slotted()").is_err()); &gt; assert!(parse("::slotted(div)").is_ok()); &gt; assert!(parse("::slotted(div).foo").is_err()); &gt; assert!(parse("::slotted(div + bar)").is_err()); &gt; assert!(parse("::slotted(div) + foo").is_err()); &gt; assert!(parse("div ::slotted(div)").is_ok()); &gt;@@ -2902,17 +2840,17 @@ pub mod tests { &gt; } &gt; &gt; #[test] &gt; fn test_universal() { &gt; let selector = &amp;parse_ns( &gt; "*|*::before", &gt; &amp;DummyParser::default_with_namespace(DummyAtom::from("https://mozilla.org")), &gt; ).unwrap() &gt;- .0[0]; &gt;+ .0[0]; &gt; assert!(selector.is_universal()); &gt; } &gt; &gt; #[test] &gt; fn test_empty_pseudo_iter() { &gt; let selector = &amp;parse("::before").unwrap().0[0]; &gt; assert!(selector.is_universal()); &gt; let mut iter = selector.iter(); &gt;diff --git a/servo/components/servo_arc/lib.rs b/servo/components/servo_arc/lib.rs &gt;index 3e6cd65e85da..9163895c606f 100644 &gt;--- a/servo/components/servo_arc/lib.rs &gt;+++ b/servo/components/servo_arc/lib.rs &gt;@@ -27,32 +27,32 @@ extern crate nodrop; &gt; #[cfg(feature = "servo")] &gt; extern crate serde; &gt; extern crate stable_deref_trait; &gt; &gt; use nodrop::NoDrop; &gt; #[cfg(feature = "servo")] &gt; use serde::{Deserialize, Serialize}; &gt; use stable_deref_trait::{CloneStableDeref, StableDeref}; &gt;-use std::{isize, usize}; &gt; use std::borrow; &gt; use std::cmp::Ordering; &gt; use std::convert::From; &gt; use std::fmt; &gt; use std::hash::{Hash, Hasher}; &gt; use std::iter::{ExactSizeIterator, Iterator}; &gt; use std::marker::PhantomData; &gt; use std::mem; &gt; use std::ops::{Deref, DerefMut}; &gt; use std::os::raw::c_void; &gt; use std::process; &gt; use std::ptr; &gt; use std::slice; &gt; use std::sync::atomic; &gt; use std::sync::atomic::Ordering::{Acquire, Relaxed, Release}; &gt;+use std::{isize, usize}; &gt; &gt; // Private macro to get the offset of a struct field in bytes from the address of the struct. &gt; macro_rules! offset_of { &gt; ($container:path, $field:ident) =&gt; {{ &gt; // Make sure the field actually exists. This line ensures that a compile-time error is &gt; // generated if $field is accessed through a Deref impl. &gt; let $container { $field: _, .. }; &gt; &gt;@@ -1106,21 +1106,21 @@ impl&lt;A: 'static, B: 'static&gt; Drop for ArcUnion&lt;A, B&gt; { &gt; impl&lt;A: fmt::Debug, B: fmt::Debug&gt; fmt::Debug for ArcUnion&lt;A, B&gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; fmt::Debug::fmt(&amp;self.borrow(), f) &gt; } &gt; } &gt; &gt; #[cfg(test)] &gt; mod tests { &gt;+ use super::{Arc, HeaderWithLength, ThinArc}; &gt; use std::clone::Clone; &gt; use std::ops::Drop; &gt; use std::sync::atomic; &gt; use std::sync::atomic::Ordering::{Acquire, SeqCst}; &gt;- use super::{Arc, HeaderWithLength, ThinArc}; &gt; &gt; #[derive(PartialEq)] &gt; struct Canary(*mut atomic::AtomicUsize); &gt; &gt; impl Drop for Canary { &gt; fn drop(&amp;mut self) { &gt; unsafe { &gt; (*self.0).fetch_add(1, SeqCst); &gt;diff --git a/servo/components/size_of_test/lib.rs b/servo/components/size_of_test/lib.rs &gt;index fdd2cd62ec9e..f190c24599de 100644 &gt;--- a/servo/components/size_of_test/lib.rs &gt;+++ b/servo/components/size_of_test/lib.rs &gt;@@ -8,21 +8,27 @@ macro_rules! size_of_test { &gt; #[test] &gt; fn $testname() { &gt; let new = ::std::mem::size_of::&lt;$t&gt;(); &gt; let old = $expected_size; &gt; if new &lt; old { &gt; panic!( &gt; "Your changes have decreased the stack size of {} from {} to {}. \ &gt; Good work! Please update the expected size in {}.", &gt;- stringify!($t), old, new, file!() &gt;+ stringify!($t), &gt;+ old, &gt;+ new, &gt;+ file!() &gt; ) &gt; } else if new &gt; old { &gt; panic!( &gt; "Your changes have increased the stack size of {} from {} to {}. \ &gt; Please consider choosing a design which avoids this increase. \ &gt; If you feel that the increase is necessary, update the size in {}.", &gt;- stringify!($t), old, new, file!() &gt;+ stringify!($t), &gt;+ old, &gt;+ new, &gt;+ file!() &gt; ) &gt; } &gt; } &gt;- } &gt;+ }; &gt; } &gt;diff --git a/servo/components/style/animation.rs b/servo/components/style/animation.rs &gt;index 2d421ce06a93..cd2bd8fd785b 100644 &gt;--- a/servo/components/style/animation.rs &gt;+++ b/servo/components/style/animation.rs &gt;@@ -1,34 +1,34 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! CSS transitions and animations. &gt; &gt;-use Atom; &gt; use bezier::Bezier; &gt; use context::SharedStyleContext; &gt; use dom::{OpaqueNode, TElement}; &gt; use font_metrics::FontMetricsProvider; &gt;-use properties::{self, CascadeMode, ComputedValues, LonghandId}; &gt; use properties::animated_properties::AnimatedProperty; &gt; use properties::longhands::animation_direction::computed_value::single_value::T as AnimationDirection; &gt; use properties::longhands::animation_play_state::computed_value::single_value::T as AnimationPlayState; &gt;+use properties::{self, CascadeMode, ComputedValues, LonghandId}; &gt; use rule_tree::CascadeLevel; &gt; use servo_arc::Arc; &gt; use std::fmt; &gt; use std::sync::mpsc::Sender; &gt; use stylesheets::keyframes_rule::{KeyframesAnimation, KeyframesStep, KeyframesStepValue}; &gt; use timer::Timer; &gt;-use values::computed::Time; &gt; use values::computed::box_::TransitionProperty; &gt; use values::computed::transform::TimingFunction; &gt;+use values::computed::Time; &gt; use values::generics::box_::AnimationIterationCount; &gt; use values::generics::transform::{StepPosition, TimingFunction as GenericTimingFunction}; &gt;+use Atom; &gt; &gt; /// This structure represents a keyframes animation current iteration state. &gt; /// &gt; /// If the iteration count is infinite, there's no other state, otherwise we &gt; /// have to keep track the current iteration and the max iteration count. &gt; #[derive(Clone, Debug)] &gt; pub enum KeyframesIterationState { &gt; /// Infinite iterations, so no need to track a state. &gt;@@ -85,17 +85,17 @@ impl KeyframesAnimationState { &gt; pub fn tick(&amp;mut self) -&gt; bool { &gt; debug!("KeyframesAnimationState::tick"); &gt; debug_assert!(!self.expired); &gt; &gt; self.started_at += self.duration + self.delay; &gt; match self.running_state { &gt; // If it's paused, don't update direction or iteration count. &gt; KeyframesRunningState::Paused(_) =&gt; return true, &gt;- KeyframesRunningState::Running =&gt; {}, &gt;+ KeyframesRunningState::Running =&gt; {} &gt; } &gt; &gt; if let KeyframesIterationState::Finite(ref mut current, ref max) = self.iteration_state { &gt; *current += 1.0; &gt; // NB: This prevent us from updating the direction, which might be &gt; // needed for the correct handling of animation-fill-mode. &gt; if *current &gt;= *max { &gt; return false; &gt;@@ -105,18 +105,18 @@ impl KeyframesAnimationState { &gt; // Update the next iteration direction if applicable. &gt; match self.direction { &gt; AnimationDirection::Alternate | AnimationDirection::AlternateReverse =&gt; { &gt; self.current_direction = match self.current_direction { &gt; AnimationDirection::Normal =&gt; AnimationDirection::Reverse, &gt; AnimationDirection::Reverse =&gt; AnimationDirection::Normal, &gt; _ =&gt; unreachable!(), &gt; }; &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; &gt; true &gt; } &gt; &gt; /// Updates the appropiate state from other animation. &gt; /// &gt; /// This happens when an animation is re-submitted to layout, presumably &gt;@@ -147,33 +147,33 @@ impl KeyframesAnimationState { &gt; // restore it. &gt; // &gt; // If the animation keeps paused, keep the old value. &gt; // &gt; // If we're pausing the animation, compute the progress value. &gt; match (&amp;mut self.running_state, old_running_state) { &gt; (&amp;mut Running, Paused(progress)) =&gt; { &gt; new_started_at = timer.seconds() - (self.duration * progress) &gt;- }, &gt;+ } &gt; (&amp;mut Paused(ref mut new), Paused(old)) =&gt; *new = old, &gt; (&amp;mut Paused(ref mut progress), Running) =&gt; { &gt; *progress = (timer.seconds() - old_started_at) / old_duration &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; &gt; // Don't update the iteration count, just the iteration limit. &gt; // TODO: see how changing the limit affects rendering in other browsers. &gt; // We might need to keep the iteration count even when it's infinite. &gt; match (&amp;mut self.iteration_state, old_iteration_state) { &gt; ( &gt; &amp;mut KeyframesIterationState::Finite(ref mut iters, _), &gt; KeyframesIterationState::Finite(old_iters, _), &gt; ) =&gt; *iters = old_iters, &gt;- _ =&gt; {}, &gt;+ _ =&gt; {} &gt; } &gt; &gt; self.current_direction = old_direction; &gt; self.started_at = new_started_at; &gt; } &gt; &gt; #[inline] &gt; fn is_paused(&amp;self) -&gt; bool { &gt;@@ -208,17 +208,22 @@ pub enum Animation { &gt; /// the f64 field is the start time as returned by `time::precise_time_s()`. &gt; /// &gt; /// The `bool` field is werther this animation should no longer run. &gt; Transition(OpaqueNode, f64, AnimationFrame, bool), &gt; /// A keyframes animation is identified by a name, and can have a &gt; /// node-dependent state (i.e. iteration count, etc.). &gt; /// &gt; /// TODO(emilio): The animation object could be refcounted. &gt;- Keyframes(OpaqueNode, KeyframesAnimation, Atom, KeyframesAnimationState), &gt;+ Keyframes( &gt;+ OpaqueNode, &gt;+ KeyframesAnimation, &gt;+ Atom, &gt;+ KeyframesAnimationState, &gt;+ ), &gt; } &gt; &gt; impl Animation { &gt; /// Mark this animation as expired. &gt; #[inline] &gt; pub fn mark_as_expired(&amp;mut self) { &gt; debug_assert!(!self.is_expired()); &gt; match *self { &gt;@@ -299,44 +304,42 @@ impl PropertyAnimation { &gt; ) -&gt; Vec&lt;PropertyAnimation&gt; { &gt; let mut result = vec![]; &gt; let box_style = new_style.get_box(); &gt; let transition_property = box_style.transition_property_at(transition_index); &gt; let timing_function = box_style.transition_timing_function_mod(transition_index); &gt; let duration = box_style.transition_duration_mod(transition_index); &gt; &gt; match transition_property { &gt;- TransitionProperty::Custom(..) | &gt;- TransitionProperty::Unsupported(..) =&gt; result, &gt;+ TransitionProperty::Custom(..) | TransitionProperty::Unsupported(..) =&gt; result, &gt; TransitionProperty::Shorthand(ref shorthand_id) =&gt; shorthand_id &gt; .longhands() &gt; .filter_map(|longhand| { &gt; PropertyAnimation::from_longhand( &gt; longhand, &gt; timing_function, &gt; duration, &gt; old_style, &gt; new_style, &gt; ) &gt;- }) &gt;- .collect(), &gt;+ }).collect(), &gt; TransitionProperty::Longhand(longhand_id) =&gt; { &gt; let animation = PropertyAnimation::from_longhand( &gt; longhand_id, &gt; timing_function, &gt; duration, &gt; old_style, &gt; new_style, &gt; ); &gt; &gt; if let Some(animation) = animation { &gt; result.push(animation); &gt; } &gt; result &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; fn from_longhand( &gt; longhand: LonghandId, &gt; timing_function: TimingFunction, &gt; duration: Time, &gt; old_style: &amp;ComputedValues, &gt;@@ -358,43 +361,43 @@ impl PropertyAnimation { &gt; } &gt; &gt; /// Update the given animation at a given point of progress. &gt; pub fn update(&amp;self, style: &amp;mut ComputedValues, time: f64) { &gt; let epsilon = 1. / (200. * (self.duration.seconds() as f64)); &gt; let progress = match self.timing_function { &gt; GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } =&gt; { &gt; Bezier::new(x1, y1, x2, y2).solve(time, epsilon) &gt;- }, &gt;+ } &gt; GenericTimingFunction::Steps(steps, StepPosition::Start) =&gt; { &gt; (time * (steps as f64)).ceil() / (steps as f64) &gt;- }, &gt;+ } &gt; GenericTimingFunction::Steps(steps, StepPosition::End) =&gt; { &gt; (time * (steps as f64)).floor() / (steps as f64) &gt;- }, &gt;+ } &gt; GenericTimingFunction::Frames(frames) =&gt; { &gt; // https://drafts.csswg.org/css-timing/#frames-timing-functions &gt; let mut out = (time * (frames as f64)).floor() / ((frames - 1) as f64); &gt; if out &gt; 1.0 { &gt; // FIXME: Basically, during the animation sampling process, the input progress &gt; // should be in the range of [0, 1]. However, |time| is not accurate enough &gt; // here, which means |time| could be larger than 1.0 in the last animation &gt; // frame. (It should be equal to 1.0 exactly.) This makes the output of frames &gt; // timing function jumps to the next frame/level. &gt; // However, this solution is still not correct because |time| is possible &gt; // outside the range of [0, 1] after introducing Web Animations. We should fix &gt; // this problem when implementing web animations. &gt; out = 1.0; &gt; } &gt; out &gt;- }, &gt;+ } &gt; GenericTimingFunction::Keyword(keyword) =&gt; { &gt; let (x1, x2, y1, y2) = keyword.to_bezier(); &gt; Bezier::new(x1, x2, y1, y2).solve(time, epsilon) &gt;- }, &gt;+ } &gt; }; &gt; &gt; self.property.update(style, progress); &gt; } &gt; &gt; #[inline] &gt; fn does_animate(&amp;self) -&gt; bool { &gt; self.property.does_animate() &amp;&amp; self.duration.seconds() != 0.0 &gt;@@ -450,18 +453,17 @@ pub fn start_transitions_if_applicable( &gt; .send(Animation::Transition( &gt; opaque_node, &gt; start_time, &gt; AnimationFrame { &gt; duration: box_style.transition_duration_mod(i).seconds() as f64, &gt; property_animation: property_animation, &gt; }, &gt; /* is_expired = */ false, &gt;- )) &gt;- .unwrap(); &gt;+ )).unwrap(); &gt; &gt; had_animations = true; &gt; } &gt; } &gt; &gt; had_animations &gt; } &gt; &gt;@@ -500,24 +502,26 @@ where &gt; /* pseudo = */ None, &gt; previous_style.rules(), &gt; &amp;context.guards, &gt; iter, &gt; Some(previous_style), &gt; Some(previous_style), &gt; Some(previous_style), &gt; font_metrics_provider, &gt;- CascadeMode::Unvisited { visited_rules: None }, &gt;+ CascadeMode::Unvisited { &gt;+ visited_rules: None, &gt;+ }, &gt; context.quirks_mode(), &gt; /* rule_cache = */ None, &gt; &amp;mut Default::default(), &gt; /* element = */ None, &gt; ); &gt; computed &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Triggers animations for a given node looking at the animation property &gt; /// values. &gt; pub fn maybe_start_animations&lt;E&gt;( &gt; element: E, &gt; context: &amp;SharedStyleContext, &gt;@@ -564,20 +568,20 @@ where &gt; AnimationIterationCount::Number(n) =&gt; KeyframesIterationState::Finite(0.0, n), &gt; }; &gt; &gt; let animation_direction = box_style.animation_direction_mod(i); &gt; &gt; let initial_direction = match animation_direction { &gt; AnimationDirection::Normal | AnimationDirection::Alternate =&gt; { &gt; AnimationDirection::Normal &gt;- }, &gt;+ } &gt; AnimationDirection::Reverse | AnimationDirection::AlternateReverse =&gt; { &gt; AnimationDirection::Reverse &gt;- }, &gt;+ } &gt; }; &gt; &gt; let running_state = match box_style.animation_play_state_mod(i) { &gt; AnimationPlayState::Paused =&gt; KeyframesRunningState::Paused(0.), &gt; AnimationPlayState::Running =&gt; KeyframesRunningState::Running, &gt; }; &gt; &gt; new_animations_sender &gt;@@ -591,18 +595,17 @@ where &gt; delay: delay as f64, &gt; iteration_state: iteration_state, &gt; running_state: running_state, &gt; direction: animation_direction, &gt; current_direction: initial_direction, &gt; expired: false, &gt; cascade_style: new_style.clone(), &gt; }, &gt;- )) &gt;- .unwrap(); &gt;+ )).unwrap(); &gt; had_animations = true; &gt; } &gt; } &gt; &gt; had_animations &gt; } &gt; &gt; /// Updates a given computed style for a given animation frame. Returns a bool &gt;@@ -646,17 +649,17 @@ pub fn update_style_for_animation&lt;E&gt;( &gt; debug!("update_style_for_animation: transition found"); &gt; let now = context.timer.seconds(); &gt; let mut new_style = (*style).clone(); &gt; let updated_style = &gt; update_style_for_animation_frame(&amp;mut new_style, now, start_time, frame); &gt; if updated_style { &gt; *style = new_style &gt; } &gt;- }, &gt;+ } &gt; Animation::Keyframes(_, ref animation, ref name, ref state) =&gt; { &gt; debug!( &gt; "update_style_for_animation: animation found: \"{}\", {:?}", &gt; name, state &gt; ); &gt; let duration = state.duration; &gt; let started_at = state.started_at; &gt; &gt;@@ -675,17 +678,17 @@ pub fn update_style_for_animation&lt;E&gt;( &gt; let index = match maybe_index { &gt; Some(index) =&gt; index, &gt; None =&gt; { &gt; warn!( &gt; "update_style_for_animation: Animation {:?} not found in style", &gt; name &gt; ); &gt; return; &gt;- }, &gt;+ } &gt; }; &gt; &gt; let total_duration = style.get_box().animation_duration_mod(index).seconds() as f64; &gt; if total_duration == 0. { &gt; debug!( &gt; "update_style_for_animation: zero duration for animation {:?}", &gt; name &gt; ); &gt;@@ -714,65 +717,64 @@ pub fn update_style_for_animation&lt;E&gt;( &gt; target_keyframe_position = animation &gt; .steps &gt; .iter() &gt; .position(|step| total_progress as f32 &lt;= step.start_percentage.0); &gt; &gt; last_keyframe_position = target_keyframe_position &gt; .and_then(|pos| if pos != 0 { Some(pos - 1) } else { None }) &gt; .unwrap_or(0); &gt;- }, &gt;+ } &gt; AnimationDirection::Reverse =&gt; { &gt; target_keyframe_position = animation &gt; .steps &gt; .iter() &gt; .rev() &gt; .position(|step| total_progress as f32 &lt;= 1. - step.start_percentage.0) &gt; .map(|pos| animation.steps.len() - pos - 1); &gt; &gt; last_keyframe_position = target_keyframe_position &gt; .and_then(|pos| { &gt; if pos != animation.steps.len() - 1 { &gt; Some(pos + 1) &gt; } else { &gt; None &gt; } &gt;- }) &gt;- .unwrap_or(animation.steps.len() - 1); &gt;- }, &gt;+ }).unwrap_or(animation.steps.len() - 1); &gt;+ } &gt; _ =&gt; unreachable!(), &gt; } &gt; &gt; debug!( &gt; "update_style_for_animation: keyframe from {:?} to {:?}", &gt; last_keyframe_position, target_keyframe_position &gt; ); &gt; &gt; let target_keyframe = match target_keyframe_position { &gt; Some(target) =&gt; &amp;animation.steps[target], &gt; None =&gt; { &gt; warn!("update_style_for_animation: No current keyframe found for animation \"{}\" at progress {}", &gt; name, total_progress); &gt; return; &gt;- }, &gt;+ } &gt; }; &gt; &gt; let last_keyframe = &amp;animation.steps[last_keyframe_position]; &gt; &gt; let relative_timespan = &gt; (target_keyframe.start_percentage.0 - last_keyframe.start_percentage.0).abs(); &gt; let relative_duration = relative_timespan as f64 * duration; &gt; let last_keyframe_ended_at = match state.current_direction { &gt; AnimationDirection::Normal =&gt; { &gt; state.started_at + (total_duration * last_keyframe.start_percentage.0 as f64) &gt;- }, &gt;+ } &gt; AnimationDirection::Reverse =&gt; { &gt;- state.started_at + &gt;- (total_duration * (1. - last_keyframe.start_percentage.0 as f64)) &gt;- }, &gt;+ state.started_at &gt;+ + (total_duration * (1. - last_keyframe.start_percentage.0 as f64)) &gt;+ } &gt; _ =&gt; unreachable!(), &gt; }; &gt; let relative_progress = (now - last_keyframe_ended_at) / relative_duration; &gt; &gt; // TODO: How could we optimise it? Is it such a big deal? &gt; let from_style = compute_style_for_animation_step::&lt;E&gt;( &gt; context, &gt; last_keyframe, &gt;@@ -816,32 +818,32 @@ pub fn update_style_for_animation&lt;E&gt;( &gt; match animation { &gt; Some(property_animation) =&gt; { &gt; debug!( &gt; "update_style_for_animation: got property animation for prop {:?}", &gt; property &gt; ); &gt; debug!("update_style_for_animation: {:?}", property_animation); &gt; property_animation.update(Arc::make_mut(&amp;mut new_style), relative_progress); &gt;- }, &gt;+ } &gt; None =&gt; { &gt; debug!( &gt; "update_style_for_animation: property animation {:?} not animating", &gt; property &gt; ); &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; debug!( &gt; "update_style_for_animation: got style change in animation \"{}\"", &gt; name &gt; ); &gt; *style = new_style; &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Update the style in the node when it finishes. &gt; #[cfg(feature = "servo")] &gt; pub fn complete_expired_transitions( &gt; node: OpaqueNode, &gt; style: &amp;mut Arc&lt;ComputedValues&gt;, &gt;diff --git a/servo/components/style/applicable_declarations.rs b/servo/components/style/applicable_declarations.rs &gt;index a1476917fcbd..95a6f947ac60 100644 &gt;--- a/servo/components/style/applicable_declarations.rs &gt;+++ b/servo/components/style/applicable_declarations.rs &gt;@@ -33,17 +33,18 @@ const SOURCE_ORDER_MASK: u32 = SOURCE_ORDER_MAX &lt;&lt; SOURCE_ORDER_SHIFT; &gt; &gt; /// We store up-to-15 shadow order levels. &gt; /// &gt; /// You'd need an element slotted across 16 components with ::slotted rules to &gt; /// trigger this as of this writing, which looks... Unlikely. &gt; const SHADOW_CASCADE_ORDER_SHIFT: usize = SOURCE_ORDER_BITS; &gt; const SHADOW_CASCADE_ORDER_BITS: usize = 4; &gt; const SHADOW_CASCADE_ORDER_MAX: u8 = (1 &lt;&lt; SHADOW_CASCADE_ORDER_BITS) - 1; &gt;-const SHADOW_CASCADE_ORDER_MASK: u32 = (SHADOW_CASCADE_ORDER_MAX as u32) &lt;&lt; SHADOW_CASCADE_ORDER_SHIFT; &gt;+const SHADOW_CASCADE_ORDER_MASK: u32 = &gt;+ (SHADOW_CASCADE_ORDER_MAX as u32) &lt;&lt; SHADOW_CASCADE_ORDER_SHIFT; &gt; &gt; const CASCADE_LEVEL_SHIFT: usize = SOURCE_ORDER_BITS + SHADOW_CASCADE_ORDER_BITS; &gt; const CASCADE_LEVEL_BITS: usize = 4; &gt; const CASCADE_LEVEL_MAX: u8 = (1 &lt;&lt; CASCADE_LEVEL_BITS) - 1; &gt; const CASCADE_LEVEL_MASK: u32 = (CASCADE_LEVEL_MAX as u32) &lt;&lt; CASCADE_LEVEL_SHIFT; &gt; &gt; /// Stores the source order of a block, the cascade level it belongs to, and the &gt; /// counter needed to handle Shadow DOM cascade order properly. &gt;@@ -56,17 +57,18 @@ impl ApplicableDeclarationBits { &gt; cascade_level: CascadeLevel, &gt; shadow_cascade_order: ShadowCascadeOrder, &gt; ) -&gt; Self { &gt; debug_assert!( &gt; cascade_level as u8 &lt;= CASCADE_LEVEL_MAX, &gt; "Gotta find more bits!" &gt; ); &gt; let mut bits = ::std::cmp::min(source_order, SOURCE_ORDER_MAX); &gt;- bits |= ((shadow_cascade_order &amp; SHADOW_CASCADE_ORDER_MAX) as u32) &lt;&lt; SHADOW_CASCADE_ORDER_SHIFT; &gt;+ bits |= ((shadow_cascade_order &amp; SHADOW_CASCADE_ORDER_MAX) as u32) &gt;+ &lt;&lt; SHADOW_CASCADE_ORDER_SHIFT; &gt; bits |= (cascade_level as u8 as u32) &lt;&lt; CASCADE_LEVEL_SHIFT; &gt; ApplicableDeclarationBits(bits) &gt; } &gt; &gt; fn source_order(&amp;self) -&gt; u32 { &gt; (self.0 &amp; SOURCE_ORDER_MASK) &gt;&gt; SOURCE_ORDER_SHIFT &gt; } &gt; &gt;diff --git a/servo/components/style/attr.rs b/servo/components/style/attr.rs &gt;index 5f335472f324..41b7800071ab 100644 &gt;--- a/servo/components/style/attr.rs &gt;+++ b/servo/components/style/attr.rs &gt;@@ -1,31 +1,31 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Parsed representations of [DOM attributes][attr]. &gt; //! &gt; //! [attr]: https://dom.spec.whatwg.org/#interface-attr &gt; &gt;-use {Atom, LocalName, Namespace, Prefix}; &gt; use app_units::Au; &gt; use cssparser::{self, Color, RGBA}; &gt; use euclid::num::Zero; &gt; use num_traits::ToPrimitive; &gt; use properties::PropertyDeclarationBlock; &gt; use selectors::attr::AttrSelectorOperation; &gt; use servo_arc::Arc; &gt; use servo_url::ServoUrl; &gt; use shared_lock::Locked; &gt; use std::str::FromStr; &gt;+use str::str_join; &gt; use str::{read_exponent, read_fraction, HTML_SPACE_CHARACTERS}; &gt; use str::{read_numbers, split_commas, split_html_space_chars}; &gt;-use str::str_join; &gt; use values::specified::Length; &gt;+use {Atom, LocalName, Namespace, Prefix}; &gt; &gt; // Duplicated from script::dom::values. &gt; const UNSIGNED_LONG_MAX: u32 = 2147483647; &gt; &gt; #[derive(Clone, Copy, Debug, PartialEq)] &gt; #[cfg_attr(feature = "servo", derive(MallocSizeOf))] &gt; pub enum LengthOrPercentageOrAuto { &gt; Auto, &gt;@@ -78,21 +78,21 @@ fn do_parse_integer&lt;T: Iterator&lt;Item = char&gt;&gt;(input: T) -&gt; Result&lt;i64, ()&gt; { &gt; .skip_while(|c| HTML_SPACE_CHARACTERS.iter().any(|s| s == c)) &gt; .peekable(); &gt; &gt; let sign = match input.peek() { &gt; None =&gt; return Err(()), &gt; Some(&amp;'-') =&gt; { &gt; input.next(); &gt; -1 &gt;- }, &gt;+ } &gt; Some(&amp;'+') =&gt; { &gt; input.next(); &gt; 1 &gt;- }, &gt;+ } &gt; Some(_) =&gt; 1, &gt; }; &gt; &gt; let (value, _) = read_numbers(input); &gt; &gt; value.and_then(|value| value.checked_mul(sign)).ok_or(()) &gt; } &gt; &gt;@@ -114,21 +114,21 @@ pub fn parse_double(string: &amp;str) -&gt; Result&lt;f64, ()&gt; { &gt; let trimmed = string.trim_matches(HTML_SPACE_CHARACTERS); &gt; let mut input = trimmed.chars().peekable(); &gt; &gt; let (value, divisor, chars_skipped) = match input.peek() { &gt; None =&gt; return Err(()), &gt; Some(&amp;'-') =&gt; { &gt; input.next(); &gt; (-1f64, -1f64, 1) &gt;- }, &gt;+ } &gt; Some(&amp;'+') =&gt; { &gt; input.next(); &gt; (1f64, 1f64, 1) &gt;- }, &gt;+ } &gt; _ =&gt; (1f64, 1f64, 0), &gt; }; &gt; &gt; let (value, value_digits) = if let Some(&amp;'.') = input.peek() { &gt; (0f64, 0) &gt; } else { &gt; let (read_val, read_digits) = read_numbers(input); &gt; ( &gt;@@ -153,25 +153,25 @@ pub fn parse_double(string: &amp;str) -&gt; Result&lt;f64, ()&gt; { &gt; value *= 10f64.powi(exp) &gt; }; &gt; &gt; Ok(value) &gt; } &gt; &gt; impl AttrValue { &gt; pub fn from_serialized_tokenlist(tokens: String) -&gt; AttrValue { &gt;- let atoms = split_html_space_chars(&amp;tokens).map(Atom::from).fold( &gt;- vec![], &gt;- |mut acc, atom| { &gt;- if !acc.contains(&amp;atom) { &gt;- acc.push(atom) &gt;- } &gt;- acc &gt;- }, &gt;- ); &gt;+ let atoms = &gt;+ split_html_space_chars(&amp;tokens) &gt;+ .map(Atom::from) &gt;+ .fold(vec![], |mut acc, atom| { &gt;+ if !acc.contains(&amp;atom) { &gt;+ acc.push(atom) &gt;+ } &gt;+ acc &gt;+ }); &gt; AttrValue::TokenList(tokens, atoms) &gt; } &gt; &gt; pub fn from_comma_separated_tokenlist(tokens: String) -&gt; AttrValue { &gt; let atoms = split_commas(&amp;tokens) &gt; .map(Atom::from) &gt; .fold(vec![], |mut acc, atom| { &gt; if !acc.contains(&amp;atom) { &gt;@@ -374,26 +374,26 @@ impl AttrValue { &gt; } &gt; } &gt; &gt; impl ::std::ops::Deref for AttrValue { &gt; type Target = str; &gt; &gt; fn deref(&amp;self) -&gt; &amp;str { &gt; match *self { &gt;- AttrValue::String(ref value) | &gt;- AttrValue::TokenList(ref value, _) | &gt;- AttrValue::UInt(ref value, _) | &gt;- AttrValue::Double(ref value, _) | &gt;- AttrValue::Length(ref value, _) | &gt;- AttrValue::Color(ref value, _) | &gt;- AttrValue::Int(ref value, _) | &gt;- AttrValue::ResolvedUrl(ref value, _) | &gt;- AttrValue::Declaration(ref value, _) | &gt;- AttrValue::Dimension(ref value, _) =&gt; &amp;value, &gt;+ AttrValue::String(ref value) &gt;+ | AttrValue::TokenList(ref value, _) &gt;+ | AttrValue::UInt(ref value, _) &gt;+ | AttrValue::Double(ref value, _) &gt;+ | AttrValue::Length(ref value, _) &gt;+ | AttrValue::Color(ref value, _) &gt;+ | AttrValue::Int(ref value, _) &gt;+ | AttrValue::ResolvedUrl(ref value, _) &gt;+ | AttrValue::Declaration(ref value, _) &gt;+ | AttrValue::Dimension(ref value, _) =&gt; &amp;value, &gt; AttrValue::Atom(ref value) =&gt; &amp;value, &gt; } &gt; } &gt; } &gt; &gt; impl PartialEq&lt;Atom&gt; for AttrValue { &gt; fn eq(&amp;self, other: &amp;Atom) -&gt; bool { &gt; match *self { &gt;@@ -530,17 +530,17 @@ pub fn parse_legacy_color(mut input: &amp;str) -&gt; Result&lt;RGBA, ()&gt; { &gt; fn hex_string(string: &amp;[u8]) -&gt; Result&lt;u8, ()&gt; { &gt; match string.len() { &gt; 0 =&gt; Err(()), &gt; 1 =&gt; hex(string[0] as char), &gt; _ =&gt; { &gt; let upper = hex(string[0] as char)?; &gt; let lower = hex(string[1] as char)?; &gt; Ok((upper &lt;&lt; 4) | lower) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// Parses a [dimension value][dim]. If unparseable, `Auto` is returned. &gt; /// &gt; /// [dim]: https://html.spec.whatwg.org/multipage/#rules-for-parsing-dimension-values &gt; // TODO: this function can be rewritten to return Result&lt;LengthOrPercentage, _&gt; &gt;@@ -557,17 +557,17 @@ pub fn parse_length(mut value: &amp;str) -&gt; LengthOrPercentageOrAuto { &gt; &gt; // Step 5 &gt; if value.starts_with('+') { &gt; value = &amp;value[1..] &gt; } &gt; &gt; // Steps 6 &amp; 7 &gt; match value.chars().nth(0) { &gt;- Some('0'...'9') =&gt; {}, &gt;+ Some('0'...'9') =&gt; {} &gt; _ =&gt; return LengthOrPercentageOrAuto::Auto, &gt; } &gt; &gt; // Steps 8 to 13 &gt; // We trim the string length to the minimum of: &gt; // 1. the end of the string &gt; // 2. the first occurence of a '%' (U+0025 PERCENT SIGN) &gt; // 3. the second occurrence of a '.' (U+002E FULL STOP) &gt;@@ -577,25 +577,25 @@ pub fn parse_length(mut value: &amp;str) -&gt; LengthOrPercentageOrAuto { &gt; let (mut found_full_stop, mut found_percent) = (false, false); &gt; for (i, ch) in value.chars().enumerate() { &gt; match ch { &gt; '0'...'9' =&gt; continue, &gt; '%' =&gt; { &gt; found_percent = true; &gt; end_index = i; &gt; break; &gt;- }, &gt;+ } &gt; '.' if !found_full_stop =&gt; { &gt; found_full_stop = true; &gt; continue; &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; end_index = i; &gt; break; &gt;- }, &gt;+ } &gt; } &gt; } &gt; value = &amp;value[..end_index]; &gt; &gt; if found_percent { &gt; let result: Result&lt;f32, _&gt; = FromStr::from_str(value); &gt; match result { &gt; Ok(number) =&gt; return LengthOrPercentageOrAuto::Percentage((number as f32) / 100.0), &gt;diff --git a/servo/components/style/author_styles.rs b/servo/components/style/author_styles.rs &gt;index e8ec621bd92e..837569078c08 100644 &gt;--- a/servo/components/style/author_styles.rs &gt;+++ b/servo/components/style/author_styles.rs &gt;@@ -55,25 +55,27 @@ where &gt; &amp;mut self, &gt; device: &amp;Device, &gt; quirks_mode: QuirksMode, &gt; guard: &amp;SharedRwLockReadGuard, &gt; ) where &gt; E: TElement, &gt; S: ToMediaListKey, &gt; { &gt;- let flusher = self.stylesheets &gt;+ let flusher = self &gt;+ .stylesheets &gt; .flush::&lt;E&gt;(/* host = */ None, /* snapshot_map = */ None); &gt; &gt; if flusher.sheets.dirty() { &gt; self.quirks_mode = quirks_mode; &gt; } &gt; &gt; // Ignore OOM. &gt;- let _ = self.data &gt;+ let _ = self &gt;+ .data &gt; .rebuild(device, quirks_mode, flusher.sheets, guard); &gt; } &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt; unsafe impl HasFFI for AuthorStyles&lt;::gecko::data::GeckoStyleSheet&gt; { &gt; type FFIType = ::gecko_bindings::bindings::RawServoAuthorStyles; &gt; } &gt;diff --git a/servo/components/style/bloom.rs b/servo/components/style/bloom.rs &gt;index 613cbde49992..3f7cfc1626e0 100644 &gt;--- a/servo/components/style/bloom.rs &gt;+++ b/servo/components/style/bloom.rs &gt;@@ -277,17 +277,17 @@ impl&lt;E: TElement&gt; StyleBloom&lt;E&gt; { &gt; } &gt; &gt; let traversal_parent = match element.traversal_parent() { &gt; Some(parent) =&gt; parent, &gt; None =&gt; { &gt; // Yay, another easy case. &gt; self.clear(); &gt; return; &gt;- }, &gt;+ } &gt; }; &gt; &gt; if self.current_parent() == Some(traversal_parent) { &gt; // Ta da, cache hit, we're all done. &gt; return; &gt; } &gt; &gt; if element_depth == 0 { &gt;@@ -359,17 +359,17 @@ impl&lt;E: TElement&gt; StyleBloom&lt;E&gt; { &gt; Some(parent) =&gt; parent, &gt; None =&gt; { &gt; debug_assert!(self.elements.is_empty()); &gt; if cfg!(feature = "gecko") { &gt; break; &gt; } else { &gt; panic!("should have found a common ancestor"); &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; // Now the parents match, so insert the stack of elements we have been &gt; // collecting so far. &gt; for parent in parents_to_insert.drain().rev() { &gt; self.push(parent); &gt; } &gt;diff --git a/servo/components/style/build.rs b/servo/components/style/build.rs &gt;index 8de16176c346..82695d6d2a63 100644 &gt;--- a/servo/components/style/build.rs &gt;+++ b/servo/components/style/build.rs &gt;@@ -75,18 +75,18 @@ lazy_static! { &gt; } &gt; &gt; fn generate_properties() { &gt; for entry in WalkDir::new("properties") { &gt; let entry = entry.unwrap(); &gt; match entry.path().extension().and_then(|e| e.to_str()) { &gt; Some("mako") | Some("rs") | Some("py") | Some("zip") =&gt; { &gt; println!("cargo:rerun-if-changed={}", entry.path().display()); &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; } &gt; &gt; let script = Path::new(&amp;env::var_os("CARGO_MANIFEST_DIR").unwrap()) &gt; .join("properties") &gt; .join("build.py"); &gt; let product = if cfg!(feature = "gecko") { &gt; "gecko" &gt;diff --git a/servo/components/style/build_gecko.rs b/servo/components/style/build_gecko.rs &gt;index 8387f6513a68..7774265fc071 100644 &gt;--- a/servo/components/style/build_gecko.rs &gt;+++ b/servo/components/style/build_gecko.rs &gt;@@ -9,30 +9,30 @@ mod common { &gt; lazy_static! { &gt; pub static ref OUTDIR_PATH: PathBuf = &gt; PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("gecko"); &gt; } &gt; } &gt; &gt; #[cfg(feature = "bindgen")] &gt; mod bindings { &gt;+ use super::super::PYTHON; &gt;+ use super::common::*; &gt; use bindgen::{Builder, CodegenConfig}; &gt; use regex::Regex; &gt; use std::cmp; &gt; use std::collections::{HashMap, HashSet}; &gt; use std::env; &gt; use std::fs::{self, File}; &gt; use std::io::{Read, Write}; &gt; use std::path::{Path, PathBuf}; &gt; use std::process::{exit, Command}; &gt; use std::slice; &gt; use std::sync::Mutex; &gt; use std::time::SystemTime; &gt;- use super::common::*; &gt;- use super::super::PYTHON; &gt; use toml; &gt; use toml::value::Table; &gt; &gt; const STRUCTS_FILE: &amp;'static str = "structs.rs"; &gt; const BINDINGS_FILE: &amp;'static str = "bindings.rs"; &gt; &gt; fn read_config(path: &amp;PathBuf) -&gt; Table { &gt; println!("cargo:rerun-if-changed={}", path.to_str().unwrap()); &gt;@@ -278,17 +278,17 @@ mod bindings { &gt; let result = builder.generate(); &gt; let mut result = match result { &gt; Ok(bindings) =&gt; bindings.to_string(), &gt; Err(_) =&gt; { &gt; panic!( &gt; "Failed to generate bindings, flags: {:?}", &gt; command_line_opts &gt; ); &gt;- }, &gt;+ } &gt; }; &gt; &gt; for fixup in fixups.iter() { &gt; result = Regex::new(&amp;fixup.pat) &gt; .unwrap() &gt; .replace_all(&amp;result, &amp;*fixup.rep) &gt; .into_owned() &gt; .into(); &gt;@@ -317,23 +317,21 @@ mod bindings { &gt; .lines() &gt; .map(|line| line.trim()) &gt; .filter(|line| !line.is_empty()) &gt; .map(|line| { &gt; re.captures(&amp;line) &gt; .expect(&amp;format!( &gt; "Unrecognized line in ServoArcTypeList.h: '{}'", &gt; line &gt;- )) &gt;- .get(1) &gt;+ )).get(1) &gt; .unwrap() &gt; .as_str() &gt; .to_string() &gt;- }) &gt;- .collect() &gt;+ }).collect() &gt; } &gt; &gt; struct BuilderWithConfig&lt;'a&gt; { &gt; builder: Builder, &gt; config: &amp;'a Table, &gt; used_keys: HashSet&lt;&amp;'static str&gt;, &gt; } &gt; impl&lt;'a&gt; BuilderWithConfig&lt;'a&gt; { &gt;@@ -435,18 +433,17 @@ mod bindings { &gt; rep: format!("::gecko_bindings::structs::{}", gecko_name), &gt; }); &gt; builder.blacklist_type(gecko).raw_line(format!( &gt; "pub type {0}{2} = {1}{2};", &gt; gecko_name, &gt; servo, &gt; if generic { "&lt;T&gt;" } else { "" } &gt; )) &gt;- }) &gt;- .get_builder(); &gt;+ }).get_builder(); &gt; write_binding_file(builder, STRUCTS_FILE, &amp;fixups); &gt; } &gt; &gt; fn setup_logging() -&gt; bool { &gt; use log; &gt; &gt; struct BuildLogger { &gt; file: Option&lt;Mutex&lt;fs::File&gt;&gt;, &gt;@@ -555,18 +552,17 @@ mod bindings { &gt; .handle_str_items("servo-borrow-types", |b, ty| b.mutable_borrowed_type(ty)) &gt; .get_builder(); &gt; for ty in get_arc_types().iter() { &gt; builder = builder &gt; .blacklist_type(format!("{}Strong", ty)) &gt; .raw_line(format!( &gt; "pub type {0}Strong = ::gecko_bindings::sugar::ownership::Strong&lt;{0}&gt;;", &gt; ty &gt;- )) &gt;- .borrowed_type(ty) &gt;+ )).borrowed_type(ty) &gt; .zero_size_type(ty, &amp;structs_types); &gt; } &gt; write_binding_file(builder, BINDINGS_FILE, &amp;fixups); &gt; } &gt; &gt; fn generate_atoms() { &gt; let script = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()) &gt; .join("gecko") &gt;@@ -606,19 +602,19 @@ mod bindings { &gt; for path in ADDED_PATHS.lock().unwrap().iter() { &gt; println!("cargo:rerun-if-changed={}", path.to_str().unwrap()); &gt; } &gt; } &gt; } &gt; &gt; #[cfg(not(feature = "bindgen"))] &gt; mod bindings { &gt;+ use super::common::*; &gt;+ use std::path::{Path, PathBuf}; &gt; use std::{env, fs, io}; &gt;- use std::path::{Path, PathBuf}; &gt;- use super::common::*; &gt; &gt; /// Copy contents of one directory into another. &gt; /// It currently only does a shallow copy. &gt; fn copy_dir&lt;P, Q, F&gt;(from: P, to: Q, callback: F) -&gt; io::Result&lt;()&gt; &gt; where &gt; P: AsRef&lt;Path&gt;, &gt; Q: AsRef&lt;Path&gt;, &gt; F: Fn(&amp;Path), &gt;diff --git a/servo/components/style/context.rs b/servo/components/style/context.rs &gt;index 16bba2a863f4..8e3e05b53559 100644 &gt;--- a/servo/components/style/context.rs &gt;+++ b/servo/components/style/context.rs &gt;@@ -4,47 +4,47 @@ &gt; &gt; //! The context within which style is calculated. &gt; &gt; #[cfg(feature = "servo")] &gt; use animation::Animation; &gt; use app_units::Au; &gt; use bloom::StyleBloom; &gt; use data::{EagerPseudoStyles, ElementData}; &gt;-use dom::{SendElement, TElement}; &gt; #[cfg(feature = "servo")] &gt; use dom::OpaqueNode; &gt;+use dom::{SendElement, TElement}; &gt; use euclid::Size2D; &gt; use euclid::TypedScale; &gt; use font_metrics::FontMetricsProvider; &gt; use fxhash::FxHashMap; &gt; #[cfg(feature = "gecko")] &gt; use gecko_bindings::structs; &gt; use parallel::{STACK_SAFETY_MARGIN_KB, STYLE_THREAD_STACK_SIZE_KB}; &gt; #[cfg(feature = "servo")] &gt; use parking_lot::RwLock; &gt; use properties::ComputedValues; &gt; #[cfg(feature = "servo")] &gt; use properties::PropertyId; &gt; use rule_cache::RuleCache; &gt; use rule_tree::StrongRuleNode; &gt; use selector_parser::{SnapshotMap, EAGER_PSEUDO_COUNT}; &gt;-use selectors::NthIndexCache; &gt; use selectors::matching::ElementSelectorFlags; &gt;+use selectors::NthIndexCache; &gt; use servo_arc::Arc; &gt; #[cfg(feature = "servo")] &gt; use servo_atoms::Atom; &gt; use shared_lock::StylesheetGuards; &gt; use sharing::StyleSharingCache; &gt; use std::fmt; &gt; use std::ops; &gt; #[cfg(feature = "servo")] &gt;-use std::sync::Mutex; &gt;-#[cfg(feature = "servo")] &gt; use std::sync::mpsc::Sender; &gt;+#[cfg(feature = "servo")] &gt;+use std::sync::Mutex; &gt; use style_traits::CSSPixel; &gt; use style_traits::DevicePixel; &gt; #[cfg(feature = "servo")] &gt; use style_traits::SpeculativePainter; &gt; use stylist::Stylist; &gt; use thread_state::{self, ThreadState}; &gt; use time; &gt; use timer::Timer; &gt;@@ -523,21 +523,21 @@ impl&lt;E: TElement&gt; SequentialTask&lt;E&gt; { &gt; Unused(_) =&gt; unreachable!(), &gt; #[cfg(feature = "gecko")] &gt; UpdateAnimations { &gt; el, &gt; before_change_style, &gt; tasks, &gt; } =&gt; { &gt; el.update_animations(before_change_style, tasks); &gt;- }, &gt;+ } &gt; #[cfg(feature = "gecko")] &gt; PostAnimation { el, tasks } =&gt; { &gt; el.process_post_animation(tasks); &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Creates a task to update various animation-related state on a given &gt; /// (pseudo-)element. &gt; #[cfg(feature = "gecko")] &gt; pub fn update_animations( &gt; el: E, &gt;diff --git a/servo/components/style/counter_style/mod.rs b/servo/components/style/counter_style/mod.rs &gt;index 2542dee3625a..1b911ea5cf18 100644 &gt;--- a/servo/components/style/counter_style/mod.rs &gt;+++ b/servo/components/style/counter_style/mod.rs &gt;@@ -1,32 +1,32 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! The [`@counter-style`][counter-style] at-rule. &gt; //! &gt; //! [counter-style]: https://drafts.csswg.org/css-counter-styles/ &gt; &gt;-use Atom; &gt; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser}; &gt; use cssparser::{CowRcStr, Parser, SourceLocation, Token}; &gt; use error_reporting::ContextualParseError; &gt; use parser::{Parse, ParserContext}; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; &gt; use std::fmt::{self, Write}; &gt; use std::mem; &gt; use std::num::Wrapping; &gt; use std::ops::Range; &gt; use str::CssStringWriter; &gt; use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError}; &gt; use style_traits::{StyleParseErrorKind, ToCss}; &gt;-use values::CustomIdent; &gt; use values::specified::Integer; &gt;+use values::CustomIdent; &gt;+use Atom; &gt; &gt; /// Parse a counter style name reference. &gt; /// &gt; /// This allows the reserved counter style names "decimal" and "disc". &gt; pub fn parse_counter_style_name&lt;'i, 't&gt;( &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;CustomIdent, ParseError&lt;'i&gt;&gt; { &gt; macro_rules! predefined { &gt;@@ -86,52 +86,52 @@ pub fn parse_counter_style_body&lt;'i, 't&gt;( &gt; context: context, &gt; rule: &amp;mut rule, &gt; }; &gt; let mut iter = DeclarationListParser::new(input, parser); &gt; while let Some(declaration) = iter.next() { &gt; if let Err((error, slice)) = declaration { &gt; let location = error.location; &gt; let error = ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration( &gt;- slice, &gt;- error, &gt;+ slice, error, &gt; ); &gt; context.log_css_error(location, error) &gt; } &gt; } &gt; } &gt; let error = match *rule.resolved_system() { &gt;- ref system @ System::Cyclic | &gt;- ref system @ System::Fixed { .. } | &gt;- ref system @ System::Symbolic | &gt;- ref system @ System::Alphabetic | &gt;- ref system @ System::Numeric if rule.symbols.is_none() =&gt; &gt;+ ref system @ System::Cyclic &gt;+ | ref system @ System::Fixed { .. } &gt;+ | ref system @ System::Symbolic &gt;+ | ref system @ System::Alphabetic &gt;+ | ref system @ System::Numeric &gt;+ if rule.symbols.is_none() =&gt; &gt; { &gt; let system = system.to_css_string(); &gt; Some(ContextualParseError::InvalidCounterStyleWithoutSymbols( &gt; system, &gt; )) &gt; } &gt; ref system @ System::Alphabetic | ref system @ System::Numeric &gt; if rule.symbols().unwrap().0.len() &lt; 2 =&gt; &gt; { &gt; let system = system.to_css_string(); &gt; Some(ContextualParseError::InvalidCounterStyleNotEnoughSymbols( &gt; system, &gt; )) &gt; } &gt; System::Additive if rule.additive_symbols.is_none() =&gt; { &gt; Some(ContextualParseError::InvalidCounterStyleWithoutAdditiveSymbols) &gt;- }, &gt;+ } &gt; System::Extends(_) if rule.symbols.is_some() =&gt; { &gt; Some(ContextualParseError::InvalidCounterStyleExtendsWithSymbols) &gt;- }, &gt;+ } &gt; System::Extends(_) if rule.additive_symbols.is_some() =&gt; { &gt; Some(ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols) &gt;- }, &gt;+ } &gt; _ =&gt; None, &gt; }; &gt; if let Some(error) = error { &gt; context.log_css_error(start, error); &gt; Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt; } else { &gt; Ok(rule) &gt; } &gt;@@ -394,21 +394,21 @@ impl ToCss for System { &gt; System::Additive =&gt; dest.write_str("additive"), &gt; System::Fixed { first_symbol_value } =&gt; { &gt; if let Some(value) = first_symbol_value { &gt; dest.write_str("fixed ")?; &gt; value.to_css(dest) &gt; } else { &gt; dest.write_str("fixed") &gt; } &gt;- }, &gt;+ } &gt; System::Extends(ref other) =&gt; { &gt; dest.write_str("extends ")?; &gt; other.to_css(dest) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// &lt;https://drafts.csswg.org/css-counter-styles/#typedef-symbol&gt; &gt; #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] &gt; #[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss)] &gt; pub enum Symbol { &gt;@@ -491,22 +491,23 @@ impl Parse for Ranges { &gt; input &gt; .parse_comma_separated(|input| { &gt; let opt_start = parse_bound(context, input)?; &gt; let opt_end = parse_bound(context, input)?; &gt; if let (CounterBound::Integer(start), CounterBound::Integer(end)) = &gt; (opt_start, opt_end) &gt; { &gt; if start &gt; end { &gt;- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt;+ return Err( &gt;+ input.new_custom_error(StyleParseErrorKind::UnspecifiedError) &gt;+ ); &gt; } &gt; } &gt; Ok(opt_start..opt_end) &gt;- }) &gt;- .map(Ranges) &gt;+ }).map(Ranges) &gt; } &gt; } &gt; } &gt; &gt; fn parse_bound&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;CounterBound, ParseError&lt;'i&gt;&gt; { &gt;diff --git a/servo/components/style/custom_properties.rs b/servo/components/style/custom_properties.rs &gt;index d79a27c5c4d8..d0bbf53cba3f 100644 &gt;--- a/servo/components/style/custom_properties.rs &gt;+++ b/servo/components/style/custom_properties.rs &gt;@@ -1,30 +1,30 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Support for [custom properties for cascading variables][custom]. &gt; //! &gt; //! [custom]: https://drafts.csswg.org/css-variables/ &gt; &gt;-use Atom; &gt; use cssparser::{Delimiter, Parser, ParserInput, SourcePosition, Token, TokenSerializationType}; &gt; use hash::map::Entry; &gt; use precomputed_hash::PrecomputedHash; &gt; use properties::{CSSWideKeyword, DeclaredValue}; &gt; use selector_map::{PrecomputedHashMap, PrecomputedHashSet}; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use servo_arc::Arc; &gt; use smallvec::SmallVec; &gt; use std::borrow::{Borrow, Cow}; &gt; use std::cmp; &gt; use std::fmt::{self, Write}; &gt; use std::hash::Hash; &gt; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt;+use Atom; &gt; &gt; /// A custom property name is just an `Atom`. &gt; /// &gt; /// Note that this does not include the `--` prefix &gt; pub type Name = Atom; &gt; &gt; /// Parse a custom property name. &gt; /// &gt;@@ -113,20 +113,20 @@ where &gt; let OrderedMap { &gt; ref mut index, &gt; ref mut values, &gt; } = *self; &gt; match values.entry(key) { &gt; Entry::Vacant(mut entry) =&gt; { &gt; index.push(entry.key().clone()); &gt; entry.insert(value); &gt;- }, &gt;+ } &gt; Entry::Occupied(mut entry) =&gt; { &gt; entry.insert(value); &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Get a value given its key. &gt; pub fn get(&amp;self, key: &amp;K) -&gt; Option&lt;&amp;V&gt; { &gt; let value = self.values.get(key); &gt; debug_assert_eq!(value.is_some(), self.index.contains(key)); &gt; value &gt;@@ -238,17 +238,18 @@ impl VariableValue { &gt; // In that case, css_*_token_type is nonsensical. &gt; if css.is_empty() { &gt; return; &gt; } &gt; &gt; self.first_token_type.set_if_nothing(css_first_token_type); &gt; // If self.first_token_type was nothing, &gt; // self.last_token_type is also nothing and this will be false: &gt;- if self.last_token_type &gt;+ if self &gt;+ .last_token_type &gt; .needs_separator_when_before(css_first_token_type) &gt; { &gt; self.css.push_str("/**/") &gt; } &gt; self.css.push_str(css); &gt; self.last_token_type = css_last_token_type &gt; } &gt; &gt;@@ -340,17 +341,17 @@ fn parse_declaration_value_block&lt;'i, 't&gt;( &gt; let mut token = match input.next_including_whitespace_and_comments() { &gt; // FIXME: remove clone() when borrows are non-lexical &gt; Ok(token) =&gt; token.clone(), &gt; Err(_) =&gt; { &gt; return Ok(( &gt; TokenSerializationType::nothing(), &gt; TokenSerializationType::nothing(), &gt; )) &gt;- }, &gt;+ } &gt; }; &gt; let first_token_type = token.serialization_type(); &gt; loop { &gt; macro_rules! nested { &gt; () =&gt; { &gt; input.parse_nested_block(|input| { &gt; parse_declaration_value_block( &gt; input, &gt;@@ -373,93 +374,93 @@ fn parse_declaration_value_block&lt;'i, 't&gt;( &gt; if !token_slice.ends_with("*/") { &gt; missing_closing_characters.push_str(if token_slice.ends_with('*') { &gt; "/" &gt; } else { &gt; "*/" &gt; }) &gt; } &gt; token.serialization_type() &gt;- }, &gt;+ } &gt; Token::BadUrl(u) =&gt; { &gt; let e = StyleParseErrorKind::BadUrlInDeclarationValueBlock(u); &gt; return Err(input.new_custom_error(e)); &gt;- }, &gt;+ } &gt; Token::BadString(s) =&gt; { &gt; let e = StyleParseErrorKind::BadStringInDeclarationValueBlock(s); &gt; return Err(input.new_custom_error(e)); &gt;- }, &gt;+ } &gt; Token::CloseParenthesis =&gt; { &gt; let e = StyleParseErrorKind::UnbalancedCloseParenthesisInDeclarationValueBlock; &gt; return Err(input.new_custom_error(e)); &gt;- }, &gt;+ } &gt; Token::CloseSquareBracket =&gt; { &gt; let e = StyleParseErrorKind::UnbalancedCloseSquareBracketInDeclarationValueBlock; &gt; return Err(input.new_custom_error(e)); &gt;- }, &gt;+ } &gt; Token::CloseCurlyBracket =&gt; { &gt; let e = StyleParseErrorKind::UnbalancedCloseCurlyBracketInDeclarationValueBlock; &gt; return Err(input.new_custom_error(e)); &gt;- }, &gt;+ } &gt; Token::Function(ref name) =&gt; { &gt; if name.eq_ignore_ascii_case("var") { &gt; let args_start = input.state(); &gt; input.parse_nested_block(|input| { &gt; parse_var_function(input, references.as_mut().map(|r| &amp;mut **r)) &gt; })?; &gt; input.reset(&amp;args_start); &gt; } &gt; nested!(); &gt; check_closed!(")"); &gt; Token::CloseParenthesis.serialization_type() &gt;- }, &gt;+ } &gt; Token::ParenthesisBlock =&gt; { &gt; nested!(); &gt; check_closed!(")"); &gt; Token::CloseParenthesis.serialization_type() &gt;- }, &gt;+ } &gt; Token::CurlyBracketBlock =&gt; { &gt; nested!(); &gt; check_closed!("}"); &gt; Token::CloseCurlyBracket.serialization_type() &gt;- }, &gt;+ } &gt; Token::SquareBracketBlock =&gt; { &gt; nested!(); &gt; check_closed!("]"); &gt; Token::CloseSquareBracket.serialization_type() &gt;- }, &gt;+ } &gt; Token::QuotedString(_) =&gt; { &gt; let token_slice = input.slice_from(token_start); &gt; let quote = &amp;token_slice[..1]; &gt; debug_assert!(matches!(quote, "\"" | "'")); &gt; if !(token_slice.ends_with(quote) &amp;&amp; token_slice.len() &gt; 1) { &gt; missing_closing_characters.push_str(quote) &gt; } &gt; token.serialization_type() &gt;- }, &gt;- Token::Ident(ref value) | &gt;- Token::AtKeyword(ref value) | &gt;- Token::Hash(ref value) | &gt;- Token::IDHash(ref value) | &gt;- Token::UnquotedUrl(ref value) | &gt;- Token::Dimension { &gt;+ } &gt;+ Token::Ident(ref value) &gt;+ | Token::AtKeyword(ref value) &gt;+ | Token::Hash(ref value) &gt;+ | Token::IDHash(ref value) &gt;+ | Token::UnquotedUrl(ref value) &gt;+ | Token::Dimension { &gt; unit: ref value, .. &gt; } =&gt; { &gt; if value.ends_with("�") &amp;&amp; input.slice_from(token_start).ends_with("\\") { &gt; // Unescaped backslash at EOF in these contexts is interpreted as U+FFFD &gt; // Check the value in case the final backslash was itself escaped. &gt; // Serialize as escaped U+FFFD, which is also interpreted as U+FFFD. &gt; // (Unescaped U+FFFD would also work, but removing the backslash is annoying.) &gt; missing_closing_characters.push_str("�") &gt; } &gt; if matches!(token, Token::UnquotedUrl(_)) { &gt; check_closed!(")"); &gt; } &gt; token.serialization_type() &gt;- }, &gt;+ } &gt; _ =&gt; token.serialization_type(), &gt; }; &gt; &gt; token_start = input.position(); &gt; token = match input.next_including_whitespace_and_comments() { &gt; // FIXME: remove clone() when borrows are non-lexical &gt; Ok(token) =&gt; token.clone(), &gt; Err(..) =&gt; return Ok((first_token_type, last_token_type)), &gt;@@ -536,63 +537,64 @@ impl&lt;'a&gt; CustomPropertiesBuilder&lt;'a&gt; { &gt; }); &gt; } &gt; &gt; let map = self.custom_properties.as_mut().unwrap(); &gt; match specified_value { &gt; DeclaredValue::Value(ref specified_value) =&gt; { &gt; self.may_have_cycles |= !specified_value.references.is_empty(); &gt; map.insert(name.clone(), (*specified_value).clone()); &gt;- }, &gt;+ } &gt; DeclaredValue::WithVariables(_) =&gt; unreachable!(), &gt; DeclaredValue::CSSWideKeyword(keyword) =&gt; match keyword { &gt; CSSWideKeyword::Initial =&gt; { &gt; map.remove(name); &gt;- }, &gt;+ } &gt; // handled in value_may_affect_style &gt; CSSWideKeyword::Unset | CSSWideKeyword::Inherit =&gt; unreachable!(), &gt; }, &gt; } &gt; } &gt; &gt; fn value_may_affect_style( &gt; &amp;self, &gt; name: &amp;Name, &gt; value: &amp;DeclaredValue&lt;Arc&lt;SpecifiedValue&gt;&gt;, &gt; ) -&gt; bool { &gt; match *value { &gt;- DeclaredValue::CSSWideKeyword(CSSWideKeyword::Unset) | &gt;- DeclaredValue::CSSWideKeyword(CSSWideKeyword::Inherit) =&gt; { &gt;+ DeclaredValue::CSSWideKeyword(CSSWideKeyword::Unset) &gt;+ | DeclaredValue::CSSWideKeyword(CSSWideKeyword::Inherit) =&gt; { &gt; // Custom properties are inherited by default. So &gt; // explicit 'inherit' or 'unset' means we can just use &gt; // any existing value in the inherited CustomPropertiesMap. &gt; return false; &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; &gt;- let existing_value = self.custom_properties &gt;+ let existing_value = self &gt;+ .custom_properties &gt; .as_ref() &gt; .and_then(|m| m.get(name)) &gt; .or_else(|| self.inherited.and_then(|m| m.get(name))); &gt; &gt; match (existing_value, value) { &gt; (None, &amp;DeclaredValue::CSSWideKeyword(CSSWideKeyword::Initial)) =&gt; { &gt; // The initial value of a custom property is the same as it &gt; // not existing in the map. &gt; return false; &gt;- }, &gt;+ } &gt; (Some(existing_value), &amp;DeclaredValue::Value(specified_value)) =&gt; { &gt; // Don't bother overwriting an existing inherited value with &gt; // the same specified value. &gt; if existing_value == specified_value { &gt; return false; &gt; } &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; &gt; true &gt; } &gt; &gt; /// Returns the final map of applicable custom properties. &gt; /// &gt; /// If there was any specified property, we've created a new map and now we need &gt;@@ -690,21 +692,21 @@ fn substitute_all(custom_properties_map: &amp;mut CustomPropertiesMap) { &gt; if value.references.is_empty() || context.invalid.contains(&amp;name) { &gt; return None; &gt; } &gt; // Whether this variable has been visited in this traversal. &gt; let key; &gt; match context.index_map.entry(name) { &gt; Entry::Occupied(entry) =&gt; { &gt; return Some(*entry.get()); &gt;- }, &gt;+ } &gt; Entry::Vacant(entry) =&gt; { &gt; key = entry.key().clone(); &gt; entry.insert(context.count); &gt;- }, &gt;+ } &gt; } &gt; // Hold a strong reference to the value so that we don't &gt; // need to keep reference to context.map. &gt; (key, value.clone()) &gt; } else { &gt; // The variable doesn't exist at all. &gt; return None; &gt; }; &gt;@@ -723,17 +725,17 @@ fn substitute_all(custom_properties_map: &amp;mut CustomPropertiesMap) { &gt; let mut lowlink = index; &gt; for next in value.references.iter() { &gt; let next_index = match traverse(next.clone(), context) { &gt; Some(index) =&gt; index, &gt; // There is nothing to do if the next variable has been &gt; // fully resolved at this point. &gt; None =&gt; { &gt; continue; &gt;- }, &gt;+ } &gt; }; &gt; let next_info = &amp;context.var_info[next_index]; &gt; if next_index &gt; index { &gt; // The next variable has a larger index than us, so it &gt; // must be inserted in the recursive call above. We want &gt; // to get its lowlink. &gt; lowlink = cmp::min(lowlink, next_info.lowlink); &gt; } else if next_index == index { &gt;@@ -914,28 +916,28 @@ where &gt; partial_computed_value, &gt; substitute_one, &gt; )?; &gt; partial_computed_value.push_from(position, input, last_token_type); &gt; } &gt; Ok(()) &gt; })?; &gt; set_position_at_next_iteration = true &gt;- }, &gt;+ } &gt; &gt;- Token::Function(_) | &gt;- Token::ParenthesisBlock | &gt;- Token::CurlyBracketBlock | &gt;- Token::SquareBracketBlock =&gt; { &gt;+ Token::Function(_) &gt;+ | Token::ParenthesisBlock &gt;+ | Token::CurlyBracketBlock &gt;+ | Token::SquareBracketBlock =&gt; { &gt; input.parse_nested_block(|input| { &gt; substitute_block(input, position, partial_computed_value, substitute_one) &gt; })?; &gt; // It’s the same type for CloseCurlyBracket and CloseSquareBracket. &gt; last_token_type = Token::CloseParenthesis.serialization_type(); &gt;- }, &gt;+ } &gt; &gt; _ =&gt; last_token_type = token.serialization_type(), &gt; } &gt; } &gt; // FIXME: deal with things being implicitly closed at the end of the input. E.g. &gt; // ```html &gt; // &lt;div style="--color: rgb(0,0,0"&gt; &gt; // &lt;p style="background: var(--color) var(--image) top left; --image: url('a.png"&gt;&lt;/p&gt; &gt;diff --git a/servo/components/style/data.rs b/servo/components/style/data.rs &gt;index 71a0ac233207..7bb22d7ad335 100644 &gt;--- a/servo/components/style/data.rs &gt;+++ b/servo/components/style/data.rs &gt;@@ -267,22 +267,18 @@ impl ElementData { &gt; element.handled_snapshot(), &gt; element.implemented_pseudo_element() &gt; ); &gt; &gt; if !element.has_snapshot() || element.handled_snapshot() { &gt; return InvalidationResult::empty(); &gt; } &gt; &gt;- let mut processor = StateAndAttrInvalidationProcessor::new( &gt;- shared_context, &gt;- element, &gt;- self, &gt;- nth_index_cache, &gt;- ); &gt;+ let mut processor = &gt;+ StateAndAttrInvalidationProcessor::new(shared_context, element, self, nth_index_cache); &gt; &gt; let invalidator = TreeStyleInvalidator::new(element, stack_limit_checker, &amp;mut processor); &gt; &gt; let result = invalidator.invalidate(); &gt; &gt; unsafe { element.set_handled_snapshot() } &gt; debug_assert!(element.handled_snapshot()); &gt; &gt;@@ -300,17 +296,18 @@ impl ElementData { &gt; ResolvedElementStyles { &gt; primary: self.share_primary_style(), &gt; pseudos: self.styles.pseudos.clone(), &gt; } &gt; } &gt; &gt; /// Returns this element's primary style as a resolved style to use for sharing. &gt; pub fn share_primary_style(&amp;self) -&gt; PrimaryStyle { &gt;- let reused_via_rule_node = self.flags &gt;+ let reused_via_rule_node = self &gt;+ .flags &gt; .contains(ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE); &gt; &gt; PrimaryStyle { &gt; style: ResolvedStyle(self.styles.primary().clone()), &gt; reused_via_rule_node, &gt; } &gt; } &gt; &gt;@@ -385,17 +382,18 @@ impl ElementData { &gt; /// If it costs too much, get_properties_overriding_animations() should return a set &gt; /// containing only opacity and transform properties. &gt; pub fn important_rules_are_different( &gt; &amp;self, &gt; rules: &amp;StrongRuleNode, &gt; guards: &amp;StylesheetGuards, &gt; ) -&gt; bool { &gt; debug_assert!(self.has_styles()); &gt;- let (important_rules, _custom) = self.styles &gt;+ let (important_rules, _custom) = self &gt;+ .styles &gt; .primary() &gt; .rules() &gt; .get_properties_overriding_animations(&amp;guards); &gt; let (other_important_rules, _custom) = rules.get_properties_overriding_animations(&amp;guards); &gt; important_rules != other_important_rules &gt; } &gt; &gt; /// Drops any restyle state from the element. &gt;@@ -468,18 +466,18 @@ impl ElementData { &gt; /// ellided styling. &gt; /// &gt; /// Second, we want to only consider elements whose ComputedValues match due to a hit &gt; /// in the style sharing cache, rather than due to the rule-node-based reuse that &gt; /// happens later in the styling pipeline. The former gives us the stronger guarantees &gt; /// we need for style sharing, the latter does not. &gt; pub fn safe_for_cousin_sharing(&amp;self) -&gt; bool { &gt; !self.flags.intersects( &gt;- ElementDataFlags::TRAVERSED_WITHOUT_STYLING | &gt;- ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE, &gt;+ ElementDataFlags::TRAVERSED_WITHOUT_STYLING &gt;+ | ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE, &gt; ) &gt; } &gt; &gt; /// Measures memory usage. &gt; #[cfg(feature = "gecko")] &gt; pub fn size_of_excluding_cvs(&amp;self, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; let n = self.styles.size_of_excluding_cvs(ops); &gt; &gt;diff --git a/servo/components/style/dom.rs b/servo/components/style/dom.rs &gt;index 42f6e9ba0c05..72e03583966a 100644 &gt;--- a/servo/components/style/dom.rs &gt;+++ b/servo/components/style/dom.rs &gt;@@ -2,52 +2,55 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Types and traits used to access the DOM from style calculation. &gt; &gt; #![allow(unsafe_code)] &gt; #![deny(missing_docs)] &gt; &gt;-use {Atom, LocalName, Namespace, WeakAtom}; &gt; use applicable_declarations::ApplicableDeclarationBlock; &gt; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; &gt; #[cfg(feature = "gecko")] &gt; use context::PostAnimationTasks; &gt; #[cfg(feature = "gecko")] &gt; use context::UpdateAnimationsTasks; &gt; use data::ElementData; &gt; use element_state::ElementState; &gt; use font_metrics::FontMetricsProvider; &gt; use media_queries::Device; &gt; use properties::{AnimationRules, ComputedValues, PropertyDeclarationBlock}; &gt; use selector_parser::{AttrValue, PseudoClassStringArg, PseudoElement, SelectorImpl}; &gt;-use selectors::Element as SelectorsElement; &gt; use selectors::matching::{ElementSelectorFlags, QuirksMode, VisitedHandlingMode}; &gt; use selectors::sink::Push; &gt;+use selectors::Element as SelectorsElement; &gt; use servo_arc::{Arc, ArcBorrow}; &gt; use shared_lock::Locked; &gt; use std::fmt; &gt; use std::fmt::Debug; &gt; use std::hash::Hash; &gt; use std::ops::Deref; &gt; use stylist::CascadeData; &gt; use traversal_flags::TraversalFlags; &gt;+use {Atom, LocalName, Namespace, WeakAtom}; &gt; &gt; /// An opaque handle to a node, which, unlike UnsafeNode, cannot be transformed &gt; /// back into a non-opaque representation. The only safe operation that can be &gt; /// performed on this node is to compare it to another opaque handle or to another &gt; /// OpaqueNode. &gt; /// &gt; /// Layout and Graphics use this to safely represent nodes for comparison purposes. &gt; /// Because the script task's GC does not trace layout, node data cannot be safely stored in layout &gt; /// data structures. Also, layout code tends to be faster when the DOM is not being accessed, for &gt; /// locality reasons. Using `OpaqueNode` enforces this invariant. &gt; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] &gt;-#[cfg_attr(feature = "servo", derive(MallocSizeOf, Deserialize, Serialize))] &gt;+#[cfg_attr( &gt;+ feature = "servo", &gt;+ derive(MallocSizeOf, Deserialize, Serialize) &gt;+)] &gt; pub struct OpaqueNode(pub usize); &gt; &gt; impl OpaqueNode { &gt; /// Returns the address of this node, for debugging purposes. &gt; #[inline] &gt; pub fn id(&amp;self) -&gt; usize { &gt; self.0 &gt; } &gt;@@ -454,17 +457,19 @@ pub trait TElement: &gt; &gt; /// Return whether this element is an element in the MathML namespace. &gt; fn is_mathml_element(&amp;self) -&gt; bool; &gt; &gt; /// Return whether this element is an element in the SVG namespace. &gt; fn is_svg_element(&amp;self) -&gt; bool; &gt; &gt; /// Return whether this element is an element in the XUL namespace. &gt;- fn is_xul_element(&amp;self) -&gt; bool { false } &gt;+ fn is_xul_element(&amp;self) -&gt; bool { &gt;+ false &gt;+ } &gt; &gt; /// Return the list of slotted nodes of this node. &gt; fn slotted_nodes(&amp;self) -&gt; &amp;[Self::ConcreteNode] { &gt; &amp;[] &gt; } &gt; &gt; /// Get this element's style attribute. &gt; fn style_attribute(&amp;self) -&gt; Option&lt;ArcBorrow&lt;Locked&lt;PropertyDeclarationBlock&gt;&gt;&gt;; &gt;diff --git a/servo/components/style/dom_apis.rs b/servo/components/style/dom_apis.rs &gt;index 393fb6e119e4..24a32ac3ba75 100644 &gt;--- a/servo/components/style/dom_apis.rs &gt;+++ b/servo/components/style/dom_apis.rs &gt;@@ -1,26 +1,26 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic implementations of some DOM APIs so they can be shared between Servo &gt; //! and Gecko. &gt; &gt;-use Atom; &gt; use context::QuirksMode; &gt; use dom::{TDocument, TElement, TNode, TShadowRoot}; &gt; use invalidation::element::invalidator::{DescendantInvalidationLists, Invalidation}; &gt; use invalidation::element::invalidator::{InvalidationProcessor, InvalidationVector}; &gt;-use selectors::{Element, NthIndexCache, SelectorList}; &gt; use selectors::attr::CaseSensitivity; &gt; use selectors::matching::{self, MatchingContext, MatchingMode}; &gt; use selectors::parser::{Combinator, Component, LocalName}; &gt;+use selectors::{Element, NthIndexCache, SelectorList}; &gt; use smallvec::SmallVec; &gt; use std::borrow::Borrow; &gt;+use Atom; &gt; &gt; /// &lt;https://dom.spec.whatwg.org/#dom-element-matches&gt; &gt; pub fn element_matches&lt;E&gt;( &gt; element: &amp;E, &gt; selector_list: &amp;SelectorList&lt;E::Impl&gt;, &gt; quirks_mode: QuirksMode, &gt; ) -&gt; bool &gt; where &gt;@@ -307,17 +307,17 @@ fn collect_elements_with_id&lt;E, Q, F&gt;( &gt; Err(()) =&gt; { &gt; let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity(); &gt; &gt; collect_all_elements::&lt;E, Q, _&gt;(root, results, |e| { &gt; e.has_id(id, case_sensitivity) &amp;&amp; filter(e) &gt; }); &gt; &gt; return; &gt;- }, &gt;+ } &gt; }; &gt; &gt; for element in elements { &gt; // If the element is not an actual descendant of the root, even though &gt; // it's connected, we don't really care about it. &gt; if !connected_element_is_descendant_of(*element, root) { &gt; continue; &gt; } &gt;@@ -342,26 +342,26 @@ fn query_selector_single_query&lt;E, Q&gt;( &gt; ) -&gt; Result&lt;(), ()&gt; &gt; where &gt; E: TElement, &gt; Q: SelectorQuery&lt;E&gt;, &gt; { &gt; match *component { &gt; Component::ExplicitUniversalType =&gt; { &gt; collect_all_elements::&lt;E, Q, _&gt;(root, results, |_| true) &gt;- }, &gt;+ } &gt; Component::ID(ref id) =&gt; { &gt; collect_elements_with_id::&lt;E, Q, _&gt;(root, id, results, quirks_mode, |_| true); &gt;- }, &gt;+ } &gt; Component::Class(ref class) =&gt; { &gt; let case_sensitivity = quirks_mode.classes_and_ids_case_sensitivity(); &gt; collect_all_elements::&lt;E, Q, _&gt;(root, results, |element| { &gt; element.has_class(class, case_sensitivity) &gt; }) &gt;- }, &gt;+ } &gt; Component::LocalName(LocalName { &gt; ref name, &gt; ref lower_name, &gt; }) =&gt; collect_all_elements::&lt;E, Q, _&gt;(root, results, |element| { &gt; if element.is_html_element_in_html_document() { &gt; element.local_name() == lower_name.borrow() &gt; } else { &gt; element.local_name() == name.borrow() &gt;@@ -421,18 +421,17 @@ where &gt; // root that match the selector list with that id. &gt; collect_elements_with_id::&lt;E, Q, _&gt;(root, id, results, quirks_mode, |e| { &gt; matching::matches_selector_list(selector_list, &amp;e, matching_context) &gt; }); &gt; &gt; return Ok(()); &gt; } &gt; &gt;- let elements = &gt;- fast_connected_elements_with_id(root, id, quirks_mode)?; &gt;+ let elements = fast_connected_elements_with_id(root, id, quirks_mode)?; &gt; if elements.is_empty() { &gt; return Ok(()); &gt; } &gt; &gt; // Results need to be in document order. Let's not bother &gt; // reordering or deduplicating nodes, which we would need to &gt; // do if one element with the given id were a descendant of &gt; // another element with that given id. &gt;@@ -464,18 +463,18 @@ where &gt; ); &gt; &gt; if Q::should_stop_after_first_match() &amp;&amp; !Q::is_empty(&amp;results) { &gt; break; &gt; } &gt; } &gt; &gt; return Ok(()); &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; } &gt; &gt; loop { &gt; let next_combinator = match iter.next_sequence() { &gt; None =&gt; return Err(()), &gt; Some(c) =&gt; c, &gt; }; &gt;@@ -562,18 +561,18 @@ pub fn query_selector&lt;E, Q&gt;( &gt; // &gt; // The invalidation mechanism is only useful in presence of combinators. &gt; // &gt; // We could do that check properly here, though checking the length of the &gt; // selectors is a good heuristic. &gt; // &gt; // A selector with a combinator needs to have a length of at least 3: A &gt; // simple selector, a combinator, and another simple selector. &gt;- let invalidation_may_be_useful = may_use_invalidation == MayUseInvalidation::Yes &amp;&amp; &gt;- selector_list.0.iter().any(|s| s.len() &gt; 2); &gt;+ let invalidation_may_be_useful = may_use_invalidation == MayUseInvalidation::Yes &gt;+ &amp;&amp; selector_list.0.iter().any(|s| s.len() &gt; 2); &gt; &gt; if root_element.is_some() || !invalidation_may_be_useful { &gt; query_selector_slow::&lt;E, Q&gt;(root, selector_list, results, &amp;mut matching_context); &gt; } else { &gt; let mut processor = QuerySelectorProcessor::&lt;E, Q&gt; { &gt; results, &gt; matching_context, &gt; selector_list, &gt;diff --git a/servo/components/style/error_reporting.rs b/servo/components/style/error_reporting.rs &gt;index b5d5ba17ef88..e85297eebad9 100644 &gt;--- a/servo/components/style/error_reporting.rs &gt;+++ b/servo/components/style/error_reporting.rs &gt;@@ -65,17 +65,17 @@ impl&lt;'a&gt; fmt::Display for ContextualParseError&lt;'a&gt; { &gt; int_value: Some(i), .. &gt; } =&gt; write!(f, "number {}", i), &gt; Token::Number { value, .. } =&gt; write!(f, "number {}", value), &gt; Token::Percentage { &gt; int_value: Some(i), .. &gt; } =&gt; write!(f, "percentage {}", i), &gt; Token::Percentage { unit_value, .. } =&gt; { &gt; write!(f, "percentage {}", unit_value * 100.) &gt;- }, &gt;+ } &gt; Token::Dimension { &gt; value, ref unit, .. &gt; } =&gt; write!(f, "dimension {}{}", value, unit), &gt; Token::WhiteSpace(_) =&gt; write!(f, "whitespace"), &gt; Token::Comment(_) =&gt; write!(f, "comment"), &gt; Token::Colon =&gt; write!(f, "colon (:)"), &gt; Token::Semicolon =&gt; write!(f, "semicolon (;)"), &gt; Token::Comma =&gt; write!(f, "comma (,)"), &gt;@@ -98,90 +98,90 @@ impl&lt;'a&gt; fmt::Display for ContextualParseError&lt;'a&gt; { &gt; } &gt; } &gt; &gt; fn parse_error_to_str(err: &amp;ParseError, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; match err.kind { &gt; ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken(ref t)) =&gt; { &gt; write!(f, "found unexpected ")?; &gt; token_to_str(t, f) &gt;- }, &gt;+ } &gt; ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput) =&gt; { &gt; write!(f, "unexpected end of input") &gt;- }, &gt;+ } &gt; ParseErrorKind::Basic(BasicParseErrorKind::AtRuleInvalid(ref i)) =&gt; { &gt; write!(f, "@ rule invalid: {}", i) &gt;- }, &gt;+ } &gt; ParseErrorKind::Basic(BasicParseErrorKind::AtRuleBodyInvalid) =&gt; { &gt; write!(f, "@ rule invalid") &gt;- }, &gt;+ } &gt; ParseErrorKind::Basic(BasicParseErrorKind::QualifiedRuleInvalid) =&gt; { &gt; write!(f, "qualified rule invalid") &gt;- }, &gt;+ } &gt; ParseErrorKind::Custom(ref err) =&gt; write!(f, "{:?}", err), &gt; } &gt; } &gt; &gt; match *self { &gt; ContextualParseError::UnsupportedPropertyDeclaration(decl, ref err) =&gt; { &gt; write!(f, "Unsupported property declaration: '{}', ", decl)?; &gt; parse_error_to_str(err, f) &gt;- }, &gt;+ } &gt; ContextualParseError::UnsupportedFontFaceDescriptor(decl, ref err) =&gt; { &gt; write!( &gt; f, &gt; "Unsupported @font-face descriptor declaration: '{}', ", &gt; decl &gt; )?; &gt; parse_error_to_str(err, f) &gt;- }, &gt;+ } &gt; ContextualParseError::UnsupportedFontFeatureValuesDescriptor(decl, ref err) =&gt; { &gt; write!( &gt; f, &gt; "Unsupported @font-feature-values descriptor declaration: '{}', ", &gt; decl &gt; )?; &gt; parse_error_to_str(err, f) &gt;- }, &gt;+ } &gt; ContextualParseError::InvalidKeyframeRule(rule, ref err) =&gt; { &gt; write!(f, "Invalid keyframe rule: '{}', ", rule)?; &gt; parse_error_to_str(err, f) &gt;- }, &gt;+ } &gt; ContextualParseError::InvalidFontFeatureValuesRule(rule, ref err) =&gt; { &gt; write!(f, "Invalid font feature value rule: '{}', ", rule)?; &gt; parse_error_to_str(err, f) &gt;- }, &gt;+ } &gt; ContextualParseError::UnsupportedKeyframePropertyDeclaration(decl, ref err) =&gt; { &gt; write!(f, "Unsupported keyframe property declaration: '{}', ", decl)?; &gt; parse_error_to_str(err, f) &gt;- }, &gt;+ } &gt; ContextualParseError::InvalidRule(rule, ref err) =&gt; { &gt; write!(f, "Invalid rule: '{}', ", rule)?; &gt; parse_error_to_str(err, f) &gt;- }, &gt;+ } &gt; ContextualParseError::UnsupportedRule(rule, ref err) =&gt; { &gt; write!(f, "Unsupported rule: '{}', ", rule)?; &gt; parse_error_to_str(err, f) &gt;- }, &gt;+ } &gt; ContextualParseError::UnsupportedViewportDescriptorDeclaration(decl, ref err) =&gt; { &gt; write!( &gt; f, &gt; "Unsupported @viewport descriptor declaration: '{}', ", &gt; decl &gt; )?; &gt; parse_error_to_str(err, f) &gt;- }, &gt;+ } &gt; ContextualParseError::UnsupportedCounterStyleDescriptorDeclaration(decl, ref err) =&gt; { &gt; write!( &gt; f, &gt; "Unsupported @counter-style descriptor declaration: '{}', ", &gt; decl &gt; )?; &gt; parse_error_to_str(err, f) &gt;- }, &gt;+ } &gt; ContextualParseError::InvalidCounterStyleWithoutSymbols(ref system) =&gt; write!( &gt; f, &gt; "Invalid @counter-style rule: 'system: {}' without 'symbols'", &gt; system &gt; ), &gt; ContextualParseError::InvalidCounterStyleNotEnoughSymbols(ref system) =&gt; write!( &gt; f, &gt; "Invalid @counter-style rule: 'system: {}' less than two 'symbols'", &gt;@@ -197,17 +197,17 @@ impl&lt;'a&gt; fmt::Display for ContextualParseError&lt;'a&gt; { &gt; ), &gt; ContextualParseError::InvalidCounterStyleExtendsWithAdditiveSymbols =&gt; write!( &gt; f, &gt; "Invalid @counter-style rule: 'system: extends …' with 'additive-symbols'" &gt; ), &gt; ContextualParseError::InvalidMediaRule(media_rule, ref err) =&gt; { &gt; write!(f, "Invalid media rule: {}, ", media_rule)?; &gt; parse_error_to_str(err, f) &gt;- }, &gt;+ } &gt; ContextualParseError::UnsupportedValue(_value, ref err) =&gt; parse_error_to_str(err, f), &gt; } &gt; } &gt; } &gt; &gt; /// A generic trait for an error reporter. &gt; pub trait ParseErrorReporter { &gt; /// Called when the style engine detects an error. &gt;diff --git a/servo/components/style/font_face.rs b/servo/components/style/font_face.rs &gt;index d7501c1cca7f..c74f8436bd2e 100644 &gt;--- a/servo/components/style/font_face.rs &gt;+++ b/servo/components/style/font_face.rs &gt;@@ -1,39 +1,39 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! The [`@font-face`][ff] at-rule. &gt; //! &gt; //! [ff]: https://drafts.csswg.org/css-fonts/#at-font-face-rule &gt; &gt;+#[cfg(feature = "gecko")] &gt;+use cssparser::UnicodeRange; &gt; use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser}; &gt; use cssparser::{CowRcStr, SourceLocation}; &gt;-#[cfg(feature = "gecko")] &gt;-use cssparser::UnicodeRange; &gt; use error_reporting::ContextualParseError; &gt; use parser::{Parse, ParserContext}; &gt; #[cfg(feature = "gecko")] &gt; use properties::longhands::font_language_override; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; &gt; use std::fmt::{self, Write}; &gt; use str::CssStringWriter; &gt;+use style_traits::values::SequenceWriter; &gt; use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError}; &gt; use style_traits::{StyleParseErrorKind, ToCss}; &gt;-use style_traits::values::SequenceWriter; &gt; use values::computed::font::FamilyName; &gt; use values::generics::font::FontStyle as GenericFontStyle; &gt;-use values::specified::Angle; &gt;+use values::specified::font::SpecifiedFontStyle; &gt; use values::specified::font::{AbsoluteFontWeight, FontStretch as SpecifiedFontStretch}; &gt; #[cfg(feature = "gecko")] &gt; use values::specified::font::{SpecifiedFontFeatureSettings, SpecifiedFontVariationSettings}; &gt;-use values::specified::font::SpecifiedFontStyle; &gt; use values::specified::url::SpecifiedUrl; &gt;+use values::specified::Angle; &gt; &gt; /// A source for a font-face rule. &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt; #[derive(Clone, Debug, Eq, PartialEq, ToCss)] &gt; pub enum Source { &gt; /// A `url()` source. &gt; Url(UrlSource), &gt; /// A `local()` source. &gt;@@ -99,36 +99,38 @@ pub enum FontDisplay { &gt; pub struct FontWeight(pub AbsoluteFontWeight, pub Option&lt;AbsoluteFontWeight&gt;); &gt; &gt; impl Parse for FontWeight { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let first = AbsoluteFontWeight::parse(context, input)?; &gt;- let second = &gt;- input.try(|input| AbsoluteFontWeight::parse(context, input)).ok(); &gt;+ let second = input &gt;+ .try(|input| AbsoluteFontWeight::parse(context, input)) &gt;+ .ok(); &gt; Ok(FontWeight(first, second)) &gt; } &gt; } &gt; &gt; /// The font-stretch descriptor: &gt; /// &gt; /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-stretch &gt; #[derive(Clone, Debug, PartialEq, ToCss)] &gt; pub struct FontStretch(pub SpecifiedFontStretch, pub Option&lt;SpecifiedFontStretch&gt;); &gt; &gt; impl Parse for FontStretch { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let first = SpecifiedFontStretch::parse(context, input)?; &gt;- let second = &gt;- input.try(|input| SpecifiedFontStretch::parse(context, input)).ok(); &gt;+ let second = input &gt;+ .try(|input| SpecifiedFontStretch::parse(context, input)) &gt;+ .ok(); &gt; Ok(FontStretch(first, second)) &gt; } &gt; } &gt; &gt; /// The font-style descriptor: &gt; /// &gt; /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-style &gt; #[derive(Clone, Debug, PartialEq)] &gt;@@ -144,19 +146,19 @@ impl Parse for FontStyle { &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let style = SpecifiedFontStyle::parse(context, input)?; &gt; Ok(match style { &gt; GenericFontStyle::Normal =&gt; FontStyle::Normal, &gt; GenericFontStyle::Italic =&gt; FontStyle::Italic, &gt; GenericFontStyle::Oblique(angle) =&gt; { &gt;- let second_angle = input.try(|input| { &gt;- SpecifiedFontStyle::parse_angle(context, input) &gt;- }).unwrap_or_else(|_| angle.clone()); &gt;+ let second_angle = input &gt;+ .try(|input| SpecifiedFontStyle::parse_angle(context, input)) &gt;+ .unwrap_or_else(|_| angle.clone()); &gt; &gt; FontStyle::Oblique(angle, second_angle) &gt; } &gt; }) &gt; } &gt; } &gt; &gt; impl ToCss for FontStyle { &gt;@@ -230,25 +232,23 @@ impl&lt;'a&gt; FontFace&lt;'a&gt; { &gt; .iter() &gt; .rev() &gt; .filter(|source| { &gt; if let Source::Url(ref url_source) = **source { &gt; let hints = &amp;url_source.format_hints; &gt; // We support only opentype fonts and truetype is an alias for &gt; // that format. Sources without format hints need to be &gt; // downloaded in case we support them. &gt;- hints.is_empty() || &gt;- hints.iter().any(|hint| { &gt;- hint == "truetype" || hint == "opentype" || hint == "woff" &gt;- }) &gt;+ hints.is_empty() || hints &gt;+ .iter() &gt;+ .any(|hint| hint == "truetype" || hint == "opentype" || hint == "woff") &gt; } else { &gt; true &gt; } &gt;- }) &gt;- .cloned() &gt;+ }).cloned() &gt; .collect(), &gt; ) &gt; } &gt; } &gt; &gt; #[cfg(feature = "servo")] &gt; impl Iterator for EffectiveSources { &gt; type Item = Source; &gt;diff --git a/servo/components/style/font_metrics.rs b/servo/components/style/font_metrics.rs &gt;index dfe461cb3930..e093f13ef185 100644 &gt;--- a/servo/components/style/font_metrics.rs &gt;+++ b/servo/components/style/font_metrics.rs &gt;@@ -1,22 +1,22 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Access to font metrics from the style system. &gt; &gt; #![deny(missing_docs)] &gt; &gt;-use Atom; &gt; use app_units::Au; &gt; use context::SharedStyleContext; &gt; use logical_geometry::WritingMode; &gt; use media_queries::Device; &gt; use properties::style_structs::Font; &gt;+use Atom; &gt; &gt; /// Represents the font metrics that style needs from a font to compute the &gt; /// value of certain CSS units like `ex`. &gt; #[derive(Clone, Debug, PartialEq)] &gt; pub struct FontMetrics { &gt; /// The x-height of the font. &gt; pub x_height: Au, &gt; /// The zero advance. This is usually writing mode dependent &gt;diff --git a/servo/components/style/gecko/arc_types.rs b/servo/components/style/gecko/arc_types.rs &gt;index 7351cbfeac4f..2e2755d0ef1b 100644 &gt;--- a/servo/components/style/gecko/arc_types.rs &gt;+++ b/servo/components/style/gecko/arc_types.rs &gt;@@ -24,26 +24,26 @@ use gecko_bindings::bindings::ServoCssRules; &gt; use gecko_bindings::structs::RawServoAnimationValue; &gt; use gecko_bindings::structs::RawServoDeclarationBlock; &gt; use gecko_bindings::structs::RawServoFontFaceRule; &gt; use gecko_bindings::structs::RawServoMediaList; &gt; use gecko_bindings::structs::RawServoStyleRule; &gt; use gecko_bindings::structs::RawServoStyleSheetContents; &gt; use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI, Strong}; &gt; use media_queries::MediaList; &gt;-use properties::{ComputedValues, PropertyDeclarationBlock}; &gt; use properties::animated_properties::AnimationValue; &gt;+use properties::{ComputedValues, PropertyDeclarationBlock}; &gt; use rule_tree::StrongRuleNode; &gt; use servo_arc::{Arc, ArcBorrow}; &gt; use shared_lock::Locked; &gt; use std::{mem, ptr}; &gt;+use stylesheets::keyframes_rule::Keyframe; &gt; use stylesheets::{CounterStyleRule, CssRules, FontFaceRule, FontFeatureValuesRule}; &gt; use stylesheets::{DocumentRule, ImportRule, KeyframesRule, MediaRule, NamespaceRule, PageRule}; &gt; use stylesheets::{StyleRule, StylesheetContents, SupportsRule}; &gt;-use stylesheets::keyframes_rule::Keyframe; &gt; &gt; macro_rules! impl_arc_ffi { &gt; ($servo_type:ty =&gt; $gecko_type:ty[$addref:ident, $release:ident]) =&gt; { &gt; unsafe impl HasFFI for $servo_type { &gt; type FFIType = $gecko_type; &gt; } &gt; unsafe impl HasArcFFI for $servo_type {} &gt; &gt;diff --git a/servo/components/style/gecko/conversions.rs b/servo/components/style/gecko/conversions.rs &gt;index 3b1f31a1b08d..fb9bfa41f68b 100644 &gt;--- a/servo/components/style/gecko/conversions.rs &gt;+++ b/servo/components/style/gecko/conversions.rs &gt;@@ -7,24 +7,24 @@ &gt; //! forces us to keep the traits and implementations here &gt; &gt; #![allow(unsafe_code)] &gt; &gt; use app_units::Au; &gt; use gecko::values::GeckoStyleCoordConvertible; &gt; use gecko_bindings::bindings; &gt; use gecko_bindings::structs::{self, nsCSSUnit, nsStyleCoord_CalcValue}; &gt;-use gecko_bindings::structs::{nsresult, SheetType, nsStyleImage}; &gt;+use gecko_bindings::structs::{nsStyleImage, nsresult, SheetType}; &gt; use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue}; &gt; use std::f32::consts::PI; &gt; use stylesheets::{Origin, RulesMutateError}; &gt;+use values::computed::url::ComputedImageUrl; &gt; use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image}; &gt; use values::computed::{Integer, LengthOrPercentage, LengthOrPercentageOrAuto}; &gt; use values::computed::{Percentage, TextAlign}; &gt;-use values::computed::url::ComputedImageUrl; &gt; use values::generics::box_::VerticalAlign; &gt; use values::generics::grid::{TrackListValue, TrackSize}; &gt; use values::generics::image::{CompatMode, GradientItem, Image as GenericImage}; &gt; use values::generics::rect::Rect; &gt; &gt; impl From&lt;CalcLengthOrPercentage&gt; for nsStyleCoord_CalcValue { &gt; fn from(other: CalcLengthOrPercentage) -&gt; nsStyleCoord_CalcValue { &gt; let has_percentage = other.percentage.is_some(); &gt;@@ -144,17 +144,20 @@ impl nsStyleImage { &gt; pub fn set(&amp;mut self, image: Image) { &gt; match image { &gt; GenericImage::Gradient(boxed_gradient) =&gt; self.set_gradient(*boxed_gradient), &gt; GenericImage::Url(ref url) =&gt; unsafe { &gt; bindings::Gecko_SetLayerImageImageValue(self, url.0.image_value.get()); &gt; }, &gt; GenericImage::Rect(ref image_rect) =&gt; { &gt; unsafe { &gt;- bindings::Gecko_SetLayerImageImageValue(self, image_rect.url.0.image_value.get()); &gt;+ bindings::Gecko_SetLayerImageImageValue( &gt;+ self, &gt;+ image_rect.url.0.image_value.get(), &gt;+ ); &gt; bindings::Gecko_InitializeImageCropRect(self); &gt; &gt; // Set CropRect &gt; let ref mut rect = *self.mCropRect.mPtr; &gt; image_rect &gt; .top &gt; .to_gecko_style_coord(&amp;mut rect.data_at_mut(0)); &gt; image_rect &gt;@@ -162,29 +165,29 @@ impl nsStyleImage { &gt; .to_gecko_style_coord(&amp;mut rect.data_at_mut(1)); &gt; image_rect &gt; .bottom &gt; .to_gecko_style_coord(&amp;mut rect.data_at_mut(2)); &gt; image_rect &gt; .left &gt; .to_gecko_style_coord(&amp;mut rect.data_at_mut(3)); &gt; } &gt;- }, &gt;+ } &gt; GenericImage::Element(ref element) =&gt; unsafe { &gt; bindings::Gecko_SetImageElement(self, element.as_ptr()); &gt; }, &gt; } &gt; } &gt; &gt; fn set_gradient(&amp;mut self, gradient: Gradient) { &gt;- use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER as CLOSEST_CORNER; &gt;- use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE; &gt;- use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER; &gt;- use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE; &gt; use self::structs::nsStyleCoord; &gt;+ use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER as CLOSEST_CORNER; &gt;+ use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE; &gt;+ use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER; &gt;+ use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE; &gt; use values::computed::image::LineDirection; &gt; use values::generics::image::{Circle, Ellipse, EndingShape, GradientKind, ShapeExtent}; &gt; use values::specified::position::{X, Y}; &gt; &gt; let stop_count = gradient.items.len(); &gt; if stop_count &gt;= ::std::u32::MAX as usize { &gt; warn!("stylo: Prevented overflow due to too many gradient stops"); &gt; return; &gt;@@ -206,49 +209,49 @@ impl nsStyleImage { &gt; match direction { &gt; LineDirection::Angle(angle) =&gt; { &gt; // PI radians (180deg) is ignored because it is the default value. &gt; if angle.radians() != PI { &gt; unsafe { &gt; (*gecko_gradient).mAngle.set(angle); &gt; } &gt; } &gt;- }, &gt;+ } &gt; LineDirection::Horizontal(x) =&gt; { &gt; let x = match x { &gt; X::Left =&gt; 0.0, &gt; X::Right =&gt; 1.0, &gt; }; &gt; &gt; unsafe { &gt; (*gecko_gradient) &gt; .mBgPosX &gt; .set_value(CoordDataValue::Percent(x)); &gt; (*gecko_gradient) &gt; .mBgPosY &gt; .set_value(CoordDataValue::Percent(0.5)); &gt; } &gt;- }, &gt;+ } &gt; LineDirection::Vertical(y) =&gt; { &gt; // Although bottom is the default value, we can not ignore &gt; // it here, because the rendering code of Gecko relies on &gt; // this to behave correctly for legacy mode. &gt; let y = match y { &gt; Y::Top =&gt; 0.0, &gt; Y::Bottom =&gt; 1.0, &gt; }; &gt; unsafe { &gt; (*gecko_gradient) &gt; .mBgPosX &gt; .set_value(CoordDataValue::Percent(0.5)); &gt; (*gecko_gradient) &gt; .mBgPosY &gt; .set_value(CoordDataValue::Percent(y)); &gt; } &gt;- }, &gt;+ } &gt; LineDirection::Corner(horiz, vert) =&gt; { &gt; let percent_x = match horiz { &gt; X::Left =&gt; 0.0, &gt; X::Right =&gt; 1.0, &gt; }; &gt; let percent_y = match vert { &gt; Y::Top =&gt; 0.0, &gt; Y::Bottom =&gt; 1.0, &gt;@@ -257,57 +260,57 @@ impl nsStyleImage { &gt; unsafe { &gt; (*gecko_gradient) &gt; .mBgPosX &gt; .set_value(CoordDataValue::Percent(percent_x)); &gt; (*gecko_gradient) &gt; .mBgPosY &gt; .set_value(CoordDataValue::Percent(percent_y)); &gt; } &gt;- }, &gt;+ } &gt; #[cfg(feature = "gecko")] &gt; LineDirection::MozPosition(position, angle) =&gt; unsafe { &gt; if let Some(position) = position { &gt; (*gecko_gradient).mBgPosX.set(position.horizontal); &gt; (*gecko_gradient).mBgPosY.set(position.vertical); &gt; } &gt; if let Some(angle) = angle { &gt; (*gecko_gradient).mAngle.set(angle); &gt; } &gt; }, &gt; } &gt; gecko_gradient &gt;- }, &gt;+ } &gt; GradientKind::Radial(shape, position, angle) =&gt; { &gt; let keyword_to_gecko_size = |keyword| match keyword { &gt; ShapeExtent::ClosestSide =&gt; CLOSEST_SIDE, &gt; ShapeExtent::FarthestSide =&gt; FARTHEST_SIDE, &gt; ShapeExtent::ClosestCorner =&gt; CLOSEST_CORNER, &gt; ShapeExtent::FarthestCorner =&gt; FARTHEST_CORNER, &gt; ShapeExtent::Contain =&gt; CLOSEST_SIDE, &gt; ShapeExtent::Cover =&gt; FARTHEST_CORNER, &gt; }; &gt; let (gecko_shape, gecko_size) = match shape { &gt; EndingShape::Circle(ref circle) =&gt; { &gt; let size = match *circle { &gt; Circle::Extent(extent) =&gt; keyword_to_gecko_size(extent), &gt; _ =&gt; structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE, &gt; }; &gt; (structs::NS_STYLE_GRADIENT_SHAPE_CIRCULAR as u8, size as u8) &gt;- }, &gt;+ } &gt; EndingShape::Ellipse(ref ellipse) =&gt; { &gt; let size = match *ellipse { &gt; Ellipse::Extent(extent) =&gt; keyword_to_gecko_size(extent), &gt; _ =&gt; structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE, &gt; }; &gt; ( &gt; structs::NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL as u8, &gt; size as u8, &gt; ) &gt;- }, &gt;+ } &gt; }; &gt; &gt; let gecko_gradient = unsafe { &gt; bindings::Gecko_CreateGradient( &gt; gecko_shape, &gt; gecko_size, &gt; gradient.repeating, &gt; gradient.compat_mode == CompatMode::Moz, &gt;@@ -333,44 +336,44 @@ impl nsStyleImage { &gt; (*gecko_gradient) &gt; .mRadiusY &gt; .set_value(CoordDataValue::Coord(au)); &gt; }, &gt; EndingShape::Ellipse(Ellipse::Radii(x, y)) =&gt; unsafe { &gt; (*gecko_gradient).mRadiusX.set(x); &gt; (*gecko_gradient).mRadiusY.set(y); &gt; }, &gt;- _ =&gt; {}, &gt;+ _ =&gt; {} &gt; } &gt; unsafe { &gt; (*gecko_gradient).mBgPosX.set(position.horizontal); &gt; (*gecko_gradient).mBgPosY.set(position.vertical); &gt; } &gt; &gt; gecko_gradient &gt;- }, &gt;+ } &gt; }; &gt; &gt; for (index, item) in gradient.items.iter().enumerate() { &gt; // NB: stops are guaranteed to be none in the gecko side by &gt; // default. &gt; &gt; let gecko_stop = unsafe { &amp;mut (*gecko_gradient).mStops[index] }; &gt; let mut coord = nsStyleCoord::null(); &gt; &gt; match *item { &gt; GradientItem::ColorStop(ref stop) =&gt; { &gt; gecko_stop.mColor = stop.color.into(); &gt; gecko_stop.mIsInterpolationHint = false; &gt; coord.set(stop.position); &gt;- }, &gt;+ } &gt; GradientItem::InterpolationHint(hint) =&gt; { &gt; gecko_stop.mIsInterpolationHint = true; &gt; coord.set(Some(hint)); &gt;- }, &gt;+ } &gt; } &gt; &gt; gecko_stop.mLocation.move_from(coord); &gt; } &gt; &gt; unsafe { &gt; bindings::Gecko_SetGradientImageValue(self, gecko_gradient); &gt; } &gt;@@ -398,53 +401,54 @@ impl nsStyleImage { &gt; (Some(top), Some(right), Some(bottom), Some(left)) =&gt; { &gt; Some(GenericImage::Rect(Box::new(MozImageRect { &gt; url, &gt; top, &gt; right, &gt; bottom, &gt; left, &gt; }))) &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; debug_assert!( &gt; false, &gt; "mCropRect could not convert to NumberOrPercentage" &gt; ); &gt; None &gt;- }, &gt;+ } &gt; } &gt; } &gt;- }, &gt;+ } &gt; nsStyleImageType::eStyleImageType_Gradient =&gt; { &gt; Some(GenericImage::Gradient(self.get_gradient())) &gt;- }, &gt;+ } &gt; nsStyleImageType::eStyleImageType_Element =&gt; { &gt; use gecko_string_cache::Atom; &gt; let atom = bindings::Gecko_GetImageElement(self); &gt; Some(GenericImage::Element(Atom::from_raw(atom))) &gt;- }, &gt;+ } &gt; _ =&gt; panic!("Unexpected image type"), &gt; } &gt; } &gt; &gt; unsafe fn get_image_url(&amp;self) -&gt; ComputedImageUrl { &gt; let image_request = bindings::Gecko_GetImageRequest(self) &gt;- .as_ref().expect("Null image request?"); &gt;+ .as_ref() &gt;+ .expect("Null image request?"); &gt; ComputedImageUrl::from_image_request(image_request) &gt; } &gt; &gt; unsafe fn get_gradient(self: &amp;nsStyleImage) -&gt; Box&lt;Gradient&gt; { &gt; use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER as CLOSEST_CORNER; &gt; use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE; &gt; use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER; &gt; use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE; &gt;- use values::computed::{Length, LengthOrPercentage}; &gt; use values::computed::image::LineDirection; &gt; use values::computed::position::Position; &gt;+ use values::computed::{Length, LengthOrPercentage}; &gt; use values::generics::image::{Circle, ColorStop, CompatMode, Ellipse}; &gt; use values::generics::image::{EndingShape, GradientKind, ShapeExtent}; &gt; use values::specified::position::{X, Y}; &gt; &gt; let gecko_gradient = bindings::Gecko_GetGradientImageValue(self) &gt; .as_ref() &gt; .unwrap(); &gt; let angle = Angle::from_gecko_style_coord(&amp;gecko_gradient.mAngle); &gt;@@ -460,60 +464,60 @@ impl nsStyleImage { &gt; LengthOrPercentage::Percentage(percentage) =&gt; { &gt; if percentage.0 == 0.0 { &gt; Some(X::Left) &gt; } else if percentage.0 == 1.0 { &gt; Some(X::Right) &gt; } else { &gt; None &gt; } &gt;- }, &gt;+ } &gt; _ =&gt; None, &gt; }; &gt; let vertical_as_corner = match vertical { &gt; LengthOrPercentage::Percentage(percentage) =&gt; { &gt; if percentage.0 == 0.0 { &gt; Some(Y::Top) &gt; } else if percentage.0 == 1.0 { &gt; Some(Y::Bottom) &gt; } else { &gt; None &gt; } &gt;- }, &gt;+ } &gt; _ =&gt; None, &gt; }; &gt; &gt; match (horizontal_as_corner, vertical_as_corner) { &gt; (Some(hc), Some(vc)) =&gt; LineDirection::Corner(hc, vc), &gt; _ =&gt; LineDirection::MozPosition( &gt; Some(Position { &gt; horizontal, &gt; vertical, &gt; }), &gt; None, &gt; ), &gt; } &gt;- }, &gt;+ } &gt; (Some(_), Some(horizontal), Some(vertical)) =&gt; LineDirection::MozPosition( &gt; Some(Position { &gt; horizontal, &gt; vertical, &gt; }), &gt; angle, &gt; ), &gt; _ =&gt; { &gt; debug_assert!( &gt; horizontal_style.is_none() &amp;&amp; vertical_style.is_none(), &gt; "Unexpected linear gradient direction" &gt; ); &gt; LineDirection::MozPosition(None, None) &gt;- }, &gt;+ } &gt; }; &gt; GradientKind::Linear(line_direction) &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; let gecko_size_to_keyword = |gecko_size| { &gt; match gecko_size { &gt; CLOSEST_SIDE =&gt; ShapeExtent::ClosestSide, &gt; FARTHEST_SIDE =&gt; ShapeExtent::FarthestSide, &gt; CLOSEST_CORNER =&gt; ShapeExtent::ClosestCorner, &gt; FARTHEST_CORNER =&gt; ShapeExtent::FarthestCorner, &gt; // FIXME: We should support ShapeExtent::Contain and ShapeExtent::Cover. &gt;@@ -522,30 +526,30 @@ impl nsStyleImage { &gt; _ =&gt; panic!("Found unexpected gecko_size"), &gt; } &gt; }; &gt; &gt; let shape = match gecko_gradient.mShape as u32 { &gt; structs::NS_STYLE_GRADIENT_SHAPE_CIRCULAR =&gt; { &gt; let circle = match gecko_gradient.mSize as u32 { &gt; structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE =&gt; { &gt;- let radius = Length::from_gecko_style_coord( &gt;- &amp;gecko_gradient.mRadiusX, &gt;- ).expect("mRadiusX could not convert to Length"); &gt;+ let radius = &gt;+ Length::from_gecko_style_coord(&amp;gecko_gradient.mRadiusX) &gt;+ .expect("mRadiusX could not convert to Length"); &gt; debug_assert_eq!( &gt; radius, &gt; Length::from_gecko_style_coord(&amp;gecko_gradient.mRadiusY) &gt; .unwrap() &gt; ); &gt; Circle::Radius(radius) &gt;- }, &gt;+ } &gt; size =&gt; Circle::Extent(gecko_size_to_keyword(size)), &gt; }; &gt; EndingShape::Circle(circle) &gt;- }, &gt;+ } &gt; structs::NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL =&gt; { &gt; let length_percentage_keyword = match gecko_gradient.mSize as u32 { &gt; structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE =&gt; match ( &gt; LengthOrPercentage::from_gecko_style_coord( &gt; &amp;gecko_gradient.mRadiusX, &gt; ), &gt; LengthOrPercentage::from_gecko_style_coord( &gt; &amp;gecko_gradient.mRadiusY, &gt;@@ -554,22 +558,22 @@ impl nsStyleImage { &gt; (Some(x), Some(y)) =&gt; Ellipse::Radii(x, y), &gt; _ =&gt; { &gt; debug_assert!(false, &gt; "mRadiusX, mRadiusY could not convert to LengthOrPercentage"); &gt; Ellipse::Radii( &gt; LengthOrPercentage::zero(), &gt; LengthOrPercentage::zero(), &gt; ) &gt;- }, &gt;+ } &gt; }, &gt; size =&gt; Ellipse::Extent(gecko_size_to_keyword(size)), &gt; }; &gt; EndingShape::Ellipse(length_percentage_keyword) &gt;- }, &gt;+ } &gt; _ =&gt; panic!("Found unexpected mShape"), &gt; }; &gt; &gt; let position = match (horizontal_style, vertical_style) { &gt; (Some(horizontal), Some(vertical)) =&gt; Position { &gt; horizontal, &gt; vertical, &gt; }, &gt;@@ -577,21 +581,21 @@ impl nsStyleImage { &gt; debug_assert!( &gt; false, &gt; "mRadiusX, mRadiusY could not convert to LengthOrPercentage" &gt; ); &gt; Position { &gt; horizontal: LengthOrPercentage::zero(), &gt; vertical: LengthOrPercentage::zero(), &gt; } &gt;- }, &gt;+ } &gt; }; &gt; &gt; GradientKind::Radial(shape, position, angle) &gt;- }, &gt;+ } &gt; }; &gt; &gt; let items = gecko_gradient &gt; .mStops &gt; .iter() &gt; .map(|ref stop| { &gt; if stop.mIsInterpolationHint { &gt; GradientItem::InterpolationHint( &gt;@@ -599,18 +603,17 @@ impl nsStyleImage { &gt; .expect("mLocation could not convert to LengthOrPercentage"), &gt; ) &gt; } else { &gt; GradientItem::ColorStop(ColorStop { &gt; color: stop.mColor.into(), &gt; position: LengthOrPercentage::from_gecko_style_coord(&amp;stop.mLocation), &gt; }) &gt; } &gt;- }) &gt;- .collect(); &gt;+ }).collect(); &gt; &gt; let compat_mode = if gecko_gradient.mMozLegacySyntax { &gt; CompatMode::Moz &gt; } else if gecko_gradient.mLegacySyntax { &gt; CompatMode::WebKit &gt; } else { &gt; CompatMode::Modern &gt; }; &gt;@@ -624,19 +627,19 @@ impl nsStyleImage { &gt; } &gt; } &gt; &gt; pub mod basic_shape { &gt; //! Conversions from and to CSS shape representations. &gt; &gt; use gecko::values::GeckoStyleCoordConvertible; &gt; use gecko_bindings::structs; &gt;+ use gecko_bindings::structs::{nsStyleCoord, nsStyleCorners}; &gt; use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleFillRule}; &gt; use gecko_bindings::structs::{StyleGeometryBox, StyleShapeSource, StyleShapeSourceType}; &gt;- use gecko_bindings::structs::{nsStyleCoord, nsStyleCorners}; &gt; use gecko_bindings::sugar::ns_style_coord::{CoordDataMut, CoordDataValue}; &gt; use gecko_bindings::sugar::refptr::RefPtr; &gt; use std::borrow::Borrow; &gt; use values::computed::basic_shape::{BasicShape, ClippingShape, FloatAreaShape, ShapeRadius}; &gt; use values::computed::border::{BorderCornerRadius, BorderRadius}; &gt; use values::computed::length::LengthOrPercentage; &gt; use values::computed::position; &gt; use values::computed::url::ComputedUrl; &gt;@@ -662,47 +665,47 @@ pub mod basic_shape { &gt; let other_shape = unsafe { &amp;*self.__bindgen_anon_1.mBasicShape.as_ref().mPtr }; &gt; let shape = other_shape.into(); &gt; let reference_box = if self.mReferenceBox == StyleGeometryBox::NoBox { &gt; None &gt; } else { &gt; Some(self.mReferenceBox.into()) &gt; }; &gt; Some(ShapeSource::Shape(shape, reference_box)) &gt;- }, &gt;+ } &gt; StyleShapeSourceType::URL | StyleShapeSourceType::Image =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a StyleShapeSource&gt; for ClippingShape { &gt; fn from(other: &amp;'a StyleShapeSource) -&gt; Self { &gt; match other.mType { &gt; StyleShapeSourceType::URL =&gt; unsafe { &gt; let shape_image = &amp;*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; &gt; let other_url = RefPtr::new(*shape_image.__bindgen_anon_1.mURLValue.as_ref()); &gt; let url = ComputedUrl::from_url_value(other_url); &gt; ShapeSource::ImageOrUrl(url) &gt; }, &gt; StyleShapeSourceType::Image =&gt; { &gt; unreachable!("ClippingShape doesn't support Image!"); &gt;- }, &gt;+ } &gt; _ =&gt; other &gt; .into_shape_source() &gt; .expect("Couldn't convert to StyleSource!"), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a StyleShapeSource&gt; for FloatAreaShape { &gt; fn from(other: &amp;'a StyleShapeSource) -&gt; Self { &gt; match other.mType { &gt; StyleShapeSourceType::URL =&gt; { &gt; unreachable!("FloatAreaShape doesn't support URL!"); &gt;- }, &gt;+ } &gt; StyleShapeSourceType::Image =&gt; unsafe { &gt; let shape_image = &amp;*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; &gt; let image = shape_image.into_image().expect("Cannot convert to Image"); &gt; ShapeSource::ImageOrUrl(image) &gt; }, &gt; _ =&gt; other &gt; .into_shape_source() &gt; .expect("Couldn't convert to StyleSource!"), &gt;@@ -724,17 +727,17 @@ pub mod basic_shape { &gt; r.expect("inset() offset should be a length, percentage, or calc value"), &gt; b.expect("inset() offset should be a length, percentage, or calc value"), &gt; l.expect("inset() offset should be a length, percentage, or calc value"), &gt; ); &gt; GenericBasicShape::Inset(InsetRect { &gt; rect: rect, &gt; round: Some(round), &gt; }) &gt;- }, &gt;+ } &gt; StyleBasicShapeType::Circle =&gt; GenericBasicShape::Circle(Circle { &gt; radius: (&amp;other.mCoordinates[0]).into(), &gt; position: (&amp;other.mPosition).into(), &gt; }), &gt; StyleBasicShapeType::Ellipse =&gt; GenericBasicShape::Ellipse(Ellipse { &gt; semiaxis_x: (&amp;other.mCoordinates[0]).into(), &gt; semiaxis_y: (&amp;other.mCoordinates[1]).into(), &gt; position: (&amp;other.mPosition).into(), &gt;@@ -754,17 +757,17 @@ pub mod basic_shape { &gt; LengthOrPercentage::from_gecko_style_coord(&amp;other.mCoordinates[y]) &gt; .expect("polygon() coordinate should be a length, percentage, or calc value") &gt; )) &gt; } &gt; GenericBasicShape::Polygon(Polygon { &gt; fill: fill_rule, &gt; coordinates: coords, &gt; }) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; From&lt;&amp;'a nsStyleCorners&gt; for BorderRadius { &gt; fn from(other: &amp;'a nsStyleCorners) -&gt; Self { &gt; let get_corner = |index| { &gt; BorderCornerRadius::new( &gt;@@ -927,19 +930,19 @@ impl TrackSize&lt;LengthOrPercentage&gt; { &gt; /// Return TrackSize from given two nsStyleCoord &gt; pub fn from_gecko_style_coords&lt;T: CoordData&gt;(gecko_min: &amp;T, gecko_max: &amp;T) -&gt; Self { &gt; use gecko_bindings::structs::root::nsStyleUnit; &gt; use values::computed::length::LengthOrPercentage; &gt; use values::generics::grid::{TrackBreadth, TrackSize}; &gt; &gt; if gecko_min.unit() == nsStyleUnit::eStyleUnit_None { &gt; debug_assert!( &gt;- gecko_max.unit() == nsStyleUnit::eStyleUnit_Coord || &gt;- gecko_max.unit() == nsStyleUnit::eStyleUnit_Percent || &gt;- gecko_max.unit() == nsStyleUnit::eStyleUnit_Calc &gt;+ gecko_max.unit() == nsStyleUnit::eStyleUnit_Coord &gt;+ || gecko_max.unit() == nsStyleUnit::eStyleUnit_Percent &gt;+ || gecko_max.unit() == nsStyleUnit::eStyleUnit_Calc &gt; ); &gt; return TrackSize::FitContent( &gt; LengthOrPercentage::from_gecko_style_coord(gecko_max) &gt; .expect("gecko_max could not convert to LengthOrPercentage"), &gt; ); &gt; } &gt; &gt; let min = TrackBreadth::from_gecko_style_coord(gecko_min) &gt;@@ -958,27 +961,27 @@ impl TrackSize&lt;LengthOrPercentage&gt; { &gt; use values::generics::grid::TrackSize; &gt; &gt; match *self { &gt; TrackSize::FitContent(ref lop) =&gt; { &gt; // Gecko sets min value to None and max value to the actual value in fit-content &gt; // https://dxr.mozilla.org/mozilla-central/rev/0eef1d5/layout/style/nsRuleNode.cpp#8221 &gt; gecko_min.set_value(CoordDataValue::None); &gt; lop.to_gecko_style_coord(gecko_max); &gt;- }, &gt;+ } &gt; TrackSize::Breadth(ref breadth) =&gt; { &gt; // Set the value to both fields if there's one breadth value &gt; // https://dxr.mozilla.org/mozilla-central/rev/0eef1d5/layout/style/nsRuleNode.cpp#8230 &gt; breadth.to_gecko_style_coord(gecko_min); &gt; breadth.to_gecko_style_coord(gecko_max); &gt;- }, &gt;+ } &gt; TrackSize::Minmax(ref min, ref max) =&gt; { &gt; min.to_gecko_style_coord(gecko_min); &gt; max.to_gecko_style_coord(gecko_max); &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl TrackListValue&lt;LengthOrPercentage, Integer&gt; { &gt; /// Return TrackSize from given two nsStyleCoord &gt; pub fn from_gecko_style_coords&lt;T: CoordData&gt;(gecko_min: &amp;T, gecko_max: &amp;T) -&gt; Self { &gt; TrackListValue::TrackSize(TrackSize::from_gecko_style_coords(gecko_min, gecko_max)) &gt;@@ -1031,17 +1034,17 @@ impl&lt;L&gt; VerticalAlign&lt;L&gt; { &gt; structs::NS_STYLE_VERTICAL_ALIGN_SUPER =&gt; VerticalAlign::Super, &gt; structs::NS_STYLE_VERTICAL_ALIGN_TOP =&gt; VerticalAlign::Top, &gt; structs::NS_STYLE_VERTICAL_ALIGN_TEXT_TOP =&gt; VerticalAlign::TextTop, &gt; structs::NS_STYLE_VERTICAL_ALIGN_MIDDLE =&gt; VerticalAlign::Middle, &gt; structs::NS_STYLE_VERTICAL_ALIGN_BOTTOM =&gt; VerticalAlign::Bottom, &gt; structs::NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM =&gt; VerticalAlign::TextBottom, &gt; structs::NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE =&gt; { &gt; VerticalAlign::MozMiddleWithBaseline &gt;- }, &gt;+ } &gt; _ =&gt; panic!("unexpected enumerated value for vertical-align"), &gt; } &gt; } &gt; } &gt; &gt; impl TextAlign { &gt; /// Obtain a specified value from a Gecko keyword value &gt; /// &gt;diff --git a/servo/components/style/gecko/data.rs b/servo/components/style/gecko/data.rs &gt;index 0bd938c67e8f..19c97572137e 100644 &gt;--- a/servo/components/style/gecko/data.rs &gt;+++ b/servo/components/style/gecko/data.rs &gt;@@ -3,18 +3,20 @@ &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Data needed to style a Gecko document. &gt; &gt; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; &gt; use context::QuirksMode; &gt; use dom::TElement; &gt; use gecko_bindings::bindings::{self, RawServoStyleSet}; &gt;-use gecko_bindings::structs::{RawGeckoPresContextOwned, ServoStyleSetSizes, StyleSheet as DomStyleSheet}; &gt;-use gecko_bindings::structs::{StyleSheetInfo, nsIDocument}; &gt;+use gecko_bindings::structs::{nsIDocument, StyleSheetInfo}; &gt;+use gecko_bindings::structs::{ &gt;+ RawGeckoPresContextOwned, ServoStyleSetSizes, StyleSheet as DomStyleSheet, &gt;+}; &gt; use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI}; &gt; use invalidation::media_queries::{MediaListKey, ToMediaListKey}; &gt; use malloc_size_of::MallocSizeOfOps; &gt; use media_queries::{Device, MediaList}; &gt; use properties::ComputedValues; &gt; use selector_parser::SnapshotMap; &gt; use servo_arc::Arc; &gt; use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; &gt;@@ -24,17 +26,18 @@ use stylist::Stylist; &gt; &gt; /// Little wrapper to a Gecko style sheet. &gt; #[derive(Eq, PartialEq)] &gt; pub struct GeckoStyleSheet(*const DomStyleSheet); &gt; &gt; impl fmt::Debug for GeckoStyleSheet { &gt; fn fmt(&amp;self, formatter: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; let contents = self.contents(); &gt;- formatter.debug_struct("GeckoStyleSheet") &gt;+ formatter &gt;+ .debug_struct("GeckoStyleSheet") &gt; .field("origin", &amp;contents.origin) &gt; .field("url_data", &amp;*contents.url_data.read()) &gt; .finish() &gt; } &gt; } &gt; &gt; impl ToMediaListKey for ::gecko::data::GeckoStyleSheet { &gt; fn to_media_list_key(&amp;self) -&gt; MediaListKey { &gt;@@ -61,19 +64,17 @@ impl GeckoStyleSheet { &gt; } &gt; &gt; /// Get the raw `StyleSheet` that we're wrapping. &gt; pub fn raw(&amp;self) -&gt; &amp;DomStyleSheet { &gt; unsafe { &amp;*self.0 } &gt; } &gt; &gt; fn inner(&amp;self) -&gt; &amp;StyleSheetInfo { &gt;- unsafe { &gt;- &amp;*(self.raw().mInner as *const StyleSheetInfo) &gt;- } &gt;+ unsafe { &amp;*(self.raw().mInner as *const StyleSheetInfo) } &gt; } &gt; &gt; /// Gets the StylesheetContents for this stylesheet. &gt; pub fn contents(&amp;self) -&gt; &amp;StylesheetContents { &gt; debug_assert!(!self.inner().mContents.mRawPtr.is_null()); &gt; unsafe { &gt; let contents = &gt; (&amp;**StylesheetContents::as_arc(&amp;&amp;*self.inner().mContents.mRawPtr)) as *const _; &gt;@@ -188,17 +189,18 @@ impl PerDocumentStyleDataImpl { &gt; /// Get the default computed values for this document. &gt; pub fn default_computed_values(&amp;self) -&gt; &amp;Arc&lt;ComputedValues&gt; { &gt; self.stylist.device().default_computed_values_arc() &gt; } &gt; &gt; /// Returns whether visited styles are enabled. &gt; #[inline] &gt; pub fn visited_styles_enabled(&amp;self) -&gt; bool { &gt;- let doc = self.stylist &gt;+ let doc = self &gt;+ .stylist &gt; .device() &gt; .pres_context() &gt; .mDocument &gt; .raw::&lt;nsIDocument&gt;(); &gt; unsafe { bindings::Gecko_VisitedStylesEnabled(doc) } &gt; } &gt; &gt; /// Measure heap usage. &gt;diff --git a/servo/components/style/gecko/global_style_data.rs b/servo/components/style/gecko/global_style_data.rs &gt;index 6671de9867d2..8007acb6ce2a 100644 &gt;--- a/servo/components/style/gecko/global_style_data.rs &gt;+++ b/servo/components/style/gecko/global_style_data.rs &gt;@@ -1,17 +1,17 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Global style data &gt; &gt; use context::StyleSystemOptions; &gt;-use gecko_bindings::bindings::{Gecko_RegisterProfilerThread, Gecko_UnregisterProfilerThread}; &gt; use gecko_bindings::bindings::Gecko_SetJemallocThreadLocalArena; &gt;+use gecko_bindings::bindings::{Gecko_RegisterProfilerThread, Gecko_UnregisterProfilerThread}; &gt; use num_cpus; &gt; use parallel::STYLE_THREAD_STACK_SIZE_KB; &gt; use rayon; &gt; use shared_lock::SharedRwLock; &gt; use std::cmp; &gt; use std::env; &gt; use std::ffi::CString; &gt; use thread_state; &gt;diff --git a/servo/components/style/gecko/media_features.rs b/servo/components/style/gecko/media_features.rs &gt;index 3595133f55c1..2958bb0a488d 100644 &gt;--- a/servo/components/style/gecko/media_features.rs &gt;+++ b/servo/components/style/gecko/media_features.rs &gt;@@ -1,57 +1,53 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Gecko's media feature list and evaluator. &gt; &gt;-use Atom; &gt; use app_units::Au; &gt; use euclid::Size2D; &gt; use gecko_bindings::bindings; &gt; use values::computed::CSSPixelLength; &gt; use values::computed::Resolution; &gt;+use Atom; &gt; &gt;-use media_queries::Device; &gt;-use media_queries::media_feature::{MediaFeatureDescription, Evaluator}; &gt; use media_queries::media_feature::{AllowsRanges, ParsingRequirements}; &gt;+use media_queries::media_feature::{Evaluator, MediaFeatureDescription}; &gt; use media_queries::media_feature_expression::{AspectRatio, RangeOrOperator}; &gt;+use media_queries::Device; &gt; &gt; macro_rules! feature { &gt; ($name:expr, $allows_ranges:expr, $evaluator:expr, $reqs:expr,) =&gt; { &gt; MediaFeatureDescription { &gt; name: $name, &gt; allows_ranges: $allows_ranges, &gt; evaluator: $evaluator, &gt; requirements: $reqs, &gt; } &gt;- } &gt;+ }; &gt; } &gt; &gt; fn viewport_size(device: &amp;Device) -&gt; Size2D&lt;Au&gt; { &gt; let pc = device.pres_context(); &gt; if pc.mIsRootPaginatedDocument() != 0 { &gt; // We want the page size, including unprintable areas and margins. &gt; // FIXME(emilio, bug 1414600): Not quite! &gt; let area = &amp;pc.mPageSize; &gt;- return Size2D::new(Au(area.width), Au(area.height)) &gt;+ return Size2D::new(Au(area.width), Au(area.height)); &gt; } &gt; device.au_viewport_size() &gt; } &gt; &gt; fn device_size(device: &amp;Device) -&gt; Size2D&lt;Au&gt; { &gt; let mut width = 0; &gt; let mut height = 0; &gt; unsafe { &gt;- bindings::Gecko_MediaFeatures_GetDeviceSize( &gt;- device.document(), &gt;- &amp;mut width, &gt;- &amp;mut height, &gt;- ); &gt;+ bindings::Gecko_MediaFeatures_GetDeviceSize(device.document(), &amp;mut width, &amp;mut height); &gt; } &gt; Size2D::new(Au(width), Au(height)) &gt; } &gt; &gt; /// https://drafts.csswg.org/mediaqueries-4/#width &gt; fn eval_width( &gt; device: &amp;Device, &gt; value: Option&lt;CSSPixelLength&gt;, &gt;@@ -159,21 +155,17 @@ fn eval_device_pixel_ratio( &gt; &gt; #[derive(Debug, Copy, Clone, FromPrimitive, ToCss, Parse)] &gt; #[repr(u8)] &gt; enum Orientation { &gt; Landscape, &gt; Portrait, &gt; } &gt; &gt;-fn eval_orientation_for&lt;F&gt;( &gt;- device: &amp;Device, &gt;- value: Option&lt;Orientation&gt;, &gt;- get_size: F, &gt;-) -&gt; bool &gt;+fn eval_orientation_for&lt;F&gt;(device: &amp;Device, value: Option&lt;Orientation&gt;, get_size: F) -&gt; bool &gt; where &gt; F: FnOnce(&amp;Device) -&gt; Size2D&lt;Au&gt;, &gt; { &gt; let query_orientation = match value { &gt; Some(v) =&gt; v, &gt; None =&gt; return true, &gt; }; &gt; &gt;@@ -183,74 +175,60 @@ where &gt; let is_landscape = size.width &gt; size.height; &gt; match query_orientation { &gt; Orientation::Landscape =&gt; is_landscape, &gt; Orientation::Portrait =&gt; !is_landscape, &gt; } &gt; } &gt; &gt; /// https://drafts.csswg.org/mediaqueries-4/#orientation &gt;-fn eval_orientation( &gt;- device: &amp;Device, &gt;- value: Option&lt;Orientation&gt;, &gt;-) -&gt; bool { &gt;+fn eval_orientation(device: &amp;Device, value: Option&lt;Orientation&gt;) -&gt; bool { &gt; eval_orientation_for(device, value, viewport_size) &gt; } &gt; &gt; /// FIXME: There's no spec for `-moz-device-orientation`. &gt;-fn eval_device_orientation( &gt;- device: &amp;Device, &gt;- value: Option&lt;Orientation&gt;, &gt;-) -&gt; bool { &gt;+fn eval_device_orientation(device: &amp;Device, value: Option&lt;Orientation&gt;) -&gt; bool { &gt; eval_orientation_for(device, value, device_size) &gt; } &gt; &gt; /// Values for the display-mode media feature. &gt; #[derive(Debug, Copy, Clone, FromPrimitive, ToCss, Parse)] &gt; #[repr(u8)] &gt; #[allow(missing_docs)] &gt; pub enum DisplayMode { &gt;- Browser = 0, &gt;- MinimalUi, &gt;- Standalone, &gt;- Fullscreen, &gt;+ Browser = 0, &gt;+ MinimalUi, &gt;+ Standalone, &gt;+ Fullscreen, &gt; } &gt; &gt; /// https://w3c.github.io/manifest/#the-display-mode-media-feature &gt;-fn eval_display_mode( &gt;- device: &amp;Device, &gt;- query_value: Option&lt;DisplayMode&gt;, &gt;-) -&gt; bool { &gt;+fn eval_display_mode(device: &amp;Device, query_value: Option&lt;DisplayMode&gt;) -&gt; bool { &gt; let query_value = match query_value { &gt; Some(v) =&gt; v, &gt; None =&gt; return true, &gt; }; &gt; &gt;- let gecko_display_mode = unsafe { &gt;- bindings::Gecko_MediaFeatures_GetDisplayMode(device.document()) &gt;- }; &gt;+ let gecko_display_mode = &gt;+ unsafe { bindings::Gecko_MediaFeatures_GetDisplayMode(device.document()) }; &gt; &gt; // NOTE: cbindgen guarantees the same representation. &gt; gecko_display_mode as u8 == query_value as u8 &gt; } &gt; &gt; /// https://drafts.csswg.org/mediaqueries-4/#grid &gt; fn eval_grid(_: &amp;Device, query_value: Option&lt;bool&gt;, _: Option&lt;RangeOrOperator&gt;) -&gt; bool { &gt; // Gecko doesn't support grid devices (e.g., ttys), so the 'grid' feature &gt; // is always 0. &gt; let supports_grid = false; &gt; query_value.map_or(supports_grid, |v| v == supports_grid) &gt; } &gt; &gt; /// https://compat.spec.whatwg.org/#css-media-queries-webkit-transform-3d &gt;-fn eval_transform_3d( &gt;- _: &amp;Device, &gt;- query_value: Option&lt;bool&gt;, &gt;- _: Option&lt;RangeOrOperator&gt;, &gt;-) -&gt; bool { &gt;+fn eval_transform_3d(_: &amp;Device, query_value: Option&lt;bool&gt;, _: Option&lt;RangeOrOperator&gt;) -&gt; bool { &gt; let supports_transforms = true; &gt; query_value.map_or(supports_transforms, |v| v == supports_transforms) &gt; } &gt; &gt; #[derive(Debug, Copy, Clone, FromPrimitive, ToCss, Parse)] &gt; #[repr(u8)] &gt; enum Scan { &gt; Progressive, &gt;@@ -267,81 +245,65 @@ fn eval_scan(_: &amp;Device, _: Option&lt;Scan&gt;) -&gt; bool { &gt; /// https://drafts.csswg.org/mediaqueries-4/#color &gt; fn eval_color( &gt; device: &amp;Device, &gt; query_value: Option&lt;u32&gt;, &gt; range_or_operator: Option&lt;RangeOrOperator&gt;, &gt; ) -&gt; bool { &gt; let color_bits_per_channel = &gt; unsafe { bindings::Gecko_MediaFeatures_GetColorDepth(device.document()) }; &gt;- RangeOrOperator::evaluate( &gt;- range_or_operator, &gt;- query_value, &gt;- color_bits_per_channel, &gt;- ) &gt;+ RangeOrOperator::evaluate(range_or_operator, query_value, color_bits_per_channel) &gt; } &gt; &gt; /// https://drafts.csswg.org/mediaqueries-4/#color-index &gt; fn eval_color_index( &gt; _: &amp;Device, &gt; query_value: Option&lt;u32&gt;, &gt; range_or_operator: Option&lt;RangeOrOperator&gt;, &gt; ) -&gt; bool { &gt; // We should return zero if the device does not use a color lookup table. &gt; let index = 0; &gt;- RangeOrOperator::evaluate( &gt;- range_or_operator, &gt;- query_value, &gt;- index, &gt;- ) &gt;+ RangeOrOperator::evaluate(range_or_operator, query_value, index) &gt; } &gt; &gt; /// https://drafts.csswg.org/mediaqueries-4/#monochrome &gt; fn eval_monochrome( &gt; _: &amp;Device, &gt; query_value: Option&lt;u32&gt;, &gt; range_or_operator: Option&lt;RangeOrOperator&gt;, &gt; ) -&gt; bool { &gt; // For color devices we should return 0. &gt; // FIXME: On a monochrome device, return the actual color depth, not 0! &gt; let depth = 0; &gt;- RangeOrOperator::evaluate( &gt;- range_or_operator, &gt;- query_value, &gt;- depth, &gt;- ) &gt;+ RangeOrOperator::evaluate(range_or_operator, query_value, depth) &gt; } &gt; &gt; /// https://drafts.csswg.org/mediaqueries-4/#resolution &gt; fn eval_resolution( &gt; device: &amp;Device, &gt; query_value: Option&lt;Resolution&gt;, &gt; range_or_operator: Option&lt;RangeOrOperator&gt;, &gt; ) -&gt; bool { &gt;- let resolution_dppx = &gt;- unsafe { bindings::Gecko_MediaFeatures_GetResolution(device.document()) }; &gt;+ let resolution_dppx = unsafe { bindings::Gecko_MediaFeatures_GetResolution(device.document()) }; &gt; RangeOrOperator::evaluate( &gt; range_or_operator, &gt; query_value.map(|r| r.dppx()), &gt; resolution_dppx, &gt; ) &gt; } &gt; &gt; #[derive(Debug, Copy, Clone, FromPrimitive, ToCss, Parse)] &gt; #[repr(u8)] &gt; enum PrefersReducedMotion { &gt; NoPreference, &gt; Reduce, &gt; } &gt; &gt; /// https://drafts.csswg.org/mediaqueries-5/#prefers-reduced-motion &gt;-fn eval_prefers_reduced_motion( &gt;- device: &amp;Device, &gt;- query_value: Option&lt;PrefersReducedMotion&gt;, &gt;-) -&gt; bool { &gt;+fn eval_prefers_reduced_motion(device: &amp;Device, query_value: Option&lt;PrefersReducedMotion&gt;) -&gt; bool { &gt; let prefers_reduced = &gt; unsafe { bindings::Gecko_MediaFeatures_PrefersReducedMotion(device.document()) }; &gt; let query_value = match query_value { &gt; Some(v) =&gt; v, &gt; None =&gt; return prefers_reduced, &gt; }; &gt; &gt; match query_value { &gt;@@ -359,19 +321,18 @@ fn eval_moz_is_glyph( &gt; query_value.map_or(is_glyph, |v| v == is_glyph) &gt; } &gt; &gt; fn eval_moz_is_resource_document( &gt; device: &amp;Device, &gt; query_value: Option&lt;bool&gt;, &gt; _: Option&lt;RangeOrOperator&gt;, &gt; ) -&gt; bool { &gt;- let is_resource_doc = unsafe { &gt;- bindings::Gecko_MediaFeatures_IsResourceDocument(device.document()) &gt;- }; &gt;+ let is_resource_doc = &gt;+ unsafe { bindings::Gecko_MediaFeatures_IsResourceDocument(device.document()) }; &gt; query_value.map_or(is_resource_doc, |v| v == is_resource_doc) &gt; } &gt; &gt; fn eval_system_metric( &gt; device: &amp;Device, &gt; query_value: Option&lt;bool&gt;, &gt; metric: Atom, &gt; accessible_from_content: bool, &gt;@@ -404,47 +365,40 @@ fn eval_moz_os_version( &gt; query_value: Option&lt;Atom&gt;, &gt; _: Option&lt;RangeOrOperator&gt;, &gt; ) -&gt; bool { &gt; let query_value = match query_value { &gt; Some(v) =&gt; v, &gt; None =&gt; return false, &gt; }; &gt; &gt;- let os_version = unsafe { &gt;- bindings::Gecko_MediaFeatures_GetOperatingSystemVersion(device.document()) &gt;- }; &gt;+ let os_version = &gt;+ unsafe { bindings::Gecko_MediaFeatures_GetOperatingSystemVersion(device.document()) }; &gt; &gt; query_value.as_ptr() == os_version &gt; } &gt; &gt; macro_rules! system_metric_feature { &gt;- ($feature_name:expr) =&gt; { &gt;- { &gt;- fn __eval( &gt;- device: &amp;Device, &gt;- query_value: Option&lt;bool&gt;, &gt;- _: Option&lt;RangeOrOperator&gt;, &gt;- ) -&gt; bool { &gt;- eval_system_metric( &gt;- device, &gt;- query_value, &gt;- $feature_name, &gt;- /* accessible_from_content = */ false, &gt;- ) &gt;- } &gt;- &gt;- feature!( &gt;+ ($feature_name:expr) =&gt; {{ &gt;+ fn __eval(device: &amp;Device, query_value: Option&lt;bool&gt;, _: Option&lt;RangeOrOperator&gt;) -&gt; bool { &gt;+ eval_system_metric( &gt;+ device, &gt;+ query_value, &gt; $feature_name, &gt;- AllowsRanges::No, &gt;- Evaluator::BoolInteger(__eval), &gt;- ParsingRequirements::CHROME_AND_UA_ONLY, &gt;+ /* accessible_from_content = */ false, &gt; ) &gt; } &gt;- } &gt;+ &gt;+ feature!( &gt;+ $feature_name, &gt;+ AllowsRanges::No, &gt;+ Evaluator::BoolInteger(__eval), &gt;+ ParsingRequirements::CHROME_AND_UA_ONLY, &gt;+ ) &gt;+ }}; &gt; } &gt; &gt; lazy_static! { &gt; /// Adding new media features requires (1) adding the new feature to this &gt; /// array, with appropriate entries (and potentially any new code needed &gt; /// to support new types in these entries and (2) ensuring that either &gt; /// nsPresContext::MediaFeatureValuesChanged is called when the value that &gt; /// would be returned by the evaluator function could change. &gt;diff --git a/servo/components/style/gecko/media_queries.rs b/servo/components/style/gecko/media_queries.rs &gt;index c41bc4ffd73e..9b77c6a00d81 100644 &gt;--- a/servo/components/style/gecko/media_queries.rs &gt;+++ b/servo/components/style/gecko/media_queries.rs &gt;@@ -1,33 +1,33 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Gecko's media-query device and expression representation. &gt; &gt;-use app_units::AU_PER_PX; &gt; use app_units::Au; &gt;+use app_units::AU_PER_PX; &gt; use cssparser::RGBA; &gt; use euclid::Size2D; &gt; use euclid::TypedScale; &gt; use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor}; &gt; use gecko_bindings::bindings; &gt; use gecko_bindings::structs; &gt; use gecko_bindings::structs::{nsPresContext, RawGeckoPresContextOwned}; &gt; use media_queries::MediaType; &gt; use properties::ComputedValues; &gt; use servo_arc::Arc; &gt; use std::fmt; &gt; use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering}; &gt; use string_cache::Atom; &gt;-use style_traits::{CSSPixel, DevicePixel}; &gt; use style_traits::viewport::ViewportConstraints; &gt;-use values::{CustomIdent, KeyframesName}; &gt;+use style_traits::{CSSPixel, DevicePixel}; &gt; use values::computed::font::FontSize; &gt;+use values::{CustomIdent, KeyframesName}; &gt; &gt; /// The `Device` in Gecko wraps a pres context, has a default values computed, &gt; /// and contains all the viewport rule state. &gt; pub struct Device { &gt; /// NB: The pres context lifetime is tied to the styleset, who owns the &gt; /// stylist, and thus the `Device`, so having a raw pres context pointer &gt; /// here is fine. &gt; pres_context: RawGeckoPresContextOwned, &gt;@@ -121,17 +121,18 @@ impl Device { &gt; /// Get the font size of the root element (for rem) &gt; pub fn root_font_size(&amp;self) -&gt; Au { &gt; self.used_root_font_size.store(true, Ordering::Relaxed); &gt; Au::new(self.root_font_size.load(Ordering::Relaxed) as i32) &gt; } &gt; &gt; /// Set the font size of the root element (for rem) &gt; pub fn set_root_font_size(&amp;self, size: Au) { &gt;- self.root_font_size.store(size.0 as isize, Ordering::Relaxed) &gt;+ self.root_font_size &gt;+ .store(size.0 as isize, Ordering::Relaxed) &gt; } &gt; &gt; /// Sets the body text color for the "inherit color from body" quirk. &gt; /// &gt; /// &lt;https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk&gt; &gt; pub fn set_body_text_color(&amp;self, color: RGBA) { &gt; self.body_text_color &gt; .store(convert_rgba_to_nscolor(&amp;color) as usize, Ordering::Relaxed) &gt;diff --git a/servo/components/style/gecko/pseudo_element.rs b/servo/components/style/gecko/pseudo_element.rs &gt;index a08da8d40f13..7c4fe22c2a9e 100644 &gt;--- a/servo/components/style/gecko/pseudo_element.rs &gt;+++ b/servo/components/style/gecko/pseudo_element.rs &gt;@@ -5,18 +5,18 @@ &gt; //! Gecko's definition of a pseudo-element. &gt; //! &gt; //! Note that a few autogenerated bits of this live in &gt; //! `pseudo_element_definition.mako.rs`. If you touch that file, you probably &gt; //! need to update the checked-in files for Servo. &gt; &gt; use cssparser::ToCss; &gt; use gecko_bindings::structs::{self, CSSPseudoElementType}; &gt;-use properties::{ComputedValues, PropertyFlags}; &gt; use properties::longhands::display::computed_value::T as Display; &gt;+use properties::{ComputedValues, PropertyFlags}; &gt; use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl}; &gt; use std::fmt; &gt; use string_cache::Atom; &gt; use thin_slice::ThinBoxedSlice; &gt; use values::serialize_atom_identifier; &gt; &gt; include!(concat!( &gt; env!("OUT_DIR"), &gt;@@ -56,17 +56,19 @@ impl PseudoElement { &gt; PseudoElementCascadeType::Lazy &gt; } &gt; &gt; /// Whether cascading this pseudo-element makes it inherit all properties, &gt; /// even reset ones. &gt; /// &gt; /// This is used in Servo for anonymous boxes, though it's likely broken. &gt; #[inline] &gt;- pub fn inherits_all(&amp;self) -&gt; bool { false } &gt;+ pub fn inherits_all(&amp;self) -&gt; bool { &gt;+ false &gt;+ } &gt; &gt; /// Whether the pseudo-element should inherit from the default computed &gt; /// values instead of from the parent element. &gt; /// &gt; /// This is not the common thing, but there are some pseudos (namely: &gt; /// ::backdrop), that shouldn't inherit from the parent element. &gt; pub fn inherits_from_default_values(&amp;self) -&gt; bool { &gt; matches!(*self, PseudoElement::Backdrop) &gt;diff --git a/servo/components/style/gecko/rules.rs b/servo/components/style/gecko/rules.rs &gt;index a57314a418cc..5a5d1b380569 100644 &gt;--- a/servo/components/style/gecko/rules.rs &gt;+++ b/servo/components/style/gecko/rules.rs &gt;@@ -2,26 +2,26 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Bindings for CSS Rule objects &gt; &gt; use byteorder::{BigEndian, WriteBytesExt}; &gt; use counter_style::{self, CounterBound}; &gt; use cssparser::UnicodeRange; &gt;-use font_face::{FontDisplay, FontWeight, FontStretch, FontStyle, Source}; &gt;+use font_face::{FontDisplay, FontStretch, FontStyle, FontWeight, Source}; &gt; use gecko_bindings::structs::{self, nsCSSValue}; &gt; use gecko_bindings::sugar::ns_css_value::ToNsCssValue; &gt; use properties::longhands::font_language_override; &gt; use std::str; &gt; use values::computed::font::FamilyName; &gt; use values::generics::font::FontTag; &gt;+use values::specified::font::SpecifiedFontStyle; &gt; use values::specified::font::{AbsoluteFontWeight, FontStretch as SpecifiedFontStretch}; &gt; use values::specified::font::{SpecifiedFontFeatureSettings, SpecifiedFontVariationSettings}; &gt;-use values::specified::font::SpecifiedFontStyle; &gt; &gt; impl&lt;'a&gt; ToNsCssValue for &amp;'a FamilyName { &gt; fn convert(self, nscssvalue: &amp;mut nsCSSValue) { &gt; nscssvalue.set_string_from_atom(&amp;self.name) &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; ToNsCssValue for &amp;'a SpecifiedFontStretch { &gt;@@ -96,17 +96,17 @@ macro_rules! descriptor_range_conversion { &gt; let mut b = nsCSSValue::null(); &gt; &gt; a.set_from(first); &gt; b.set_from(second); &gt; &gt; nscssvalue.set_pair(&amp;a, &amp;b); &gt; } &gt; } &gt;- } &gt;+ }; &gt; } &gt; &gt; descriptor_range_conversion!(FontWeight); &gt; descriptor_range_conversion!(FontStretch); &gt; &gt; impl&lt;'a&gt; ToNsCssValue for &amp;'a FontStyle { &gt; fn convert(self, nscssvalue: &amp;mut nsCSSValue) { &gt; match *self { &gt;@@ -126,17 +126,17 @@ impl&lt;'a&gt; ToNsCssValue for &amp;'a FontStyle { &gt; } &gt; &gt; impl&lt;'a&gt; ToNsCssValue for &amp;'a font_language_override::SpecifiedValue { &gt; fn convert(self, nscssvalue: &amp;mut nsCSSValue) { &gt; match *self { &gt; font_language_override::SpecifiedValue::Normal =&gt; nscssvalue.set_normal(), &gt; font_language_override::SpecifiedValue::Override(ref lang) =&gt; { &gt; nscssvalue.set_string(&amp;*lang) &gt;- }, &gt;+ } &gt; // This path is unreachable because the descriptor is only specified by the user. &gt; font_language_override::SpecifiedValue::System(_) =&gt; unreachable!(), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; ToNsCssValue for &amp;'a Vec&lt;Source&gt; { &gt; fn convert(self, nscssvalue: &amp;mut nsCSSValue) { &gt;@@ -160,20 +160,20 @@ impl&lt;'a&gt; ToNsCssValue for &amp;'a Vec&lt;Source&gt; { &gt; } &gt; for src in self.iter() { &gt; match *src { &gt; Source::Url(ref url) =&gt; { &gt; next!().set_url(&amp;url.url); &gt; for hint in url.format_hints.iter() { &gt; next!().set_font_format(&amp;hint); &gt; } &gt;- }, &gt;+ } &gt; Source::Local(ref family) =&gt; { &gt; next!().set_local_font(&amp;family.name); &gt;- }, &gt;+ } &gt; } &gt; } &gt; debug_assert!(target_srcs.next().is_none(), "Should have filled all slots"); &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; ToNsCssValue for &amp;'a Vec&lt;UnicodeRange&gt; { &gt; fn convert(self, nscssvalue: &amp;mut nsCSSValue) { &gt;@@ -212,24 +212,24 @@ impl&lt;'a&gt; ToNsCssValue for &amp;'a counter_style::System { &gt; Fixed { &gt; ref first_symbol_value, &gt; } =&gt; { &gt; let mut a = nsCSSValue::null(); &gt; let mut b = nsCSSValue::null(); &gt; a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_FIXED as i32); &gt; b.set_integer(first_symbol_value.map_or(1, |v| v.value())); &gt; nscssvalue.set_pair(&amp;a, &amp;b); &gt;- }, &gt;+ } &gt; Extends(ref other) =&gt; { &gt; let mut a = nsCSSValue::null(); &gt; let mut b = nsCSSValue::null(); &gt; a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_EXTENDS as i32); &gt; b.set_atom_ident(other.0.clone()); &gt; nscssvalue.set_pair(&amp;a, &amp;b); &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; ToNsCssValue for &amp;'a counter_style::Negative { &gt; fn convert(self, nscssvalue: &amp;mut nsCSSValue) { &gt; if let Some(ref second) = self.1 { &gt; let mut a = nsCSSValue::null(); &gt;diff --git a/servo/components/style/gecko/selector_parser.rs b/servo/components/style/gecko/selector_parser.rs &gt;index fa514835e8c7..456ca9e874d9 100644 &gt;--- a/servo/components/style/gecko/selector_parser.rs &gt;+++ b/servo/components/style/gecko/selector_parser.rs &gt;@@ -7,20 +7,20 @@ &gt; use cssparser::{BasicParseError, BasicParseErrorKind, Parser}; &gt; use cssparser::{CowRcStr, SourceLocation, ToCss, Token}; &gt; use element_state::{DocumentState, ElementState}; &gt; use gecko_bindings::structs; &gt; use gecko_bindings::structs::RawServoSelectorList; &gt; use gecko_bindings::sugar::ownership::{HasBoxFFI, HasFFI, HasSimpleFFI}; &gt; use invalidation::element::document_state::InvalidationMatchingData; &gt; use selector_parser::{Direction, SelectorParser}; &gt;-use selectors::SelectorList; &gt;-use selectors::parser::{SelectorParseErrorKind, Visit}; &gt; use selectors::parser::{self as selector_parser, Selector}; &gt;+use selectors::parser::{SelectorParseErrorKind, Visit}; &gt; use selectors::visitor::SelectorVisitor; &gt;+use selectors::SelectorList; &gt; use std::fmt; &gt; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; &gt; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss as ToCss_}; &gt; use thin_slice::ThinBoxedSlice; &gt; &gt; pub use gecko::pseudo_element::{PseudoElement, EAGER_PSEUDOS, EAGER_PSEUDO_COUNT, PSEUDO_COUNT}; &gt; pub use gecko::snapshot::SnapshotMap; &gt; &gt;@@ -189,19 +189,18 @@ impl NonTSPseudoClass { &gt; NonTSPseudoClass::Fullscreen =&gt; unsafe { &gt; mozilla::StaticPrefs_sVarCache_full_screen_api_unprefix_enabled &gt; }, &gt; NonTSPseudoClass::Defined =&gt; unsafe { &gt; structs::nsContentUtils_sIsCustomElementsEnabled &gt; }, &gt; // Otherwise, a pseudo-class is enabled in content when it &gt; // doesn't have any enabled flag. &gt;- _ =&gt; !self.has_any_flag( &gt;- NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME, &gt;- ), &gt;+ _ =&gt; !self &gt;+ .has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME), &gt; } &gt; } &gt; &gt; /// &lt;https://drafts.csswg.org/selectors-4/#useraction-pseudos&gt; &gt; /// &gt; /// We intentionally skip the link-related ones. &gt; pub fn is_safe_user_action_state(&amp;self) -&gt; bool { &gt; matches!( &gt;@@ -242,18 +241,17 @@ impl NonTSPseudoClass { &gt; NonTSPseudoClass::MozWindowInactive =&gt; DocumentState::NS_DOCUMENT_STATE_WINDOW_INACTIVE, &gt; _ =&gt; DocumentState::empty(), &gt; } &gt; } &gt; &gt; /// Returns true if the given pseudoclass should trigger style sharing cache &gt; /// revalidation. &gt; pub fn needs_cache_revalidation(&amp;self) -&gt; bool { &gt;- self.state_flag().is_empty() &amp;&amp; &gt;- !matches!(*self, &gt;+ self.state_flag().is_empty() &amp;&amp; !matches!(*self, &gt; // :-moz-any is handled by the revalidation visitor walking &gt; // the things inside it; it does not need to cause &gt; // revalidation on its own. &gt; NonTSPseudoClass::MozAny(_) | &gt; // :dir() depends on state only, but doesn't use state_flag &gt; // because its semantics don't quite match. Nevertheless, it &gt; // doesn't need cache revalidation, because we already compare &gt; // states for elements and candidates. &gt;@@ -277,18 +275,19 @@ impl NonTSPseudoClass { &gt; ) &gt; } &gt; &gt; /// Returns true if the evaluation of the pseudo-class depends on the &gt; /// element's attributes. &gt; pub fn is_attr_based(&amp;self) -&gt; bool { &gt; matches!( &gt; *self, &gt;- NonTSPseudoClass::MozTableBorderNonzero | NonTSPseudoClass::MozBrowserFrame | &gt;- NonTSPseudoClass::Lang(..) &gt;+ NonTSPseudoClass::MozTableBorderNonzero &gt;+ | NonTSPseudoClass::MozBrowserFrame &gt;+ | NonTSPseudoClass::Lang(..) &gt; ) &gt; } &gt; } &gt; &gt; impl ::selectors::parser::NonTSPseudoClass for NonTSPseudoClass { &gt; type Impl = SelectorImpl; &gt; &gt; #[inline] &gt;@@ -317,24 +316,24 @@ impl ::selectors::SelectorImpl for SelectorImpl { &gt; } &gt; &gt; impl&lt;'a&gt; SelectorParser&lt;'a&gt; { &gt; fn is_pseudo_class_enabled(&amp;self, pseudo_class: &amp;NonTSPseudoClass) -&gt; bool { &gt; if pseudo_class.is_enabled_in_content() { &gt; return true; &gt; } &gt; &gt;- if self.in_user_agent_stylesheet() &amp;&amp; &gt;- pseudo_class.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS) &gt;+ if self.in_user_agent_stylesheet() &gt;+ &amp;&amp; pseudo_class.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_UA_SHEETS) &gt; { &gt; return true; &gt; } &gt; &gt;- if self.chrome_rules_enabled() &amp;&amp; &gt;- pseudo_class.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_CHROME) &gt;+ if self.chrome_rules_enabled() &gt;+ &amp;&amp; pseudo_class.has_any_flag(NonTSPseudoClassFlag::PSEUDO_CLASS_ENABLED_IN_CHROME) &gt; { &gt; return true; &gt; } &gt; &gt; return false; &gt; } &gt; &gt; fn is_pseudo_element_enabled(&amp;self, pseudo_element: &amp;PseudoElement) -&gt; bool { &gt;@@ -472,17 +471,17 @@ impl&lt;'a, 'i&gt; ::selectors::Parser&lt;'i&gt; for SelectorParser&lt;'a&gt; { &gt; if name.starts_with("-moz-tree-") { &gt; // Tree pseudo-elements can have zero or more arguments, separated &gt; // by either comma or space. &gt; let mut args = Vec::new(); &gt; loop { &gt; let location = parser.current_source_location(); &gt; match parser.next() { &gt; Ok(&amp;Token::Ident(ref ident)) =&gt; args.push(Atom::from(ident.as_ref())), &gt;- Ok(&amp;Token::Comma) =&gt; {}, &gt;+ Ok(&amp;Token::Comma) =&gt; {} &gt; Ok(t) =&gt; return Err(location.new_unexpected_token_error(t.clone())), &gt; Err(BasicParseError { &gt; kind: BasicParseErrorKind::EndOfInput, &gt; .. &gt; }) =&gt; break, &gt; _ =&gt; unreachable!("Parser::next() shouldn't return any other error"), &gt; } &gt; } &gt;diff --git a/servo/components/style/gecko/snapshot.rs b/servo/components/style/gecko/snapshot.rs &gt;index fc4a9121ae40..6b6266dce6e6 100644 &gt;--- a/servo/components/style/gecko/snapshot.rs &gt;+++ b/servo/components/style/gecko/snapshot.rs &gt;@@ -1,28 +1,28 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! A gecko snapshot, that stores the element attributes and state before they &gt; //! change in order to properly calculate restyle hints. &gt; &gt;-use WeakAtom; &gt; use dom::TElement; &gt; use element_state::ElementState; &gt; use gecko::snapshot_helpers; &gt; use gecko::wrapper::{GeckoElement, NamespaceConstraintHelpers}; &gt; use gecko_bindings::bindings; &gt; use gecko_bindings::structs::ServoElementSnapshot; &gt; use gecko_bindings::structs::ServoElementSnapshotFlags as Flags; &gt; use gecko_bindings::structs::ServoElementSnapshotTable; &gt; use invalidation::element::element_wrapper::ElementSnapshot; &gt; use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator}; &gt; use selectors::attr::{CaseSensitivity, NamespaceConstraint}; &gt; use string_cache::{Atom, Namespace}; &gt;+use WeakAtom; &gt; &gt; /// A snapshot of a Gecko element. &gt; pub type GeckoElementSnapshot = ServoElementSnapshot; &gt; &gt; /// A map from elements to snapshots for Gecko's style back-end. &gt; pub type SnapshotMap = ServoElementSnapshotTable; &gt; &gt; impl SnapshotMap { &gt;@@ -83,17 +83,17 @@ impl GeckoElementSnapshot { &gt; ns: &amp;NamespaceConstraint&lt;&amp;Namespace&gt;, &gt; local_name: &amp;Atom, &gt; operation: &amp;AttrSelectorOperation&lt;&amp;Atom&gt;, &gt; ) -&gt; bool { &gt; unsafe { &gt; match *operation { &gt; AttrSelectorOperation::Exists =&gt; { &gt; bindings::Gecko_SnapshotHasAttr(self, ns.atom_or_null(), local_name.as_ptr()) &gt;- }, &gt;+ } &gt; AttrSelectorOperation::WithValue { &gt; operator, &gt; case_sensitivity, &gt; expected_value, &gt; } =&gt; { &gt; let ignore_case = match case_sensitivity { &gt; CaseSensitivity::CaseSensitive =&gt; false, &gt; CaseSensitivity::AsciiCaseInsensitive =&gt; true, &gt;@@ -138,19 +138,19 @@ impl GeckoElementSnapshot { &gt; AttrSelectorOperator::Substring =&gt; { &gt; bindings::Gecko_SnapshotAttrHasSubstring( &gt; self, &gt; ns.atom_or_null(), &gt; local_name.as_ptr(), &gt; expected_value.as_ptr(), &gt; ignore_case, &gt; ) &gt;- }, &gt;+ } &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; } &gt; &gt; impl ElementSnapshot for GeckoElementSnapshot { &gt; fn debug_list_attributes(&amp;self) -&gt; String { &gt; use nsstring::nsCString; &gt;diff --git a/servo/components/style/gecko/snapshot_helpers.rs b/servo/components/style/gecko/snapshot_helpers.rs &gt;index 6c40f242d5f0..1b8ba9735fc5 100644 &gt;--- a/servo/components/style/gecko/snapshot_helpers.rs &gt;+++ b/servo/components/style/gecko/snapshot_helpers.rs &gt;@@ -1,19 +1,19 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Element an snapshot common logic. &gt; &gt;-use CaseSensitivityExt; &gt; use gecko_bindings::bindings; &gt; use gecko_bindings::structs::{self, nsAtom}; &gt; use selectors::attr::CaseSensitivity; &gt; use string_cache::{Atom, WeakAtom}; &gt;+use CaseSensitivityExt; &gt; &gt; /// A function that, given an element of type `T`, allows you to get a single &gt; /// class or a class list. &gt; enum Class&lt;'a&gt; { &gt; None, &gt; One(*const nsAtom), &gt; More(&amp;'a [structs::RefPtr&lt;nsAtom&gt;]), &gt; } &gt;@@ -36,35 +36,47 @@ unsafe fn get_class_from_attr(attr: &amp;structs::nsAttrValue) -&gt; Class { &gt; return Class::None; &gt; } &gt; if base_type == structs::nsAttrValue_ValueBaseType_eAtomBase { &gt; return Class::One(ptr::&lt;nsAtom&gt;(attr)); &gt; } &gt; debug_assert_eq!(base_type, structs::nsAttrValue_ValueBaseType_eOtherBase); &gt; &gt; let container = ptr::&lt;structs::MiscContainer&gt;(attr); &gt;- debug_assert_eq!((*container).mType, structs::nsAttrValue_ValueType_eAtomArray); &gt;- let array = &gt;- (*container).__bindgen_anon_1.mValue.as_ref().__bindgen_anon_1.mAtomArray.as_ref(); &gt;+ debug_assert_eq!( &gt;+ (*container).mType, &gt;+ structs::nsAttrValue_ValueType_eAtomArray &gt;+ ); &gt;+ let array = (*container) &gt;+ .__bindgen_anon_1 &gt;+ .mValue &gt;+ .as_ref() &gt;+ .__bindgen_anon_1 &gt;+ .mAtomArray &gt;+ .as_ref(); &gt; Class::More(&amp;***array) &gt; } &gt; &gt; #[inline(always)] &gt; unsafe fn get_id_from_attr(attr: &amp;structs::nsAttrValue) -&gt; &amp;WeakAtom { &gt;- debug_assert_eq!(base_type(attr), structs::nsAttrValue_ValueBaseType_eAtomBase); &gt;+ debug_assert_eq!( &gt;+ base_type(attr), &gt;+ structs::nsAttrValue_ValueBaseType_eAtomBase &gt;+ ); &gt; WeakAtom::new(ptr::&lt;nsAtom&gt;(attr)) &gt; } &gt; &gt; /// Find an attribute value with a given name and no namespace. &gt; #[inline(always)] &gt; pub fn find_attr&lt;'a&gt;( &gt; attrs: &amp;'a [structs::AttrArray_InternalAttr], &gt; name: &amp;Atom, &gt; ) -&gt; Option&lt;&amp;'a structs::nsAttrValue&gt; { &gt;- attrs.iter() &gt;+ attrs &gt;+ .iter() &gt; .find(|attr| attr.mName.mBits == name.as_ptr() as usize) &gt; .map(|attr| &amp;attr.mValue) &gt; } &gt; &gt; /// Finds the id attribute from a list of attributes. &gt; #[inline(always)] &gt; pub fn get_id(attrs: &amp;[structs::AttrArray_InternalAttr]) -&gt; Option&lt;&amp;WeakAtom&gt; { &gt; Some(unsafe { get_id_from_attr(find_attr(attrs, &amp;atom!("id"))?) }) &gt;@@ -75,42 +87,40 @@ pub fn get_id(attrs: &amp;[structs::AttrArray_InternalAttr]) -&gt; Option&lt;&amp;WeakAtom&gt; { &gt; #[inline(always)] &gt; pub fn has_class( &gt; name: &amp;Atom, &gt; case_sensitivity: CaseSensitivity, &gt; attr: &amp;structs::nsAttrValue, &gt; ) -&gt; bool { &gt; match unsafe { get_class_from_attr(attr) } { &gt; Class::None =&gt; false, &gt;- Class::One(atom) =&gt; unsafe { &gt;- case_sensitivity.eq_atom(name, WeakAtom::new(atom)) &gt;+ Class::One(atom) =&gt; unsafe { case_sensitivity.eq_atom(name, WeakAtom::new(atom)) }, &gt;+ Class::More(atoms) =&gt; match case_sensitivity { &gt;+ CaseSensitivity::CaseSensitive =&gt; { &gt;+ atoms.iter().any(|atom| atom.mRawPtr == name.as_ptr()) &gt;+ } &gt;+ CaseSensitivity::AsciiCaseInsensitive =&gt; unsafe { &gt;+ atoms &gt;+ .iter() &gt;+ .any(|atom| WeakAtom::new(atom.mRawPtr).eq_ignore_ascii_case(name)) &gt;+ }, &gt; }, &gt;- Class::More(atoms) =&gt; { &gt;- match case_sensitivity { &gt;- CaseSensitivity::CaseSensitive =&gt; { &gt;- atoms.iter().any(|atom| atom.mRawPtr == name.as_ptr()) &gt;- } &gt;- CaseSensitivity::AsciiCaseInsensitive =&gt; unsafe { &gt;- atoms.iter().any(|atom| WeakAtom::new(atom.mRawPtr).eq_ignore_ascii_case(name)) &gt;- } &gt;- } &gt;- } &gt; } &gt; } &gt; &gt; /// Given an item, a callback, and a getter, execute `callback` for each class &gt; /// this `item` has. &gt; #[inline(always)] &gt; pub fn each_class&lt;F&gt;(attr: &amp;structs::nsAttrValue, mut callback: F) &gt; where &gt; F: FnMut(&amp;Atom), &gt; { &gt; unsafe { &gt; match get_class_from_attr(attr) { &gt;- Class::None =&gt; {}, &gt;+ Class::None =&gt; {} &gt; Class::One(atom) =&gt; Atom::with(atom, callback), &gt; Class::More(atoms) =&gt; { &gt; for atom in atoms { &gt; Atom::with(atom.mRawPtr, &amp;mut callback) &gt; } &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/style/gecko/url.rs b/servo/components/style/gecko/url.rs &gt;index b94d21397648..de1889d4b403 100644 &gt;--- a/servo/components/style/gecko/url.rs &gt;+++ b/servo/components/style/gecko/url.rs &gt;@@ -1,20 +1,20 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Common handling for the specified value CSS url() values. &gt; &gt; use cssparser::Parser; &gt; use gecko_bindings::bindings; &gt;-use gecko_bindings::structs::ServoBundledURI; &gt; use gecko_bindings::structs::mozilla::css::URLValueData; &gt;-use gecko_bindings::structs::root::{RustString, nsStyleImageRequest}; &gt; use gecko_bindings::structs::root::mozilla::css::{ImageValue, URLValue}; &gt;+use gecko_bindings::structs::root::{nsStyleImageRequest, RustString}; &gt;+use gecko_bindings::structs::ServoBundledURI; &gt; use gecko_bindings::sugar::refptr::RefPtr; &gt; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; &gt; use nsstring::nsCString; &gt; use parser::{Parse, ParserContext}; &gt; use servo_arc::{Arc, RawOffsetArc}; &gt; use std::fmt::{self, Write}; &gt; use std::mem; &gt; use style_traits::{CssWriter, ParseError, ToCss}; &gt;@@ -50,18 +50,17 @@ impl CssUrl { &gt; /// URLs in gecko, so we just return false here. &gt; /// use its |resolved| status. &gt; pub fn is_invalid(&amp;self) -&gt; bool { &gt; false &gt; } &gt; &gt; /// Convert from URLValueData to SpecifiedUrl. &gt; unsafe fn from_url_value_data(url: &amp;URLValueData) -&gt; Self { &gt;- let arc_type = &gt;- &amp;url.mString as *const _ as *const RawOffsetArc&lt;String&gt;; &gt;+ let arc_type = &amp;url.mString as *const _ as *const RawOffsetArc&lt;String&gt;; &gt; CssUrl { &gt; serialization: Arc::from_raw_offset((*arc_type).clone()), &gt; extra_data: UrlExtraData(url.mExtraData.to_safe()), &gt; } &gt; } &gt; &gt; /// Returns true if this URL looks like a fragment. &gt; /// See https://drafts.csswg.org/css-values/#local-urls &gt;@@ -135,17 +134,16 @@ impl SpecifiedUrl { &gt; // We do not expect Gecko_NewURLValue returns null. &gt; debug_assert!(!ptr.is_null()); &gt; RefPtr::from_addrefed(ptr) &gt; }; &gt; Self { url, url_value } &gt; } &gt; } &gt; &gt;- &gt; impl PartialEq for SpecifiedUrl { &gt; fn eq(&amp;self, other: &amp;Self) -&gt; bool { &gt; self.url.eq(&amp;other.url) &gt; } &gt; } &gt; &gt; impl Eq for SpecifiedUrl {} &gt; &gt;@@ -250,20 +248,17 @@ impl ToComputedValue for SpecifiedImageUrl { &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; computed.0.clone() &gt; } &gt; } &gt; &gt;-fn serialize_computed_url&lt;W&gt;( &gt;- url_value_data: &amp;URLValueData, &gt;- dest: &amp;mut CssWriter&lt;W&gt;, &gt;-) -&gt; fmt::Result &gt;+fn serialize_computed_url&lt;W&gt;(url_value_data: &amp;URLValueData, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; dest.write_str("url(")?; &gt; unsafe { &gt; let mut string = nsCString::new(); &gt; bindings::Gecko_GetComputedURLSpec(url_value_data, &amp;mut string); &gt; string.as_str_unchecked().to_css(dest)?; &gt;@@ -276,17 +271,17 @@ where &gt; /// The only difference between specified and computed URLs is the &gt; /// serialization. &gt; #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] &gt; pub struct ComputedUrl(pub SpecifiedUrl); &gt; &gt; impl ToCss for ComputedUrl { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt;- W: Write &gt;+ W: Write, &gt; { &gt; serialize_computed_url(&amp;self.0.url_value._base, dest) &gt; } &gt; } &gt; &gt; impl ComputedUrl { &gt; /// Convert from RefPtr&lt;URLValue&gt; to ComputedUrl. &gt; pub unsafe fn from_url_value(url_value: RefPtr&lt;URLValue&gt;) -&gt; Self { &gt;@@ -297,17 +292,17 @@ impl ComputedUrl { &gt; &gt; /// The computed value of a CSS `url()` for image. &gt; #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] &gt; pub struct ComputedImageUrl(pub SpecifiedImageUrl); &gt; &gt; impl ToCss for ComputedImageUrl { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt;- W: Write &gt;+ W: Write, &gt; { &gt; serialize_computed_url(&amp;self.0.image_value._base, dest) &gt; } &gt; } &gt; &gt; impl ComputedImageUrl { &gt; /// Convert from nsStyleImageReques to ComputedImageUrl. &gt; pub unsafe fn from_image_request(image_request: &amp;nsStyleImageRequest) -&gt; Self { &gt;diff --git a/servo/components/style/gecko/values.rs b/servo/components/style/gecko/values.rs &gt;index 3bb22947211d..b2b5ac937f1f 100644 &gt;--- a/servo/components/style/gecko/values.rs &gt;+++ b/servo/components/style/gecko/values.rs &gt;@@ -1,39 +1,41 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; #![allow(unsafe_code)] &gt; &gt; //! Different kind of helpers to interact with Gecko values. &gt; &gt;-use Atom; &gt; use app_units::Au; &gt; use counter_style::{Symbol, Symbols}; &gt; use cssparser::RGBA; &gt;-use gecko_bindings::structs::{self, CounterStylePtr, nsStyleCoord}; &gt;+use gecko_bindings::structs::{self, nsStyleCoord, CounterStylePtr}; &gt; use gecko_bindings::structs::{StyleGridTrackBreadth, StyleShapeRadius}; &gt; use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue}; &gt; use media_queries::Device; &gt; use nsstring::{nsACString, nsCStr}; &gt; use std::cmp::max; &gt;-use values::{Auto, Either, None_, Normal}; &gt;-use values::computed::{Angle, ExtremumLength, Length, LengthOrPercentage, LengthOrPercentageOrAuto}; &gt;+use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius; &gt;+use values::computed::FlexBasis as ComputedFlexBasis; &gt;+use values::computed::{ &gt;+ Angle, ExtremumLength, Length, LengthOrPercentage, LengthOrPercentageOrAuto, &gt;+}; &gt; use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage}; &gt; use values::computed::{MaxLength, MozLength, Percentage}; &gt; use values::computed::{NonNegativeLength, NonNegativeLengthOrPercentage, NonNegativeNumber}; &gt;-use values::computed::FlexBasis as ComputedFlexBasis; &gt;-use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius; &gt;-use values::generics::{CounterStyleOrNone, NonNegative}; &gt; use values::generics::basic_shape::ShapeRadius; &gt; use values::generics::box_::Perspective; &gt; use values::generics::flex::FlexBasis; &gt; use values::generics::gecko::ScrollSnapPoint; &gt; use values::generics::grid::{TrackBreadth, TrackKeyword}; &gt;+use values::generics::{CounterStyleOrNone, NonNegative}; &gt;+use values::{Auto, Either, None_, Normal}; &gt;+use Atom; &gt; &gt; /// A trait that defines an interface to convert from and to `nsStyleCoord`s. &gt; pub trait GeckoStyleCoordConvertible: Sized { &gt; /// Convert this to a `nsStyleCoord`. &gt; fn to_gecko_style_coord&lt;T: CoordDataMut&gt;(&amp;self, coord: &amp;mut T); &gt; /// Given a `nsStyleCoord`, try to get a value of this type.. &gt; fn from_gecko_style_coord&lt;T: CoordData&gt;(coord: &amp;T) -&gt; Option&lt;Self&gt;; &gt; } &gt;@@ -202,17 +204,17 @@ impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto { &gt; }; &gt; coord.set_value(value); &gt; } &gt; &gt; fn from_gecko_style_coord&lt;T: CoordData&gt;(coord: &amp;T) -&gt; Option&lt;Self&gt; { &gt; match coord.as_value() { &gt; CoordDataValue::Coord(coord) =&gt; { &gt; Some(LengthOrPercentageOrAuto::Length(Au(coord).into())) &gt;- }, &gt;+ } &gt; CoordDataValue::Percent(p) =&gt; Some(LengthOrPercentageOrAuto::Percentage(Percentage(p))), &gt; CoordDataValue::Auto =&gt; Some(LengthOrPercentageOrAuto::Auto), &gt; CoordDataValue::Calc(calc) =&gt; Some(LengthOrPercentageOrAuto::Calc(calc.into())), &gt; _ =&gt; None, &gt; } &gt; } &gt; } &gt; &gt;@@ -226,17 +228,17 @@ impl GeckoStyleCoordConvertible for LengthOrPercentageOrNone { &gt; }; &gt; coord.set_value(value); &gt; } &gt; &gt; fn from_gecko_style_coord&lt;T: CoordData&gt;(coord: &amp;T) -&gt; Option&lt;Self&gt; { &gt; match coord.as_value() { &gt; CoordDataValue::Coord(coord) =&gt; { &gt; Some(LengthOrPercentageOrNone::Length(Au(coord).into())) &gt;- }, &gt;+ } &gt; CoordDataValue::Percent(p) =&gt; Some(LengthOrPercentageOrNone::Percentage(Percentage(p))), &gt; CoordDataValue::None =&gt; Some(LengthOrPercentageOrNone::None), &gt; CoordDataValue::Calc(calc) =&gt; Some(LengthOrPercentageOrNone::Calc(calc.into())), &gt; _ =&gt; None, &gt; } &gt; } &gt; } &gt; &gt;@@ -262,17 +264,17 @@ impl&lt;L: GeckoStyleCoordConvertible&gt; GeckoStyleCoordConvertible for TrackBreadth&lt; &gt; CoordDataValue::Enumerated(v) =&gt; { &gt; if v == StyleGridTrackBreadth::MinContent as u32 { &gt; Some(TrackBreadth::Keyword(TrackKeyword::MinContent)) &gt; } else if v == StyleGridTrackBreadth::MaxContent as u32 { &gt; Some(TrackBreadth::Keyword(TrackKeyword::MaxContent)) &gt; } else { &gt; None &gt; } &gt;- }, &gt;+ } &gt; CoordDataValue::FlexFraction(fr) =&gt; Some(TrackBreadth::Fr(fr)), &gt; CoordDataValue::Auto =&gt; Some(TrackBreadth::Keyword(TrackKeyword::Auto)), &gt; _ =&gt; L::from_gecko_style_coord(coord).map(TrackBreadth::Breadth), &gt; }) &gt; } &gt; } &gt; &gt; impl GeckoStyleCoordConvertible for ComputedShapeRadius { &gt;@@ -293,17 +295,17 @@ impl GeckoStyleCoordConvertible for ComputedShapeRadius { &gt; CoordDataValue::Enumerated(v) =&gt; { &gt; if v == StyleShapeRadius::ClosestSide as u32 { &gt; Some(ShapeRadius::ClosestSide) &gt; } else if v == StyleShapeRadius::FarthestSide as u32 { &gt; Some(ShapeRadius::FarthestSide) &gt; } else { &gt; None &gt; } &gt;- }, &gt;+ } &gt; _ =&gt; LengthOrPercentage::from_gecko_style_coord(coord).map(ShapeRadius::Length), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;T: GeckoStyleCoordConvertible&gt; GeckoStyleCoordConvertible for Option&lt;T&gt; { &gt; fn to_gecko_style_coord&lt;U: CoordDataMut&gt;(&amp;self, coord: &amp;mut U) { &gt; if let Some(ref me) = *self { &gt;@@ -389,26 +391,26 @@ impl GeckoStyleCoordConvertible for ExtremumLength { &gt; } &gt; &gt; fn from_gecko_style_coord&lt;T: CoordData&gt;(coord: &amp;T) -&gt; Option&lt;Self&gt; { &gt; use gecko_bindings::structs::{NS_STYLE_WIDTH_AVAILABLE, NS_STYLE_WIDTH_FIT_CONTENT}; &gt; use gecko_bindings::structs::{NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT}; &gt; match coord.as_value() { &gt; CoordDataValue::Enumerated(NS_STYLE_WIDTH_MAX_CONTENT) =&gt; { &gt; Some(ExtremumLength::MozMaxContent) &gt;- }, &gt;+ } &gt; CoordDataValue::Enumerated(NS_STYLE_WIDTH_MIN_CONTENT) =&gt; { &gt; Some(ExtremumLength::MozMinContent) &gt;- }, &gt;+ } &gt; CoordDataValue::Enumerated(NS_STYLE_WIDTH_FIT_CONTENT) =&gt; { &gt; Some(ExtremumLength::MozFitContent) &gt;- }, &gt;+ } &gt; CoordDataValue::Enumerated(NS_STYLE_WIDTH_AVAILABLE) =&gt; { &gt; Some(ExtremumLength::MozAvailable) &gt;- }, &gt;+ } &gt; _ =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; impl GeckoStyleCoordConvertible for MozLength { &gt; fn to_gecko_style_coord&lt;T: CoordDataMut&gt;(&amp;self, coord: &amp;mut T) { &gt; match *self { &gt;@@ -483,18 +485,20 @@ where &gt; return Some(Perspective::None); &gt; } &gt; Some(Perspective::Length(L::from_gecko_style_coord(coord)?)) &gt; } &gt; } &gt; &gt; /// Convert a given RGBA value to `nscolor`. &gt; pub fn convert_rgba_to_nscolor(rgba: &amp;RGBA) -&gt; u32 { &gt;- ((rgba.alpha as u32) &lt;&lt; 24) | ((rgba.blue as u32) &lt;&lt; 16) | ((rgba.green as u32) &lt;&lt; 8) | &gt;- (rgba.red as u32) &gt;+ ((rgba.alpha as u32) &lt;&lt; 24) &gt;+ | ((rgba.blue as u32) &lt;&lt; 16) &gt;+ | ((rgba.green as u32) &lt;&lt; 8) &gt;+ | (rgba.red as u32) &gt; } &gt; &gt; /// Convert a given `nscolor` to a Servo RGBA value. &gt; pub fn convert_nscolor_to_rgba(color: u32) -&gt; RGBA { &gt; RGBA::new( &gt; (color &amp; 0xff) as u8, &gt; (color &gt;&gt; 8 &amp; 0xff) as u8, &gt; (color &gt;&gt; 16 &amp; 0xff) as u8, &gt;@@ -532,39 +536,38 @@ impl CounterStyleOrNone { &gt; }, &gt; CounterStyleOrNone::Symbols(symbols_type, symbols) =&gt; { &gt; let symbols: Vec&lt;_&gt; = symbols &gt; .0 &gt; .iter() &gt; .map(|symbol| match *symbol { &gt; Symbol::String(ref s) =&gt; nsCStr::from(s), &gt; Symbol::Ident(_) =&gt; unreachable!("Should not have identifier in symbols()"), &gt;- }) &gt;- .collect(); &gt;+ }).collect(); &gt; let symbols: Vec&lt;_&gt; = symbols &gt; .iter() &gt; .map(|symbol| symbol as &amp;nsACString as *const _) &gt; .collect(); &gt; unsafe { &gt; set_symbols( &gt; gecko_value, &gt; symbols_type.to_gecko_keyword(), &gt; symbols.as_ptr(), &gt; symbols.len() as u32, &gt; ) &gt; }; &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Convert Gecko CounterStylePtr to CounterStyleOrNone or String. &gt; pub fn from_gecko_value(gecko_value: &amp;CounterStylePtr) -&gt; Either&lt;Self, String&gt; { &gt; use gecko_bindings::bindings; &gt;- use values::CustomIdent; &gt; use values::generics::SymbolsType; &gt;+ use values::CustomIdent; &gt; &gt; let name = unsafe { bindings::Gecko_CounterStyle_GetName(gecko_value) }; &gt; if !name.is_null() { &gt; let name = unsafe { Atom::from_raw(name) }; &gt; if name == atom!("none") { &gt; Either::First(CounterStyleOrNone::None) &gt; } else { &gt; Either::First(CounterStyleOrNone::Name(CustomIdent(name))) &gt;diff --git a/servo/components/style/gecko/wrapper.rs b/servo/components/style/gecko/wrapper.rs &gt;index 1ba850696d15..d81bab247395 100644 &gt;--- a/servo/components/style/gecko/wrapper.rs &gt;+++ b/servo/components/style/gecko/wrapper.rs &gt;@@ -9,88 +9,89 @@ &gt; //! &gt; //! This really follows the Servo pattern in &gt; //! `components/script/layout_wrapper.rs`. &gt; //! &gt; //! This theoretically should live in its own crate, but now it lives in the &gt; //! style system it's kind of pointless in the Stylo case, and only Servo forces &gt; //! the separation between the style system implementation and everything else. &gt; &gt;-use CaseSensitivityExt; &gt; use app_units::Au; &gt; use applicable_declarations::ApplicableDeclarationBlock; &gt; use atomic_refcell::{AtomicRefCell, AtomicRefMut}; &gt; use author_styles::AuthorStyles; &gt; use context::{PostAnimationTasks, QuirksMode, SharedStyleContext, UpdateAnimationsTasks}; &gt; use data::ElementData; &gt; use dom::{LayoutIterator, NodeInfo, OpaqueNode, TDocument, TElement, TNode, TShadowRoot}; &gt; use element_state::{DocumentState, ElementState}; &gt; use font_metrics::{FontMetrics, FontMetricsProvider, FontMetricsQueryResult}; &gt; use gecko::data::GeckoStyleSheet; &gt; use gecko::global_style_data::GLOBAL_STYLE_DATA; &gt; use gecko::selector_parser::{NonTSPseudoClass, PseudoElement, SelectorImpl}; &gt; use gecko::snapshot_helpers; &gt; use gecko_bindings::bindings; &gt;-use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWTheme}; &gt;-use gecko_bindings::bindings::{Gecko_GetLastChild, Gecko_GetPreviousSibling, Gecko_GetNextStyleChild}; &gt;-use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags}; &gt; use gecko_bindings::bindings::Gecko_ElementHasAnimations; &gt; use gecko_bindings::bindings::Gecko_ElementHasCSSAnimations; &gt; use gecko_bindings::bindings::Gecko_ElementHasCSSTransitions; &gt; use gecko_bindings::bindings::Gecko_GetActiveLinkAttrDeclarationBlock; &gt; use gecko_bindings::bindings::Gecko_GetAnimationEffectCount; &gt; use gecko_bindings::bindings::Gecko_GetAnimationRule; &gt; use gecko_bindings::bindings::Gecko_GetExtraContentStyleDeclarations; &gt; use gecko_bindings::bindings::Gecko_GetHTMLPresentationAttrDeclarationBlock; &gt; use gecko_bindings::bindings::Gecko_GetStyleAttrDeclarationBlock; &gt; use gecko_bindings::bindings::Gecko_GetUnvisitedLinkAttrDeclarationBlock; &gt; use gecko_bindings::bindings::Gecko_GetVisitedLinkAttrDeclarationBlock; &gt; use gecko_bindings::bindings::Gecko_IsSignificantChild; &gt; use gecko_bindings::bindings::Gecko_MatchLang; &gt; use gecko_bindings::bindings::Gecko_UnsetDirtyStyleAttr; &gt; use gecko_bindings::bindings::Gecko_UpdateAnimations; &gt;+use gecko_bindings::bindings::{Gecko_ElementState, Gecko_GetDocumentLWTheme}; &gt;+use gecko_bindings::bindings::{ &gt;+ Gecko_GetLastChild, Gecko_GetNextStyleChild, Gecko_GetPreviousSibling, &gt;+}; &gt;+use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags}; &gt; use gecko_bindings::structs; &gt;-use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode, RawGeckoXBLBinding}; &gt;-use gecko_bindings::structs::{nsAtom, nsIContent, nsINode_BooleanFlag}; &gt;+use gecko_bindings::structs::nsChangeHint; &gt;+use gecko_bindings::structs::nsIDocument_DocumentTheme as DocumentTheme; &gt;+use gecko_bindings::structs::nsRestyleHint; &gt;+use gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel; &gt; use gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT; &gt; use gecko_bindings::structs::ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO; &gt; use gecko_bindings::structs::ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO; &gt; use gecko_bindings::structs::ELEMENT_HAS_SNAPSHOT; &gt;-use gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel; &gt; use gecko_bindings::structs::NODE_DESCENDANTS_NEED_FRAMES; &gt; use gecko_bindings::structs::NODE_NEEDS_FRAME; &gt;-use gecko_bindings::structs::nsChangeHint; &gt;-use gecko_bindings::structs::nsIDocument_DocumentTheme as DocumentTheme; &gt;-use gecko_bindings::structs::nsRestyleHint; &gt;+use gecko_bindings::structs::{nsAtom, nsIContent, nsINode_BooleanFlag}; &gt;+use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode, RawGeckoXBLBinding}; &gt; use gecko_bindings::sugar::ownership::{HasArcFFI, HasSimpleFFI}; &gt; use hash::FxHashMap; &gt; use logical_geometry::WritingMode; &gt; use media_queries::Device; &gt;-use properties::{ComputedValues, LonghandId}; &gt;-use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock}; &gt; use properties::animated_properties::{AnimationValue, AnimationValueMap}; &gt; use properties::style_structs::Font; &gt;+use properties::{ComputedValues, LonghandId}; &gt;+use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock}; &gt; use rule_tree::CascadeLevel as ServoCascadeLevel; &gt; use selector_parser::{AttrValue, Direction, PseudoClassStringArg}; &gt;-use selectors::{Element, OpaqueElement}; &gt; use selectors::attr::{AttrSelectorOperation, AttrSelectorOperator}; &gt; use selectors::attr::{CaseSensitivity, NamespaceConstraint}; &gt;-use selectors::matching::{ElementSelectorFlags, MatchingContext}; &gt; use selectors::matching::VisitedHandlingMode; &gt;+use selectors::matching::{ElementSelectorFlags, MatchingContext}; &gt; use selectors::sink::Push; &gt;+use selectors::{Element, OpaqueElement}; &gt; use servo_arc::{Arc, ArcBorrow, RawOffsetArc}; &gt; use shared_lock::Locked; &gt; use std::cell::RefCell; &gt; use std::fmt; &gt; use std::hash::{Hash, Hasher}; &gt; use std::mem; &gt; use std::ptr; &gt; use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace}; &gt; use stylist::CascadeData; &gt;- &gt;+use CaseSensitivityExt; &gt; &gt; #[inline] &gt; fn elements_with_id&lt;'a, 'le&gt;( &gt; array: *const structs::nsTArray&lt;*mut RawGeckoElement&gt;, &gt; ) -&gt; &amp;'a [GeckoElement&lt;'le&gt;] { &gt; unsafe { &gt; if array.is_null() { &gt; return &amp;[]; &gt;@@ -173,23 +174,22 @@ impl&lt;'lr&gt; TShadowRoot for GeckoShadowRoot&lt;'lr&gt; { &gt; { &gt; debug_assert!(!self.0.mServoStyles.mPtr.is_null()); &gt; &gt; let author_styles = unsafe { &gt; &amp;*(self.0.mServoStyles.mPtr as *const structs::RawServoAuthorStyles &gt; as *const bindings::RawServoAuthorStyles) &gt; }; &gt; &gt;- &gt; let author_styles = AuthorStyles::&lt;GeckoStyleSheet&gt;::from_ffi(author_styles); &gt; &gt; debug_assert!( &gt;- author_styles.quirks_mode == self.as_node().owner_doc().quirks_mode() || &gt;- author_styles.stylesheets.is_empty() || &gt;- author_styles.stylesheets.dirty() &gt;+ author_styles.quirks_mode == self.as_node().owner_doc().quirks_mode() &gt;+ || author_styles.stylesheets.is_empty() &gt;+ || author_styles.stylesheets.dirty() &gt; ); &gt; &gt; &amp;author_styles.data &gt; } &gt; &gt; #[inline] &gt; fn elements_with_id&lt;'a&gt;(&amp;self, id: &amp;Atom) -&gt; Result&lt;&amp;'a [GeckoElement&lt;'lr&gt;], ()&gt; &gt; where &gt;@@ -302,18 +302,18 @@ impl&lt;'ln&gt; GeckoNode&lt;'ln&gt; { &gt; use gecko_bindings::structs::*; &gt; let flags = self.flags(); &gt; if flags &amp; (NODE_MAY_BE_IN_BINDING_MNGR as u32 | NODE_IS_IN_SHADOW_TREE as u32) != 0 { &gt; return false; &gt; } &gt; &gt; let parent = unsafe { self.0.mParent.as_ref() }.map(GeckoNode); &gt; let parent_el = parent.and_then(|p| p.as_element()); &gt;- if flags &amp; (NODE_IS_NATIVE_ANONYMOUS_ROOT as u32) != 0 &amp;&amp; &gt;- parent_el.map_or(false, |el| el.is_root()) &gt;+ if flags &amp; (NODE_IS_NATIVE_ANONYMOUS_ROOT as u32) != 0 &gt;+ &amp;&amp; parent_el.map_or(false, |el| el.is_root()) &gt; { &gt; return false; &gt; } &gt; &gt; if let Some(parent) = parent_el { &gt; if parent.shadow_root().is_some() || parent.xbl_binding().is_some() { &gt; return false; &gt; } &gt;@@ -371,17 +371,18 @@ impl&lt;'ln&gt; TNode for GeckoNode&lt;'ln&gt; { &gt; fn parent_node(&amp;self) -&gt; Option&lt;Self&gt; { &gt; unsafe { self.0.mParent.as_ref().map(GeckoNode) } &gt; } &gt; &gt; #[inline] &gt; fn first_child(&amp;self) -&gt; Option&lt;Self&gt; { &gt; unsafe { &gt; self.0 &gt;- .mFirstChild.raw::&lt;nsIContent&gt;() &gt;+ .mFirstChild &gt;+ .raw::&lt;nsIContent&gt;() &gt; .as_ref() &gt; .map(GeckoNode::from_content) &gt; } &gt; } &gt; &gt; #[inline] &gt; fn last_child(&amp;self) -&gt; Option&lt;Self&gt; { &gt; unsafe { Gecko_GetLastChild(self.0).map(GeckoNode) } &gt;@@ -391,17 +392,18 @@ impl&lt;'ln&gt; TNode for GeckoNode&lt;'ln&gt; { &gt; fn prev_sibling(&amp;self) -&gt; Option&lt;Self&gt; { &gt; unsafe { Gecko_GetPreviousSibling(self.0).map(GeckoNode) } &gt; } &gt; &gt; #[inline] &gt; fn next_sibling(&amp;self) -&gt; Option&lt;Self&gt; { &gt; unsafe { &gt; self.0 &gt;- .mNextSibling.raw::&lt;nsIContent&gt;() &gt;+ .mNextSibling &gt;+ .raw::&lt;nsIContent&gt;() &gt; .as_ref() &gt; .map(GeckoNode::from_content) &gt; } &gt; } &gt; &gt; #[inline] &gt; fn owner_doc(&amp;self) -&gt; Self::ConcreteDocument { &gt; debug_assert!(!self.node_info().mDocument.is_null()); &gt;@@ -493,17 +495,17 @@ impl&lt;'a&gt; Drop for GeckoChildrenIterator&lt;'a&gt; { &gt; impl&lt;'a&gt; Iterator for GeckoChildrenIterator&lt;'a&gt; { &gt; type Item = GeckoNode&lt;'a&gt;; &gt; fn next(&amp;mut self) -&gt; Option&lt;GeckoNode&lt;'a&gt;&gt; { &gt; match *self { &gt; GeckoChildrenIterator::Current(curr) =&gt; { &gt; let next = curr.and_then(|node| node.next_sibling()); &gt; *self = GeckoChildrenIterator::Current(next); &gt; curr &gt;- }, &gt;+ } &gt; GeckoChildrenIterator::GeckoIterator(ref mut it) =&gt; unsafe { &gt; // We do this unsafe lengthening of the lifetime here because &gt; // structs::StyleChildrenIterator is actually StyleChildrenIterator&lt;'a&gt;, &gt; // however we can't express this easily with bindgen, and it would &gt; // introduce functions with two input lifetimes into bindgen, &gt; // which would be out of scope for elision. &gt; Gecko_GetNextStyleChild(&amp;mut *(it as *mut _)).map(GeckoNode) &gt; }, &gt;@@ -596,17 +598,17 @@ impl&lt;'le&gt; GeckoElement&lt;'le&gt; { &gt; fn get_class_attr(&amp;self) -&gt; Option&lt;&amp;structs::nsAttrValue&gt; { &gt; if !self.may_have_class() { &gt; return None; &gt; } &gt; &gt; if self.is_svg_element() { &gt; let svg_class = unsafe { bindings::Gecko_GetSVGAnimatedClass(self.0).as_ref() }; &gt; if let Some(c) = svg_class { &gt;- return Some(c) &gt;+ return Some(c); &gt; } &gt; } &gt; &gt; snapshot_helpers::find_attr(self.attrs(), &amp;atom!("class")) &gt; } &gt; &gt; #[inline] &gt; fn closest_anon_subtree_root_parent(&amp;self) -&gt; Option&lt;Self&gt; { &gt;@@ -666,20 +668,19 @@ impl&lt;'le&gt; GeckoElement&lt;'le&gt; { &gt; unsafe { slots.as_ref() } &gt; } &gt; &gt; /// Returns a reference to the extended DOM slots for this Element. &gt; #[inline] &gt; fn extended_slots(&amp;self) -&gt; Option&lt;&amp;structs::FragmentOrElement_nsExtendedDOMSlots&gt; { &gt; self.dom_slots().and_then(|s| unsafe { &gt; // For the bit usage, see nsContentSlots::GetExtendedSlots. &gt;- let e_slots = s._base.mExtendedSlots &amp; &gt;- !structs::nsIContent_nsContentSlots_sNonOwningExtendedSlotsFlag; &gt;- (e_slots as *const structs::FragmentOrElement_nsExtendedDOMSlots) &gt;- .as_ref() &gt;+ let e_slots = s._base.mExtendedSlots &gt;+ &amp; !structs::nsIContent_nsContentSlots_sNonOwningExtendedSlotsFlag; &gt;+ (e_slots as *const structs::FragmentOrElement_nsExtendedDOMSlots).as_ref() &gt; }) &gt; } &gt; &gt; #[inline] &gt; fn may_be_in_binding_manager(&amp;self) -&gt; bool { &gt; self.flags() &amp; (structs::NODE_MAY_BE_IN_BINDING_MNGR as u32) != 0 &gt; } &gt; &gt;@@ -715,45 +716,46 @@ impl&lt;'le&gt; GeckoElement&lt;'le&gt; { &gt; // rather than in slots. So just get it through FFI for now. &gt; unsafe { bindings::Gecko_GetBindingParent(self.0).map(GeckoElement) } &gt; } else { &gt; let binding_parent = unsafe { self.non_xul_xbl_binding_parent_raw_content().as_ref() } &gt; .map(GeckoNode::from_content) &gt; .and_then(|n| n.as_element()); &gt; &gt; debug_assert!( &gt;- binding_parent == unsafe { &gt;- bindings::Gecko_GetBindingParent(self.0).map(GeckoElement) &gt;- } &gt;+ binding_parent &gt;+ == unsafe { bindings::Gecko_GetBindingParent(self.0).map(GeckoElement) } &gt; ); &gt; binding_parent &gt; } &gt; } &gt; &gt; #[inline] &gt; fn non_xul_xbl_binding_parent_raw_content(&amp;self) -&gt; *mut nsIContent { &gt; debug_assert!(!self.is_xul_element()); &gt;- self.extended_slots() &gt;- .map_or(ptr::null_mut(), |slots| slots._base.mBindingParent.raw::&lt;nsIContent&gt;()) &gt;+ self.extended_slots().map_or(ptr::null_mut(), |slots| { &gt;+ slots._base.mBindingParent.raw::&lt;nsIContent&gt;() &gt;+ }) &gt; } &gt; &gt; #[inline] &gt; fn namespace_id(&amp;self) -&gt; i32 { &gt; self.as_node().node_info().mInner.mNamespaceID &gt; } &gt; &gt; #[inline] &gt; fn has_id(&amp;self) -&gt; bool { &gt; self.as_node() &gt; .get_bool_flag(nsINode_BooleanFlag::ElementHasID) &gt; } &gt; &gt; #[inline] &gt; fn state_internal(&amp;self) -&gt; u64 { &gt;- if !self.as_node() &gt;+ if !self &gt;+ .as_node() &gt; .get_bool_flag(nsINode_BooleanFlag::ElementHasLockedStyleStates) &gt; { &gt; return self.0.mState.mStates; &gt; } &gt; unsafe { Gecko_ElementState(self.0) } &gt; } &gt; &gt; #[inline] &gt;@@ -822,17 +824,17 @@ impl&lt;'le&gt; GeckoElement&lt;'le&gt; { &gt; "Animation restyle hints should not appear with non-animation restyle hints" &gt; ); &gt; &gt; let mut data = match self.mutate_data() { &gt; Some(d) =&gt; d, &gt; None =&gt; { &gt; debug!("(Element not styled, discarding hints)"); &gt; return; &gt;- }, &gt;+ } &gt; }; &gt; &gt; debug_assert!(data.has_styles(), "how?"); &gt; &gt; // Propagate the bit up the chain. &gt; if restyle_hint.has_animation_hint() { &gt; bindings::Gecko_NoteAnimationOnlyDirtyElement(self.0); &gt; } else { &gt;@@ -874,19 +876,17 @@ impl&lt;'le&gt; GeckoElement&lt;'le&gt; { &gt; &gt; /// Returns true if this node is the shadow root of an use-element shadow tree. &gt; #[inline] &gt; fn is_root_of_use_element_shadow_tree(&amp;self) -&gt; bool { &gt; if !self.as_node().is_in_shadow_tree() { &gt; return false; &gt; } &gt; match self.containing_shadow_host() { &gt;- Some(e) =&gt; { &gt;- e.is_svg_element() &amp;&amp; e.local_name() == &amp;*local_name!("use") &gt;- }, &gt;+ Some(e) =&gt; e.is_svg_element() &amp;&amp; e.local_name() == &amp;*local_name!("use"), &gt; None =&gt; false, &gt; } &gt; } &gt; &gt; fn css_transitions_info(&amp;self) -&gt; FxHashMap&lt;LonghandId, Arc&lt;AnimationValue&gt;&gt; { &gt; use gecko_bindings::bindings::Gecko_ElementTransitions_EndValueAt; &gt; use gecko_bindings::bindings::Gecko_ElementTransitions_Length; &gt; &gt;@@ -930,23 +930,22 @@ impl&lt;'le&gt; GeckoElement&lt;'le&gt; { &gt; return ***existing != after_value; &gt; } &gt; &gt; let from = AnimationValue::from_computed_values(longhand_id, before_change_style); &gt; let to = AnimationValue::from_computed_values(longhand_id, after_change_style); &gt; &gt; debug_assert_eq!(to.is_some(), from.is_some()); &gt; &gt;- combined_duration &gt; 0.0f32 &amp;&amp; from != to &amp;&amp; &gt;- from.unwrap() &gt;- .animate( &gt;- to.as_ref().unwrap(), &gt;- Procedure::Interpolate { progress: 0.5 }, &gt;- ) &gt;- .is_ok() &gt;+ combined_duration &gt; 0.0f32 &amp;&amp; from != to &amp;&amp; from &gt;+ .unwrap() &gt;+ .animate( &gt;+ to.as_ref().unwrap(), &gt;+ Procedure::Interpolate { progress: 0.5 }, &gt;+ ).is_ok() &gt; } &gt; } &gt; &gt; /// Converts flags from the layout used by rust-selectors to the layout used &gt; /// by Gecko. We could align these and then do this without conditionals, but &gt; /// it's probably not worth the trouble. &gt; fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -&gt; u32 { &gt; use gecko_bindings::structs::*; &gt;@@ -976,17 +975,19 @@ fn get_animation_rule( &gt; &gt; // There's a very rough correlation between the number of effects &gt; // (animations) on an element and the number of properties it is likely to &gt; // animate, so we use that as an initial guess for the size of the &gt; // AnimationValueMap in order to reduce the number of re-allocations needed. &gt; let effect_count = unsafe { Gecko_GetAnimationEffectCount(element.0) }; &gt; // Also, we should try to reuse the PDB, to avoid creating extra rule nodes. &gt; let mut animation_values = AnimationValueMap::with_capacity_and_hasher( &gt;- effect_count.min(ANIMATABLE_PROPERTY_COUNT), Default::default()); &gt;+ effect_count.min(ANIMATABLE_PROPERTY_COUNT), &gt;+ Default::default(), &gt;+ ); &gt; if unsafe { &gt; Gecko_GetAnimationRule( &gt; element.0, &gt; cascade_level, &gt; AnimationValueMap::as_ffi_mut(&amp;mut animation_values), &gt; ) &gt; } { &gt; let shared_lock = &amp;GLOBAL_STYLE_DATA.shared_lock; &gt;@@ -1080,30 +1081,34 @@ impl structs::FontSizePrefs { &gt; &gt; impl&lt;'le&gt; TElement for GeckoElement&lt;'le&gt; { &gt; type ConcreteNode = GeckoNode&lt;'le&gt;; &gt; type FontMetricsProvider = GeckoFontMetricsProvider; &gt; type TraversalChildrenIterator = GeckoChildrenIterator&lt;'le&gt;; &gt; &gt; fn inheritance_parent(&amp;self) -&gt; Option&lt;Self&gt; { &gt; if self.implemented_pseudo_element().is_some() { &gt;- return self.pseudo_element_originating_element() &gt;+ return self.pseudo_element_originating_element(); &gt; } &gt; &gt;- self.as_node().flattened_tree_parent().and_then(|n| n.as_element()) &gt;+ self.as_node() &gt;+ .flattened_tree_parent() &gt;+ .and_then(|n| n.as_element()) &gt; } &gt; &gt; fn traversal_children(&amp;self) -&gt; LayoutIterator&lt;GeckoChildrenIterator&lt;'le&gt;&gt; { &gt; // This condition is similar to the check that &gt; // StyleChildrenIterator::IsNeeded does, except that it might return &gt; // true if we used to (but no longer) have anonymous content from &gt; // ::before/::after, XBL bindings, or nsIAnonymousContentCreators. &gt;- if self.is_in_anonymous_subtree() || self.has_xbl_binding_with_content() || &gt;- self.is_html_slot_element() || self.shadow_root().is_some() || &gt;- self.may_have_anonymous_children() &gt;+ if self.is_in_anonymous_subtree() &gt;+ || self.has_xbl_binding_with_content() &gt;+ || self.is_html_slot_element() &gt;+ || self.shadow_root().is_some() &gt;+ || self.may_have_anonymous_children() &gt; { &gt; unsafe { &gt; let mut iter: structs::StyleChildrenIterator = ::std::mem::zeroed(); &gt; bindings::Gecko_ConstructStyleChildrenIterator(self.0, &amp;mut iter); &gt; return LayoutIterator(GeckoChildrenIterator::GeckoIterator(iter)); &gt; } &gt; } &gt; &gt;@@ -1153,27 +1158,26 @@ impl&lt;'le&gt; TElement for GeckoElement&lt;'le&gt; { &gt; } &gt; &gt; // FIXME(emilio): Workaround a bindgen bug on Android that causes &gt; // mAssignedNodes to be at the wrong offset. See bug 1466406. &gt; // &gt; // Bug 1466580 tracks running the Android layout tests on automation. &gt; // &gt; // The actual bindgen bug still needs reduction. &gt;- let assigned_nodes: &amp;[structs::RefPtr&lt;structs::nsINode&gt;] = &gt;- if !cfg!(target_os = "android") { &gt;- debug_assert_eq!( &gt;- unsafe { bindings::Gecko_GetAssignedNodes(self.0) }, &gt;- &amp;slot.mAssignedNodes as *const _, &gt;- ); &gt;+ let assigned_nodes: &amp;[structs::RefPtr&lt;structs::nsINode&gt;] = if !cfg!(target_os = "android") { &gt;+ debug_assert_eq!( &gt;+ unsafe { bindings::Gecko_GetAssignedNodes(self.0) }, &gt;+ &amp;slot.mAssignedNodes as *const _, &gt;+ ); &gt; &gt;- &amp;*slot.mAssignedNodes &gt;- } else { &gt;- unsafe { &amp;**bindings::Gecko_GetAssignedNodes(self.0) } &gt;- }; &gt;+ &amp;*slot.mAssignedNodes &gt;+ } else { &gt;+ unsafe { &amp;**bindings::Gecko_GetAssignedNodes(self.0) } &gt;+ }; &gt; &gt; debug_assert_eq!( &gt; mem::size_of::&lt;structs::RefPtr&lt;structs::nsINode&gt;&gt;(), &gt; mem::size_of::&lt;Self::ConcreteNode&gt;(), &gt; "Bad cast!" &gt; ); &gt; &gt; unsafe { mem::transmute(assigned_nodes) } &gt;@@ -1235,21 +1239,20 @@ impl&lt;'le&gt; TElement for GeckoElement&lt;'le&gt; { &gt; } &gt; &gt; #[inline] &gt; fn as_node(&amp;self) -&gt; Self::ConcreteNode { &gt; unsafe { GeckoNode(&amp;*(self.0 as *const _ as *const RawGeckoNode)) } &gt; } &gt; &gt; fn owner_doc_matches_for_testing(&amp;self, device: &amp;Device) -&gt; bool { &gt;- self.as_node().owner_doc().0 as *const structs::nsIDocument == &gt;- device &gt;- .pres_context() &gt;- .mDocument &gt;- .raw::&lt;structs::nsIDocument&gt;() &gt;+ self.as_node().owner_doc().0 as *const structs::nsIDocument == device &gt;+ .pres_context() &gt;+ .mDocument &gt;+ .raw::&lt;structs::nsIDocument&gt;() &gt; } &gt; &gt; fn style_attribute(&amp;self) -&gt; Option&lt;ArcBorrow&lt;Locked&lt;PropertyDeclarationBlock&gt;&gt;&gt; { &gt; if !self.may_have_style_attribute() { &gt; return None; &gt; } &gt; &gt; let declarations = unsafe { Gecko_GetStyleAttrDeclarationBlock(self.0) }; &gt;@@ -1363,28 +1366,29 @@ impl&lt;'le&gt; TElement for GeckoElement&lt;'le&gt; { &gt; } &gt; &gt; unsafe fn unset_animation_only_dirty_descendants(&amp;self) { &gt; self.unset_flags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32) &gt; } &gt; &gt; unsafe fn clear_descendant_bits(&amp;self) { &gt; self.unset_flags( &gt;- ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32 | &gt;- ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 | &gt;- NODE_DESCENDANTS_NEED_FRAMES as u32, &gt;+ ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32 &gt;+ | ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 &gt;+ | NODE_DESCENDANTS_NEED_FRAMES as u32, &gt; ) &gt; } &gt; &gt; #[inline] &gt; unsafe fn clear_dirty_bits(&amp;self) { &gt; self.unset_flags( &gt;- ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32 | &gt;- ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 | &gt;- NODE_DESCENDANTS_NEED_FRAMES as u32 | NODE_NEEDS_FRAME as u32, &gt;+ ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32 &gt;+ | ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32 &gt;+ | NODE_DESCENDANTS_NEED_FRAMES as u32 &gt;+ | NODE_NEEDS_FRAME as u32, &gt; ) &gt; } &gt; &gt; fn is_visited_link(&amp;self) -&gt; bool { &gt; self.state().intersects(ElementState::IN_VISITED_STATE) &gt; } &gt; &gt; /// This logic is duplicated in Gecko's nsINode::IsInNativeAnonymousSubtree. &gt;@@ -1434,18 +1438,20 @@ impl&lt;'le&gt; TElement for GeckoElement&lt;'le&gt; { &gt; self.0.mServoData.set(ptr); &gt; } &gt; self.mutate_data().unwrap() &gt; } &gt; &gt; unsafe fn clear_data(&amp;self) { &gt; let ptr = self.0.mServoData.get(); &gt; self.unset_flags( &gt;- ELEMENT_HAS_SNAPSHOT as u32 | ELEMENT_HANDLED_SNAPSHOT as u32 | &gt;- structs::Element_kAllServoDescendantBits | NODE_NEEDS_FRAME as u32, &gt;+ ELEMENT_HAS_SNAPSHOT as u32 &gt;+ | ELEMENT_HANDLED_SNAPSHOT as u32 &gt;+ | structs::Element_kAllServoDescendantBits &gt;+ | NODE_NEEDS_FRAME as u32, &gt; ); &gt; if !ptr.is_null() { &gt; debug!("Dropping ElementData for {:?}", self); &gt; let data = Box::from_raw(self.0.mServoData.get()); &gt; self.0.mServoData.set(ptr::null_mut()); &gt; &gt; // Perform a mutable borrow of the data in debug builds. This &gt; // serves as an assertion that there are no outstanding borrows &gt;@@ -1645,60 +1651,58 @@ impl&lt;'le&gt; TElement for GeckoElement&lt;'le&gt; { &gt; ); &gt; &gt; let after_change_box_style = after_change_style.get_box(); &gt; let transitions_count = after_change_box_style.transition_property_count(); &gt; let existing_transitions = self.css_transitions_info(); &gt; &gt; // Check if this property is none, custom or unknown. &gt; let is_none_or_custom_property = |property: nsCSSPropertyID| -&gt; bool { &gt;- return property == nsCSSPropertyID::eCSSPropertyExtra_no_properties || &gt;- property == nsCSSPropertyID::eCSSPropertyExtra_variable || &gt;- property == nsCSSPropertyID::eCSSProperty_UNKNOWN; &gt;+ return property == nsCSSPropertyID::eCSSPropertyExtra_no_properties &gt;+ || property == nsCSSPropertyID::eCSSPropertyExtra_variable &gt;+ || property == nsCSSPropertyID::eCSSProperty_UNKNOWN; &gt; }; &gt; &gt; let mut transitions_to_keep = LonghandIdSet::new(); &gt; &gt; for i in 0..transitions_count { &gt; let property = after_change_box_style.transition_nscsspropertyid_at(i); &gt; let combined_duration = after_change_box_style.transition_combined_duration_at(i); &gt; &gt; // We don't need to update transition for none/custom properties. &gt; if is_none_or_custom_property(property) { &gt; continue; &gt; } &gt; &gt; let transition_property: TransitionProperty = property.into(); &gt; &gt; let mut property_check_helper = |property: LonghandId| -&gt; bool { &gt;- let property = &gt;- property.to_physical(after_change_style.writing_mode); &gt;+ let property = property.to_physical(after_change_style.writing_mode); &gt; transitions_to_keep.insert(property); &gt; self.needs_transitions_update_per_property( &gt; property, &gt; combined_duration, &gt; before_change_style, &gt; after_change_style, &gt; &amp;existing_transitions, &gt; ) &gt; }; &gt; &gt; match transition_property { &gt;- TransitionProperty::Custom(..) | &gt;- TransitionProperty::Unsupported(..) =&gt; {}, &gt;+ TransitionProperty::Custom(..) | TransitionProperty::Unsupported(..) =&gt; {} &gt; TransitionProperty::Shorthand(ref shorthand) =&gt; { &gt; if shorthand.longhands().any(property_check_helper) { &gt; return true; &gt; } &gt;- }, &gt;+ } &gt; TransitionProperty::Longhand(longhand_id) =&gt; { &gt; if property_check_helper(longhand_id) { &gt; return true; &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; // Check if we have to cancel the running transition because this is not &gt; // a matching transition-property value. &gt; existing_transitions &gt; .keys() &gt; .any(|property| !transitions_to_keep.contains(*property)) &gt;@@ -1803,18 +1807,18 @@ impl&lt;'le&gt; TElement for GeckoElement&lt;'le&gt; { &gt; }; &gt; }; &gt; &gt; let ns = self.namespace_id(); &gt; // &lt;th&gt; elements get a default MozCenterOrInherit which may get overridden &gt; if ns == structs::kNameSpaceID_XHTML as i32 { &gt; if self.local_name().as_ptr() == atom!("th").as_ptr() { &gt; hints.push(TH_RULE.clone()); &gt;- } else if self.local_name().as_ptr() == atom!("table").as_ptr() &amp;&amp; &gt;- self.as_node().owner_doc().quirks_mode() == QuirksMode::Quirks &gt;+ } else if self.local_name().as_ptr() == atom!("table").as_ptr() &gt;+ &amp;&amp; self.as_node().owner_doc().quirks_mode() == QuirksMode::Quirks &gt; { &gt; hints.push(TABLE_COLOR_RULE.clone()); &gt; } &gt; } &gt; if ns == structs::kNameSpaceID_SVG as i32 { &gt; if self.local_name().as_ptr() == atom!("text").as_ptr() { &gt; hints.push(SVG_TEXT_DISABLE_ZOOM_RULE.clone()); &gt; } &gt;@@ -1843,34 +1847,35 @@ impl&lt;'le&gt; TElement for GeckoElement&lt;'le&gt; { &gt; // Unvisited vs. visited styles are computed up-front based on the &gt; // visited mode (not the element's actual state). &gt; let declarations = match visited_handling { &gt; VisitedHandlingMode::AllLinksVisitedAndUnvisited =&gt; { &gt; unreachable!( &gt; "We should never try to selector match with \ &gt; AllLinksVisitedAndUnvisited" &gt; ); &gt;- }, &gt;+ } &gt; VisitedHandlingMode::AllLinksUnvisited =&gt; unsafe { &gt; Gecko_GetUnvisitedLinkAttrDeclarationBlock(self.0) &gt; }, &gt; VisitedHandlingMode::RelevantLinkVisited =&gt; unsafe { &gt; Gecko_GetVisitedLinkAttrDeclarationBlock(self.0) &gt; }, &gt; }; &gt; let declarations: Option&lt;&amp;RawOffsetArc&lt;Locked&lt;PropertyDeclarationBlock&gt;&gt;&gt; = &gt; declarations.and_then(|s| s.as_arc_opt()); &gt; if let Some(decl) = declarations { &gt; hints.push(ApplicableDeclarationBlock::from_declarations( &gt; decl.clone_arc(), &gt; ServoCascadeLevel::PresHints, &gt; )); &gt; } &gt; &gt;- let active = self.state() &gt;+ let active = self &gt;+ .state() &gt; .intersects(NonTSPseudoClass::Active.state_flag()); &gt; if active { &gt; let declarations = unsafe { Gecko_GetActiveLinkAttrDeclarationBlock(self.0) }; &gt; let declarations: Option&lt; &gt; &amp;RawOffsetArc&lt;Locked&lt;PropertyDeclarationBlock&gt;&gt;, &gt; &gt; = declarations.and_then(|s| s.as_arc_opt()); &gt; if let Some(decl) = declarations { &gt; hints.push(ApplicableDeclarationBlock::from_declarations( &gt;@@ -2008,17 +2013,17 @@ impl&lt;'le&gt; ::selectors::Element for GeckoElement&lt;'le&gt; { &gt; ns: &amp;NamespaceConstraint&lt;&amp;Namespace&gt;, &gt; local_name: &amp;Atom, &gt; operation: &amp;AttrSelectorOperation&lt;&amp;Atom&gt;, &gt; ) -&gt; bool { &gt; unsafe { &gt; match *operation { &gt; AttrSelectorOperation::Exists =&gt; { &gt; bindings::Gecko_HasAttr(self.0, ns.atom_or_null(), local_name.as_ptr()) &gt;- }, &gt;+ } &gt; AttrSelectorOperation::WithValue { &gt; operator, &gt; case_sensitivity, &gt; expected_value, &gt; } =&gt; { &gt; let ignore_case = match case_sensitivity { &gt; CaseSensitivity::CaseSensitive =&gt; false, &gt; CaseSensitivity::AsciiCaseInsensitive =&gt; true, &gt;@@ -2063,37 +2068,45 @@ impl&lt;'le&gt; ::selectors::Element for GeckoElement&lt;'le&gt; { &gt; AttrSelectorOperator::Substring =&gt; bindings::Gecko_AttrHasSubstring( &gt; self.0, &gt; ns.atom_or_null(), &gt; local_name.as_ptr(), &gt; expected_value.as_ptr(), &gt; ignore_case, &gt; ), &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; #[inline] &gt; fn is_root(&amp;self) -&gt; bool { &gt;- if self.as_node().get_bool_flag(nsINode_BooleanFlag::ParentIsContent) { &gt;+ if self &gt;+ .as_node() &gt;+ .get_bool_flag(nsINode_BooleanFlag::ParentIsContent) &gt;+ { &gt; return false; &gt; } &gt; &gt; if !self.as_node().is_in_document() { &gt; return false; &gt; } &gt; &gt;- debug_assert!(self.as_node().parent_node().map_or(false, |p| p.is_document())); &gt;+ debug_assert!( &gt;+ self.as_node() &gt;+ .parent_node() &gt;+ .map_or(false, |p| p.is_document()) &gt;+ ); &gt; unsafe { bindings::Gecko_IsRootElement(self.0) } &gt; } &gt; &gt; fn is_empty(&amp;self) -&gt; bool { &gt;- !self.as_node() &gt;+ !self &gt;+ .as_node() &gt; .dom_children() &gt; .any(|child| unsafe { Gecko_IsSignificantChild(child.0, true) }) &gt; } &gt; &gt; #[inline] &gt; fn local_name(&amp;self) -&gt; &amp;WeakAtom { &gt; unsafe { WeakAtom::new(self.as_node().node_info().mInner.mName) } &gt; } &gt;@@ -2112,128 +2125,129 @@ impl&lt;'le&gt; ::selectors::Element for GeckoElement&lt;'le&gt; { &gt; context: &amp;mut MatchingContext&lt;Self::Impl&gt;, &gt; flags_setter: &amp;mut F, &gt; ) -&gt; bool &gt; where &gt; F: FnMut(&amp;Self, ElementSelectorFlags), &gt; { &gt; use selectors::matching::*; &gt; match *pseudo_class { &gt;- NonTSPseudoClass::Defined | &gt;- NonTSPseudoClass::Focus | &gt;- NonTSPseudoClass::Enabled | &gt;- NonTSPseudoClass::Disabled | &gt;- NonTSPseudoClass::Checked | &gt;- NonTSPseudoClass::Fullscreen | &gt;- NonTSPseudoClass::MozFullScreen | &gt;- NonTSPseudoClass::Indeterminate | &gt;- NonTSPseudoClass::PlaceholderShown | &gt;- NonTSPseudoClass::Target | &gt;- NonTSPseudoClass::Valid | &gt;- NonTSPseudoClass::Invalid | &gt;- NonTSPseudoClass::MozUIValid | &gt;- NonTSPseudoClass::MozBroken | &gt;- NonTSPseudoClass::MozUserDisabled | &gt;- NonTSPseudoClass::MozSuppressed | &gt;- NonTSPseudoClass::MozLoading | &gt;- NonTSPseudoClass::MozHandlerBlocked | &gt;- NonTSPseudoClass::MozHandlerDisabled | &gt;- NonTSPseudoClass::MozHandlerCrashed | &gt;- NonTSPseudoClass::Required | &gt;- NonTSPseudoClass::Optional | &gt;- NonTSPseudoClass::MozReadOnly | &gt;- NonTSPseudoClass::MozReadWrite | &gt;- NonTSPseudoClass::FocusWithin | &gt;- NonTSPseudoClass::MozDragOver | &gt;- NonTSPseudoClass::MozDevtoolsHighlighted | &gt;- NonTSPseudoClass::MozStyleeditorTransitioning | &gt;- NonTSPseudoClass::MozFocusRing | &gt;- NonTSPseudoClass::MozHandlerClickToPlay | &gt;- NonTSPseudoClass::MozHandlerVulnerableUpdatable | &gt;- NonTSPseudoClass::MozHandlerVulnerableNoUpdate | &gt;- NonTSPseudoClass::MozMathIncrementScriptLevel | &gt;- NonTSPseudoClass::InRange | &gt;- NonTSPseudoClass::OutOfRange | &gt;- NonTSPseudoClass::Default | &gt;- NonTSPseudoClass::MozSubmitInvalid | &gt;- NonTSPseudoClass::MozUIInvalid | &gt;- NonTSPseudoClass::MozMeterOptimum | &gt;- NonTSPseudoClass::MozMeterSubOptimum | &gt;- NonTSPseudoClass::MozMeterSubSubOptimum | &gt;- NonTSPseudoClass::MozHasDirAttr | &gt;- NonTSPseudoClass::MozDirAttrLTR | &gt;- NonTSPseudoClass::MozDirAttrRTL | &gt;- NonTSPseudoClass::MozDirAttrLikeAuto | &gt;- NonTSPseudoClass::MozAutofill | &gt;- NonTSPseudoClass::Active | &gt;- NonTSPseudoClass::Hover | &gt;- NonTSPseudoClass::MozAutofillPreview =&gt; { &gt;+ NonTSPseudoClass::Defined &gt;+ | NonTSPseudoClass::Focus &gt;+ | NonTSPseudoClass::Enabled &gt;+ | NonTSPseudoClass::Disabled &gt;+ | NonTSPseudoClass::Checked &gt;+ | NonTSPseudoClass::Fullscreen &gt;+ | NonTSPseudoClass::MozFullScreen &gt;+ | NonTSPseudoClass::Indeterminate &gt;+ | NonTSPseudoClass::PlaceholderShown &gt;+ | NonTSPseudoClass::Target &gt;+ | NonTSPseudoClass::Valid &gt;+ | NonTSPseudoClass::Invalid &gt;+ | NonTSPseudoClass::MozUIValid &gt;+ | NonTSPseudoClass::MozBroken &gt;+ | NonTSPseudoClass::MozUserDisabled &gt;+ | NonTSPseudoClass::MozSuppressed &gt;+ | NonTSPseudoClass::MozLoading &gt;+ | NonTSPseudoClass::MozHandlerBlocked &gt;+ | NonTSPseudoClass::MozHandlerDisabled &gt;+ | NonTSPseudoClass::MozHandlerCrashed &gt;+ | NonTSPseudoClass::Required &gt;+ | NonTSPseudoClass::Optional &gt;+ | NonTSPseudoClass::MozReadOnly &gt;+ | NonTSPseudoClass::MozReadWrite &gt;+ | NonTSPseudoClass::FocusWithin &gt;+ | NonTSPseudoClass::MozDragOver &gt;+ | NonTSPseudoClass::MozDevtoolsHighlighted &gt;+ | NonTSPseudoClass::MozStyleeditorTransitioning &gt;+ | NonTSPseudoClass::MozFocusRing &gt;+ | NonTSPseudoClass::MozHandlerClickToPlay &gt;+ | NonTSPseudoClass::MozHandlerVulnerableUpdatable &gt;+ | NonTSPseudoClass::MozHandlerVulnerableNoUpdate &gt;+ | NonTSPseudoClass::MozMathIncrementScriptLevel &gt;+ | NonTSPseudoClass::InRange &gt;+ | NonTSPseudoClass::OutOfRange &gt;+ | NonTSPseudoClass::Default &gt;+ | NonTSPseudoClass::MozSubmitInvalid &gt;+ | NonTSPseudoClass::MozUIInvalid &gt;+ | NonTSPseudoClass::MozMeterOptimum &gt;+ | NonTSPseudoClass::MozMeterSubOptimum &gt;+ | NonTSPseudoClass::MozMeterSubSubOptimum &gt;+ | NonTSPseudoClass::MozHasDirAttr &gt;+ | NonTSPseudoClass::MozDirAttrLTR &gt;+ | NonTSPseudoClass::MozDirAttrRTL &gt;+ | NonTSPseudoClass::MozDirAttrLikeAuto &gt;+ | NonTSPseudoClass::MozAutofill &gt;+ | NonTSPseudoClass::Active &gt;+ | NonTSPseudoClass::Hover &gt;+ | NonTSPseudoClass::MozAutofillPreview =&gt; { &gt; self.state().intersects(pseudo_class.state_flag()) &gt;- }, &gt;+ } &gt; NonTSPseudoClass::AnyLink =&gt; self.is_link(), &gt; NonTSPseudoClass::Link =&gt; { &gt; self.is_link() &amp;&amp; context.visited_handling().matches_unvisited() &gt;- }, &gt;+ } &gt; NonTSPseudoClass::Visited =&gt; { &gt; self.is_link() &amp;&amp; context.visited_handling().matches_visited() &gt;- }, &gt;+ } &gt; NonTSPseudoClass::MozFirstNode =&gt; { &gt; flags_setter(self, ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR); &gt; let mut elem = self.as_node(); &gt; while let Some(prev) = elem.prev_sibling() { &gt; if prev.contains_non_whitespace_content() { &gt; return false; &gt; } &gt; elem = prev; &gt; } &gt; true &gt;- }, &gt;+ } &gt; NonTSPseudoClass::MozLastNode =&gt; { &gt; flags_setter(self, ElementSelectorFlags::HAS_EDGE_CHILD_SELECTOR); &gt; let mut elem = self.as_node(); &gt; while let Some(next) = elem.next_sibling() { &gt; if next.contains_non_whitespace_content() { &gt; return false; &gt; } &gt; elem = next; &gt; } &gt; true &gt;- }, &gt;+ } &gt; NonTSPseudoClass::MozOnlyWhitespace =&gt; { &gt; flags_setter(self, ElementSelectorFlags::HAS_EMPTY_SELECTOR); &gt;- if self.as_node() &gt;+ if self &gt;+ .as_node() &gt; .dom_children() &gt; .any(|c| c.contains_non_whitespace_content()) &gt; { &gt; return false; &gt; } &gt; true &gt;- }, &gt;+ } &gt; NonTSPseudoClass::MozNativeAnonymous =&gt; self.is_in_native_anonymous_subtree(), &gt; NonTSPseudoClass::MozUseShadowTreeRoot =&gt; self.is_root_of_use_element_shadow_tree(), &gt; NonTSPseudoClass::MozTableBorderNonzero =&gt; unsafe { &gt; bindings::Gecko_IsTableBorderNonzero(self.0) &gt; }, &gt; NonTSPseudoClass::MozBrowserFrame =&gt; unsafe { bindings::Gecko_IsBrowserFrame(self.0) }, &gt; NonTSPseudoClass::MozIsHTML =&gt; self.is_html_element_in_html_document(), &gt; NonTSPseudoClass::MozLWTheme =&gt; self.document_theme() != DocumentTheme::Doc_Theme_None, &gt; NonTSPseudoClass::MozLWThemeBrightText =&gt; { &gt; self.document_theme() == DocumentTheme::Doc_Theme_Bright &gt;- }, &gt;+ } &gt; NonTSPseudoClass::MozLWThemeDarkText =&gt; { &gt; self.document_theme() == DocumentTheme::Doc_Theme_Dark &gt;- }, &gt;+ } &gt; NonTSPseudoClass::MozWindowInactive =&gt; { &gt; let state_bit = DocumentState::NS_DOCUMENT_STATE_WINDOW_INACTIVE; &gt; if context.extra_data.document_state.intersects(state_bit) { &gt; return !context.in_negation(); &gt; } &gt; &gt; self.document_state().contains(state_bit) &gt;- }, &gt;+ } &gt; NonTSPseudoClass::MozPlaceholder =&gt; false, &gt; NonTSPseudoClass::MozAny(ref sels) =&gt; context.nest(|context| { &gt; sels.iter() &gt; .any(|s| matches_complex_selector(s.iter(), self, context, flags_setter)) &gt; }), &gt; NonTSPseudoClass::Lang(ref lang_arg) =&gt; self.match_element_lang(None, lang_arg), &gt; NonTSPseudoClass::MozLocaleDir(ref dir) =&gt; { &gt; let state_bit = DocumentState::NS_DOCUMENT_STATE_RTL_LOCALE; &gt;@@ -2245,17 +2259,17 @@ impl&lt;'le&gt; ::selectors::Element for GeckoElement&lt;'le&gt; { &gt; &gt; let doc_is_rtl = self.document_state().contains(state_bit); &gt; &gt; match **dir { &gt; Direction::Ltr =&gt; !doc_is_rtl, &gt; Direction::Rtl =&gt; doc_is_rtl, &gt; Direction::Other(..) =&gt; false, &gt; } &gt;- }, &gt;+ } &gt; NonTSPseudoClass::Dir(ref dir) =&gt; match **dir { &gt; Direction::Ltr =&gt; self.state().intersects(ElementState::IN_LTR_STATE), &gt; Direction::Rtl =&gt; self.state().intersects(ElementState::IN_RTL_STATE), &gt; Direction::Other(..) =&gt; false, &gt; }, &gt; } &gt; } &gt; &gt;diff --git a/servo/components/style/gecko_bindings/mod.rs b/servo/components/style/gecko_bindings/mod.rs &gt;index eb3f0d220bf5..166e2f66fd56 100644 &gt;--- a/servo/components/style/gecko_bindings/mod.rs &gt;+++ b/servo/components/style/gecko_bindings/mod.rs &gt;@@ -1,22 +1,33 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Gecko's C++ bindings, along with some rust helpers to ease its use. &gt; &gt;-#[allow(dead_code, improper_ctypes, non_camel_case_types, missing_docs)] &gt;+#[allow( &gt;+ dead_code, &gt;+ improper_ctypes, &gt;+ non_camel_case_types, &gt;+ missing_docs &gt;+)] &gt; pub mod bindings { &gt; include!(concat!(env!("OUT_DIR"), "/gecko/bindings.rs")); &gt; } &gt; &gt; // FIXME: We allow `improper_ctypes` (for now), because the lint doesn't allow &gt; // foreign structs to have `PhantomData`. We should remove this once the lint &gt; // ignores this case. &gt; &gt;-#[allow(dead_code, improper_ctypes, non_camel_case_types, non_snake_case, non_upper_case_globals, &gt;- missing_docs)] &gt;+#[allow( &gt;+ dead_code, &gt;+ improper_ctypes, &gt;+ non_camel_case_types, &gt;+ non_snake_case, &gt;+ non_upper_case_globals, &gt;+ missing_docs &gt;+)] &gt; pub mod structs { &gt; include!(concat!(env!("OUT_DIR"), "/gecko/structs.rs")); &gt; } &gt; &gt; pub mod sugar; &gt;diff --git a/servo/components/style/gecko_bindings/sugar/ns_css_shadow_array.rs b/servo/components/style/gecko_bindings/sugar/ns_css_shadow_array.rs &gt;index 8e445a837e62..f0050796c22c 100644 &gt;--- a/servo/components/style/gecko_bindings/sugar/ns_css_shadow_array.rs &gt;+++ b/servo/components/style/gecko_bindings/sugar/ns_css_shadow_array.rs &gt;@@ -2,19 +2,19 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Rust helpers for Gecko's `nsCSSShadowArray`. &gt; &gt; use gecko_bindings::bindings::Gecko_AddRefCSSShadowArrayArbitraryThread; &gt; use gecko_bindings::bindings::Gecko_NewCSSShadowArray; &gt; use gecko_bindings::bindings::Gecko_ReleaseCSSShadowArrayArbitraryThread; &gt;-use gecko_bindings::structs::{RefPtr, nsCSSShadowArray, nsCSSShadowItem}; &gt;-use std::{ptr, slice}; &gt;+use gecko_bindings::structs::{nsCSSShadowArray, nsCSSShadowItem, RefPtr}; &gt; use std::ops::{Deref, DerefMut}; &gt;+use std::{ptr, slice}; &gt; &gt; impl RefPtr&lt;nsCSSShadowArray&gt; { &gt; /// Replaces the current `nsCSSShadowArray` with a new one of len `len`. &gt; pub fn replace_with_new(&amp;mut self, len: u32) { &gt; unsafe { &gt; if !self.mRawPtr.is_null() { &gt; Gecko_ReleaseCSSShadowArrayArbitraryThread(self.mRawPtr); &gt; } &gt;diff --git a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs &gt;index 644166e3797e..b160041500e1 100644 &gt;--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs &gt;+++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs &gt;@@ -28,18 +28,18 @@ impl nsCSSValue { &gt; pub fn is_none(&amp;self) -&gt; bool { &gt; self.mUnit == nsCSSUnit::eCSSUnit_None &gt; } &gt; &gt; /// Returns this nsCSSValue value as an integer, unchecked in release &gt; /// builds. &gt; pub fn integer_unchecked(&amp;self) -&gt; i32 { &gt; debug_assert!( &gt;- self.mUnit == nsCSSUnit::eCSSUnit_Integer || &gt;- self.mUnit == nsCSSUnit::eCSSUnit_Enumerated &gt;+ self.mUnit == nsCSSUnit::eCSSUnit_Integer &gt;+ || self.mUnit == nsCSSUnit::eCSSUnit_Enumerated &gt; ); &gt; unsafe { *self.mValue.mInt.as_ref() } &gt; } &gt; &gt; /// Checks if it is an integer and returns it if so &gt; pub fn integer(&amp;self) -&gt; Option&lt;i32&gt; { &gt; if self.mUnit == nsCSSUnit::eCSSUnit_Integer || self.mUnit == nsCSSUnit::eCSSUnit_Enumerated &gt; { &gt;@@ -55,18 +55,18 @@ impl nsCSSValue { &gt; debug_assert!(nsCSSUnit::eCSSUnit_Number as u32 &lt;= self.mUnit as u32); &gt; unsafe { *self.mValue.mFloat.as_ref() } &gt; } &gt; &gt; /// Returns this nsCSSValue as a nsCSSValue::Array, unchecked in release &gt; /// builds. &gt; pub unsafe fn array_unchecked(&amp;self) -&gt; &amp;nsCSSValue_Array { &gt; debug_assert!( &gt;- nsCSSUnit::eCSSUnit_Array as u32 &lt;= self.mUnit as u32 &amp;&amp; &gt;- self.mUnit as u32 &lt;= nsCSSUnit::eCSSUnit_Calc_Divided as u32 &gt;+ nsCSSUnit::eCSSUnit_Array as u32 &lt;= self.mUnit as u32 &gt;+ &amp;&amp; self.mUnit as u32 &lt;= nsCSSUnit::eCSSUnit_Calc_Divided as u32 &gt; ); &gt; let array = *self.mValue.mArray.as_ref(); &gt; debug_assert!(!array.is_null()); &gt; &amp;*array &gt; } &gt; &gt; /// Sets LengthOrPercentage value to this nsCSSValue. &gt; pub unsafe fn set_lop(&amp;mut self, lop: LengthOrPercentage) { &gt;@@ -87,23 +87,23 @@ impl nsCSSValue { &gt; bindings::Gecko_CSSValue_SetPercentage(self, unit_value) &gt; } &gt; &gt; /// Returns LengthOrPercentage value. &gt; pub unsafe fn get_lop(&amp;self) -&gt; LengthOrPercentage { &gt; match self.mUnit { &gt; nsCSSUnit::eCSSUnit_Pixel =&gt; { &gt; LengthOrPercentage::Length(Length::new(bindings::Gecko_CSSValue_GetNumber(self))) &gt;- }, &gt;+ } &gt; nsCSSUnit::eCSSUnit_Percent =&gt; LengthOrPercentage::Percentage(Percentage( &gt; bindings::Gecko_CSSValue_GetPercentage(self), &gt; )), &gt; nsCSSUnit::eCSSUnit_Calc =&gt; { &gt; LengthOrPercentage::Calc(bindings::Gecko_CSSValue_GetCalc(self).into()) &gt;- }, &gt;+ } &gt; _ =&gt; panic!("Unexpected unit"), &gt; } &gt; } &gt; &gt; /// Returns Length value. &gt; pub unsafe fn get_length(&amp;self) -&gt; Length { &gt; match self.mUnit { &gt; nsCSSUnit::eCSSUnit_Pixel =&gt; Length::new(bindings::Gecko_CSSValue_GetNumber(self)), &gt;@@ -336,17 +336,17 @@ pub struct nsCSSValueListIterator&lt;'a&gt; { &gt; &gt; impl&lt;'a&gt; Iterator for nsCSSValueListIterator&lt;'a&gt; { &gt; type Item = &amp;'a nsCSSValue; &gt; fn next(&amp;mut self) -&gt; Option&lt;Self::Item&gt; { &gt; match self.current { &gt; Some(item) =&gt; { &gt; self.current = unsafe { item.mNext.as_ref() }; &gt; Some(&amp;item.mValue) &gt;- }, &gt;+ } &gt; None =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; IntoIterator for &amp;'a nsCSSValueList { &gt; type Item = &amp;'a nsCSSValue; &gt; type IntoIter = nsCSSValueListIterator&lt;'a&gt;; &gt;@@ -367,17 +367,17 @@ pub struct nsCSSValueListMutIterator&lt;'a&gt; { &gt; &gt; impl&lt;'a&gt; Iterator for nsCSSValueListMutIterator&lt;'a&gt; { &gt; type Item = &amp;'a mut nsCSSValue; &gt; fn next(&amp;mut self) -&gt; Option&lt;Self::Item&gt; { &gt; match unsafe { self.current.as_mut() } { &gt; Some(item) =&gt; { &gt; self.current = item.mNext; &gt; Some(&amp;mut item.mValue) &gt;- }, &gt;+ } &gt; None =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; IntoIterator for &amp;'a mut nsCSSValueList { &gt; type Item = &amp;'a mut nsCSSValue; &gt; type IntoIter = nsCSSValueListMutIterator&lt;'a&gt;; &gt;diff --git a/servo/components/style/gecko_bindings/sugar/ns_style_auto_array.rs b/servo/components/style/gecko_bindings/sugar/ns_style_auto_array.rs &gt;index 8adb8bb54d17..256199df7276 100644 &gt;--- a/servo/components/style/gecko_bindings/sugar/ns_style_auto_array.rs &gt;+++ b/servo/components/style/gecko_bindings/sugar/ns_style_auto_array.rs &gt;@@ -1,18 +1,18 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Rust helpers for Gecko's `nsStyleAutoArray`. &gt; &gt; use gecko_bindings::bindings::Gecko_EnsureStyleAnimationArrayLength; &gt; use gecko_bindings::bindings::Gecko_EnsureStyleTransitionArrayLength; &gt;-use gecko_bindings::structs::{StyleAnimation, StyleTransition}; &gt; use gecko_bindings::structs::nsStyleAutoArray; &gt;+use gecko_bindings::structs::{StyleAnimation, StyleTransition}; &gt; use std::iter::{once, Chain, IntoIterator, Once}; &gt; use std::ops::{Index, IndexMut}; &gt; use std::slice::{Iter, IterMut}; &gt; &gt; impl&lt;T&gt; Index&lt;usize&gt; for nsStyleAutoArray&lt;T&gt; { &gt; type Output = T; &gt; fn index(&amp;self, index: usize) -&gt; &amp;T { &gt; match index { &gt;diff --git a/servo/components/style/gecko_bindings/sugar/ns_style_coord.rs b/servo/components/style/gecko_bindings/sugar/ns_style_coord.rs &gt;index 3825c5520ecc..d5a327c6e56f 100644 &gt;--- a/servo/components/style/gecko_bindings/sugar/ns_style_coord.rs &gt;+++ b/servo/components/style/gecko_bindings/sugar/ns_style_coord.rs &gt;@@ -1,17 +1,17 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Rust helpers for Gecko's `nsStyleCoord`. &gt; &gt; use gecko_bindings::bindings; &gt; use gecko_bindings::structs::{nsStyleCoord, nsStyleCoord_Calc, nsStyleCoord_CalcValue}; &gt;-use gecko_bindings::structs::{nscoord, nsStyleCorners, nsStyleSides, nsStyleUnion, nsStyleUnit}; &gt;+use gecko_bindings::structs::{nsStyleCorners, nsStyleSides, nsStyleUnion, nsStyleUnit, nscoord}; &gt; use std::mem; &gt; &gt; impl nsStyleCoord { &gt; #[inline] &gt; /// Get a `null` nsStyleCoord. &gt; pub fn null() -&gt; Self { &gt; // Can't construct directly because it has private fields &gt; let mut coord: Self = unsafe { mem::zeroed() }; &gt;@@ -47,18 +47,19 @@ impl nsStyleCoord_CalcValue { &gt; mPercent: 0.0, &gt; mHasPercent: false, &gt; } &gt; } &gt; } &gt; &gt; impl PartialEq for nsStyleCoord_CalcValue { &gt; fn eq(&amp;self, other: &amp;Self) -&gt; bool { &gt;- self.mLength == other.mLength &amp;&amp; self.mPercent == other.mPercent &amp;&amp; &gt;- self.mHasPercent == other.mHasPercent &gt;+ self.mLength == other.mLength &gt;+ &amp;&amp; self.mPercent == other.mPercent &gt;+ &amp;&amp; self.mHasPercent == other.mHasPercent &gt; } &gt; } &gt; &gt; impl nsStyleSides { &gt; /// Immutably get the `nsStyleCoord`-like object representing the side at &gt; /// index `index`. &gt; #[inline] &gt; pub fn data_at(&amp;self, index: usize) -&gt; SidesData { &gt;@@ -277,82 +278,82 @@ pub unsafe trait CoordDataMut: CoordData { &gt; *unit = eStyleUnit_Null; &gt; *union.mInt.as_mut() = 0; &gt; } &gt; } &gt; &gt; #[inline(always)] &gt; /// Sets the inner value. &gt; fn set_value(&amp;mut self, value: CoordDataValue) { &gt;- use gecko_bindings::structs::nsStyleUnit::*; &gt; use self::CoordDataValue::*; &gt;+ use gecko_bindings::structs::nsStyleUnit::*; &gt; self.reset(); &gt; unsafe { &gt; let (unit, union) = self.values_mut(); &gt; match value { &gt; Null =&gt; { &gt; *unit = eStyleUnit_Null; &gt; *union.mInt.as_mut() = 0; &gt;- }, &gt;+ } &gt; Normal =&gt; { &gt; *unit = eStyleUnit_Normal; &gt; *union.mInt.as_mut() = 0; &gt;- }, &gt;+ } &gt; Auto =&gt; { &gt; *unit = eStyleUnit_Auto; &gt; *union.mInt.as_mut() = 0; &gt;- }, &gt;+ } &gt; None =&gt; { &gt; *unit = eStyleUnit_None; &gt; *union.mInt.as_mut() = 0; &gt;- }, &gt;+ } &gt; Percent(f) =&gt; { &gt; *unit = eStyleUnit_Percent; &gt; *union.mFloat.as_mut() = f; &gt;- }, &gt;+ } &gt; Factor(f) =&gt; { &gt; *unit = eStyleUnit_Factor; &gt; *union.mFloat.as_mut() = f; &gt;- }, &gt;+ } &gt; Degree(f) =&gt; { &gt; *unit = eStyleUnit_Degree; &gt; *union.mFloat.as_mut() = f; &gt;- }, &gt;+ } &gt; Grad(f) =&gt; { &gt; *unit = eStyleUnit_Grad; &gt; *union.mFloat.as_mut() = f; &gt;- }, &gt;+ } &gt; Radian(f) =&gt; { &gt; *unit = eStyleUnit_Radian; &gt; *union.mFloat.as_mut() = f; &gt;- }, &gt;+ } &gt; Turn(f) =&gt; { &gt; *unit = eStyleUnit_Turn; &gt; *union.mFloat.as_mut() = f; &gt;- }, &gt;+ } &gt; FlexFraction(f) =&gt; { &gt; *unit = eStyleUnit_FlexFraction; &gt; *union.mFloat.as_mut() = f; &gt;- }, &gt;+ } &gt; Coord(coord) =&gt; { &gt; *unit = eStyleUnit_Coord; &gt; *union.mInt.as_mut() = coord; &gt;- }, &gt;+ } &gt; Integer(i) =&gt; { &gt; *unit = eStyleUnit_Integer; &gt; *union.mInt.as_mut() = i; &gt;- }, &gt;+ } &gt; Enumerated(i) =&gt; { &gt; *unit = eStyleUnit_Enumerated; &gt; *union.mInt.as_mut() = i as i32; &gt;- }, &gt;+ } &gt; Calc(calc) =&gt; { &gt; // Gecko_SetStyleCoordCalcValue changes the unit internally &gt; bindings::Gecko_SetStyleCoordCalcValue(unit, union, calc); &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; #[inline] &gt; /// Gets the `Calc` value mutably, asserts in debug builds if the unit is &gt; /// not `Calc`. &gt; unsafe fn as_calc_mut(&amp;mut self) -&gt; &amp;mut nsStyleCoord_Calc { &gt;@@ -376,18 +377,18 @@ pub unsafe trait CoordData { &gt; /// Get the unit of this object. &gt; fn unit(&amp;self) -&gt; nsStyleUnit; &gt; /// Get the `nsStyleUnion` for this object. &gt; fn union(&amp;self) -&gt; nsStyleUnion; &gt; &gt; #[inline(always)] &gt; /// Get the appropriate value for this object. &gt; fn as_value(&amp;self) -&gt; CoordDataValue { &gt;- use gecko_bindings::structs::nsStyleUnit::*; &gt; use self::CoordDataValue::*; &gt;+ use gecko_bindings::structs::nsStyleUnit::*; &gt; unsafe { &gt; match self.unit() { &gt; eStyleUnit_Null =&gt; Null, &gt; eStyleUnit_Normal =&gt; Normal, &gt; eStyleUnit_Auto =&gt; Auto, &gt; eStyleUnit_None =&gt; None, &gt; eStyleUnit_Percent =&gt; Percent(self.get_float()), &gt; eStyleUnit_Factor =&gt; Factor(self.get_float()), &gt;@@ -404,31 +405,35 @@ pub unsafe trait CoordData { &gt; } &gt; } &gt; &gt; #[inline] &gt; /// Pretend inner value is a float; obtain it. &gt; unsafe fn get_float(&amp;self) -&gt; f32 { &gt; use gecko_bindings::structs::nsStyleUnit::*; &gt; debug_assert!( &gt;- self.unit() == eStyleUnit_Percent || self.unit() == eStyleUnit_Factor || &gt;- self.unit() == eStyleUnit_Degree || self.unit() == eStyleUnit_Grad || &gt;- self.unit() == eStyleUnit_Radian || self.unit() == eStyleUnit_Turn || &gt;- self.unit() == eStyleUnit_FlexFraction &gt;+ self.unit() == eStyleUnit_Percent &gt;+ || self.unit() == eStyleUnit_Factor &gt;+ || self.unit() == eStyleUnit_Degree &gt;+ || self.unit() == eStyleUnit_Grad &gt;+ || self.unit() == eStyleUnit_Radian &gt;+ || self.unit() == eStyleUnit_Turn &gt;+ || self.unit() == eStyleUnit_FlexFraction &gt; ); &gt; *self.union().mFloat.as_ref() &gt; } &gt; &gt; #[inline] &gt; /// Pretend inner value is an int; obtain it. &gt; unsafe fn get_integer(&amp;self) -&gt; i32 { &gt; use gecko_bindings::structs::nsStyleUnit::*; &gt; debug_assert!( &gt;- self.unit() == eStyleUnit_Coord || self.unit() == eStyleUnit_Integer || &gt;- self.unit() == eStyleUnit_Enumerated &gt;+ self.unit() == eStyleUnit_Coord &gt;+ || self.unit() == eStyleUnit_Integer &gt;+ || self.unit() == eStyleUnit_Enumerated &gt; ); &gt; *self.union().mInt.as_ref() &gt; } &gt; &gt; #[inline] &gt; /// Pretend inner value is a calc; obtain it. &gt; /// Ensure that the unit is Calc before calling this. &gt; unsafe fn get_calc_value(&amp;self) -&gt; nsStyleCoord_CalcValue { &gt;diff --git a/servo/components/style/gecko_bindings/sugar/ns_timing_function.rs b/servo/components/style/gecko_bindings/sugar/ns_timing_function.rs &gt;index 635b1f867680..b18b25b03b60 100644 &gt;--- a/servo/components/style/gecko_bindings/sugar/ns_timing_function.rs &gt;+++ b/servo/components/style/gecko_bindings/sugar/ns_timing_function.rs &gt;@@ -1,25 +1,25 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; use gecko_bindings::structs::{nsTimingFunction, nsTimingFunction_Type}; &gt; use std::mem; &gt;-use values::computed::ToComputedValue; &gt; use values::computed::transform::TimingFunction as ComputedTimingFunction; &gt;-use values::generics::transform::{StepPosition, TimingKeyword}; &gt;+use values::computed::ToComputedValue; &gt; use values::generics::transform::TimingFunction as GenericTimingFunction; &gt;+use values::generics::transform::{StepPosition, TimingKeyword}; &gt; use values::specified::transform::TimingFunction; &gt; &gt; impl nsTimingFunction { &gt; fn set_as_step(&amp;mut self, function_type: nsTimingFunction_Type, steps: u32) { &gt; debug_assert!( &gt;- function_type == nsTimingFunction_Type::StepStart || &gt;- function_type == nsTimingFunction_Type::StepEnd, &gt;+ function_type == nsTimingFunction_Type::StepStart &gt;+ || function_type == nsTimingFunction_Type::StepEnd, &gt; "function_type should be step-start or step-end" &gt; ); &gt; self.mType = function_type; &gt; unsafe { &gt; self.__bindgen_anon_1 &gt; .__bindgen_anon_1 &gt; .as_mut() &gt; .mStepsOrFrames = steps; &gt;@@ -64,38 +64,38 @@ impl From&lt;ComputedTimingFunction&gt; for nsTimingFunction { &gt; impl From&lt;TimingFunction&gt; for nsTimingFunction { &gt; fn from(function: TimingFunction) -&gt; nsTimingFunction { &gt; let mut tf: nsTimingFunction = unsafe { mem::zeroed() }; &gt; &gt; match function { &gt; GenericTimingFunction::Steps(steps, StepPosition::Start) =&gt; { &gt; debug_assert!(steps.value() &gt;= 0); &gt; tf.set_as_step(nsTimingFunction_Type::StepStart, steps.value() as u32); &gt;- }, &gt;+ } &gt; GenericTimingFunction::Steps(steps, StepPosition::End) =&gt; { &gt; debug_assert!(steps.value() &gt;= 0); &gt; tf.set_as_step(nsTimingFunction_Type::StepEnd, steps.value() as u32); &gt;- }, &gt;+ } &gt; GenericTimingFunction::Frames(frames) =&gt; { &gt; debug_assert!(frames.value() &gt;= 2); &gt; tf.set_as_frames(frames.value() as u32); &gt;- }, &gt;+ } &gt; GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } =&gt; { &gt; tf.set_as_bezier( &gt; nsTimingFunction_Type::CubicBezier, &gt; x1.get(), &gt; y1.get(), &gt; x2.get(), &gt; y2.get(), &gt; ); &gt;- }, &gt;+ } &gt; GenericTimingFunction::Keyword(keyword) =&gt; { &gt; let (x1, y1, x2, y2) = keyword.to_bezier(); &gt; tf.set_as_bezier(keyword.into(), x1, y1, x2, y2); &gt;- }, &gt;+ } &gt; } &gt; tf &gt; } &gt; } &gt; &gt; impl From&lt;nsTimingFunction&gt; for ComputedTimingFunction { &gt; fn from(function: nsTimingFunction) -&gt; ComputedTimingFunction { &gt; match function.mType { &gt;@@ -126,20 +126,20 @@ impl From&lt;nsTimingFunction&gt; for ComputedTimingFunction { &gt; .as_ref() &gt; .mStepsOrFrames &gt; }), &gt; nsTimingFunction_Type::Ease =&gt; GenericTimingFunction::Keyword(TimingKeyword::Ease), &gt; nsTimingFunction_Type::Linear =&gt; GenericTimingFunction::Keyword(TimingKeyword::Linear), &gt; nsTimingFunction_Type::EaseIn =&gt; GenericTimingFunction::Keyword(TimingKeyword::EaseIn), &gt; nsTimingFunction_Type::EaseOut =&gt; { &gt; GenericTimingFunction::Keyword(TimingKeyword::EaseOut) &gt;- }, &gt;+ } &gt; nsTimingFunction_Type::EaseInOut =&gt; { &gt; GenericTimingFunction::Keyword(TimingKeyword::EaseInOut) &gt;- }, &gt;+ } &gt; nsTimingFunction_Type::CubicBezier =&gt; unsafe { &gt; GenericTimingFunction::CubicBezier { &gt; x1: function.__bindgen_anon_1.mFunc.as_ref().mX1, &gt; y1: function.__bindgen_anon_1.mFunc.as_ref().mY1, &gt; x2: function.__bindgen_anon_1.mFunc.as_ref().mX2, &gt; y2: function.__bindgen_anon_1.mFunc.as_ref().mY2, &gt; } &gt; }, &gt;diff --git a/servo/components/style/gecko_bindings/sugar/refptr.rs b/servo/components/style/gecko_bindings/sugar/refptr.rs &gt;index 6a32b81430e1..5351702f2e47 100644 &gt;--- a/servo/components/style/gecko_bindings/sugar/refptr.rs &gt;+++ b/servo/components/style/gecko_bindings/sugar/refptr.rs &gt;@@ -1,21 +1,21 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! A rust helper to ease the use of Gecko's refcounted types. &gt; &gt;-use Atom; &gt;-use gecko_bindings::{structs, bindings}; &gt; use gecko_bindings::sugar::ownership::HasArcFFI; &gt;+use gecko_bindings::{bindings, structs}; &gt; use servo_arc::Arc; &gt;-use std::{fmt, mem, ptr}; &gt; use std::marker::PhantomData; &gt; use std::ops::{Deref, DerefMut}; &gt;+use std::{fmt, mem, ptr}; &gt;+use Atom; &gt; &gt; /// Trait for all objects that have Addref() and Release &gt; /// methods and can be placed inside RefPtr&lt;T&gt; &gt; pub unsafe trait RefCounted { &gt; /// Bump the reference count. &gt; fn addref(&amp;self); &gt; /// Decrease the reference count. &gt; unsafe fn release(&amp;self); &gt;@@ -316,13 +316,9 @@ impl_threadsafe_refcount!( &gt; #[inline] &gt; unsafe fn addref_atom(atom: *mut structs::nsAtom) { &gt; mem::forget(Atom::from_raw(atom)); &gt; } &gt; #[inline] &gt; unsafe fn release_atom(atom: *mut structs::nsAtom) { &gt; let _ = Atom::from_addrefed(atom); &gt; } &gt;-impl_threadsafe_refcount!( &gt;- structs::nsAtom, &gt;- addref_atom, &gt;- release_atom &gt;-); &gt;+impl_threadsafe_refcount!(structs::nsAtom, addref_atom, release_atom); &gt;diff --git a/servo/components/style/gecko_bindings/sugar/style_complex_color.rs b/servo/components/style/gecko_bindings/sugar/style_complex_color.rs &gt;index 90e93b72fd08..feb47f7e53cc 100644 &gt;--- a/servo/components/style/gecko_bindings/sugar/style_complex_color.rs &gt;+++ b/servo/components/style/gecko_bindings/sugar/style_complex_color.rs &gt;@@ -2,20 +2,20 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Rust helpers to interact with Gecko's StyleComplexColor. &gt; &gt; use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor}; &gt; use gecko_bindings::structs::StyleComplexColor; &gt; use gecko_bindings::structs::StyleComplexColor_Tag as Tag; &gt;-use values::{Auto, Either}; &gt;-use values::computed::{Color as ComputedColor, RGBAColor as ComputedRGBA}; &gt; use values::computed::ui::ColorOrAuto; &gt;+use values::computed::{Color as ComputedColor, RGBAColor as ComputedRGBA}; &gt; use values::generics::color::{Color as GenericColor, ComplexColorRatios}; &gt;+use values::{Auto, Either}; &gt; &gt; impl StyleComplexColor { &gt; /// Create a `StyleComplexColor` value that represents `currentColor`. &gt; pub fn current_color() -&gt; Self { &gt; StyleComplexColor { &gt; mColor: 0, &gt; mBgRatio: 0., &gt; mFgRatio: 1., &gt;diff --git a/servo/components/style/gecko_string_cache/mod.rs b/servo/components/style/gecko_string_cache/mod.rs &gt;index 70217f233de9..90855f24407c 100644 &gt;--- a/servo/components/style/gecko_string_cache/mod.rs &gt;+++ b/servo/components/style/gecko_string_cache/mod.rs &gt;@@ -8,23 +8,23 @@ &gt; &gt; use gecko_bindings::bindings::Gecko_AddRefAtom; &gt; use gecko_bindings::bindings::Gecko_Atomize; &gt; use gecko_bindings::bindings::Gecko_Atomize16; &gt; use gecko_bindings::bindings::Gecko_ReleaseAtom; &gt; use gecko_bindings::structs::{nsAtom, nsAtom_AtomKind, nsDynamicAtom, nsStaticAtom}; &gt; use nsstring::{nsAString, nsStr}; &gt; use precomputed_hash::PrecomputedHash; &gt;-use std::{mem, slice, str}; &gt; use std::borrow::{Borrow, Cow}; &gt; use std::char::{self, DecodeUtf16}; &gt; use std::fmt::{self, Write}; &gt; use std::hash::{Hash, Hasher}; &gt; use std::iter::Cloned; &gt; use std::ops::Deref; &gt;+use std::{mem, slice, str}; &gt; use style_traits::SpecifiedValueInfo; &gt; &gt; #[macro_use] &gt; #[allow(improper_ctypes, non_camel_case_types, missing_docs)] &gt; pub mod atom_macro { &gt; include!(concat!(env!("OUT_DIR"), "/gecko/atom_macro.rs")); &gt; } &gt; &gt;@@ -212,17 +212,17 @@ impl WeakAtom { &gt; &amp;mut vec &gt; }; &gt; for char16 in &amp;mut mutable_slice[i..] { &gt; if *char16 &lt;= 0x7F { &gt; *char16 = (*char16 as u8).to_ascii_lowercase() as u16 &gt; } &gt; } &gt; Atom::from(&amp;*mutable_slice) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Return whether two atoms are ASCII-case-insensitive matches &gt; pub fn eq_ignore_ascii_case(&amp;self, other: &amp;Self) -&gt; bool { &gt; if self == other { &gt; return true; &gt; } &gt;diff --git a/servo/components/style/invalidation/element/element_wrapper.rs b/servo/components/style/invalidation/element/element_wrapper.rs &gt;index cb4f79e92e1a..03a3cb92b36d 100644 &gt;--- a/servo/components/style/invalidation/element/element_wrapper.rs &gt;+++ b/servo/components/style/invalidation/element/element_wrapper.rs &gt;@@ -1,25 +1,25 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! A wrapper over an element and a snapshot, that allows us to selector-match &gt; //! against a past state of the element. &gt; &gt;-use {Atom, CaseSensitivityExt, LocalName, Namespace, WeakAtom}; &gt; use dom::TElement; &gt; use element_state::ElementState; &gt; use selector_parser::{AttrValue, NonTSPseudoClass, PseudoElement, SelectorImpl}; &gt; use selector_parser::{Snapshot, SnapshotMap}; &gt;-use selectors::{Element, OpaqueElement}; &gt; use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint}; &gt; use selectors::matching::{ElementSelectorFlags, MatchingContext}; &gt;+use selectors::{Element, OpaqueElement}; &gt; use std::cell::Cell; &gt; use std::fmt; &gt;+use {Atom, CaseSensitivityExt, LocalName, Namespace, WeakAtom}; &gt; &gt; /// In order to compute restyle hints, we perform a selector match against a &gt; /// list of partial selectors whose rightmost simple selector may be sensitive &gt; /// to the thing being changed. We do this matching twice, once for the element &gt; /// as it exists now and once for the element as it existed at the time of the &gt; /// last restyle. If the results of the selector match differ, that means that &gt; /// the given partial selector is sensitive to the change, and we compute a &gt; /// restyle hint based on its combinator. &gt;@@ -41,17 +41,19 @@ pub trait ElementSnapshot: Sized { &gt; fn state(&amp;self) -&gt; Option&lt;ElementState&gt;; &gt; &gt; /// If this snapshot contains attribute information. &gt; fn has_attrs(&amp;self) -&gt; bool; &gt; &gt; /// Gets the attribute information of the snapshot as a string. &gt; /// &gt; /// Only for debugging purposes. &gt;- fn debug_list_attributes(&amp;self) -&gt; String { String::new() } &gt;+ fn debug_list_attributes(&amp;self) -&gt; String { &gt;+ String::new() &gt;+ } &gt; &gt; /// The ID attribute per this snapshot. Should only be called if &gt; /// `has_attrs()` returns true. &gt; fn id_attr(&amp;self) -&gt; Option&lt;&amp;WeakAtom&gt;; &gt; &gt; /// Whether this snapshot contains the class `name`. Should only be called &gt; /// if `has_attrs()` returns true. &gt; fn has_class(&amp;self, name: &amp;Atom, case_sensitivity: CaseSensitivity) -&gt; bool; &gt;@@ -171,17 +173,17 @@ where &gt; #[cfg(feature = "gecko")] &gt; NonTSPseudoClass::MozAny(ref selectors) =&gt; { &gt; use selectors::matching::matches_complex_selector; &gt; return context.nest(|context| { &gt; selectors &gt; .iter() &gt; .any(|s| matches_complex_selector(s.iter(), self, context, _setter)) &gt; }); &gt;- }, &gt;+ } &gt; &gt; // :dir is implemented in terms of state flags, but which state flag &gt; // it maps to depends on the argument to :dir. That means we can't &gt; // just add its state flags to the NonTSPseudoClass, because if we &gt; // added all of them there, and tested via intersects() here, we'd &gt; // get incorrect behavior for :not(:dir()) cases. &gt; // &gt; // FIXME(bz): How can I set this up so once Servo adds :dir() &gt;@@ -194,66 +196,69 @@ where &gt; // :dir() with some random argument; does not match. &gt; return false; &gt; } &gt; let state = match self.snapshot().and_then(|s| s.state()) { &gt; Some(snapshot_state) =&gt; snapshot_state, &gt; None =&gt; self.element.state(), &gt; }; &gt; return state.contains(selector_flag); &gt;- }, &gt;+ } &gt; &gt; // For :link and :visited, we don't actually want to test the &gt; // element state directly. &gt; // &gt; // Instead, we use the `visited_handling` to determine if they &gt; // match. &gt; NonTSPseudoClass::Link =&gt; { &gt; return self.is_link() &amp;&amp; context.visited_handling().matches_unvisited() &gt;- }, &gt;+ } &gt; NonTSPseudoClass::Visited =&gt; { &gt; return self.is_link() &amp;&amp; context.visited_handling().matches_visited() &gt;- }, &gt;+ } &gt; &gt; #[cfg(feature = "gecko")] &gt; NonTSPseudoClass::MozTableBorderNonzero =&gt; { &gt; if let Some(snapshot) = self.snapshot() { &gt; if snapshot.has_other_pseudo_class_state() { &gt; return snapshot.mIsTableBorderNonzero(); &gt; } &gt; } &gt;- }, &gt;+ } &gt; &gt; #[cfg(feature = "gecko")] &gt; NonTSPseudoClass::MozBrowserFrame =&gt; { &gt; if let Some(snapshot) = self.snapshot() { &gt; if snapshot.has_other_pseudo_class_state() { &gt; return snapshot.mIsMozBrowserFrame(); &gt; } &gt; } &gt;- }, &gt;+ } &gt; &gt; // :lang() needs to match using the closest ancestor xml:lang="" or &gt; // lang="" attribtue from snapshots. &gt; NonTSPseudoClass::Lang(ref lang_arg) =&gt; { &gt;- return self.element &gt;+ return self &gt;+ .element &gt; .match_element_lang(Some(self.get_lang()), lang_arg); &gt;- }, &gt;+ } &gt; &gt;- _ =&gt; {}, &gt;+ _ =&gt; {} &gt; } &gt; &gt; let flag = pseudo_class.state_flag(); &gt; if flag.is_empty() { &gt;- return self.element &gt;+ return self &gt;+ .element &gt; .match_non_ts_pseudo_class(pseudo_class, context, &amp;mut |_, _| {}); &gt; } &gt; match self.snapshot().and_then(|s| s.state()) { &gt; Some(snapshot_state) =&gt; snapshot_state.intersects(flag), &gt;- None =&gt; self.element &gt;+ None =&gt; self &gt;+ .element &gt; .match_non_ts_pseudo_class(pseudo_class, context, &amp;mut |_, _| {}), &gt; } &gt; } &gt; &gt; fn match_pseudo_element( &gt; &amp;self, &gt; pseudo_element: &amp;PseudoElement, &gt; context: &amp;mut MatchingContext&lt;Self::Impl&gt;, &gt;@@ -317,17 +322,17 @@ where &gt; &amp;self, &gt; ns: &amp;NamespaceConstraint&lt;&amp;Namespace&gt;, &gt; local_name: &amp;LocalName, &gt; operation: &amp;AttrSelectorOperation&lt;&amp;AttrValue&gt;, &gt; ) -&gt; bool { &gt; match self.snapshot() { &gt; Some(snapshot) if snapshot.has_attrs() =&gt; { &gt; snapshot.attr_matches(ns, local_name, operation) &gt;- }, &gt;+ } &gt; _ =&gt; self.element.attr_matches(ns, local_name, operation), &gt; } &gt; } &gt; &gt; fn has_id(&amp;self, id: &amp;Atom, case_sensitivity: CaseSensitivity) -&gt; bool { &gt; match self.snapshot() { &gt; Some(snapshot) if snapshot.has_attrs() =&gt; snapshot &gt; .id_attr() &gt;diff --git a/servo/components/style/invalidation/element/invalidation_map.rs b/servo/components/style/invalidation/element/invalidation_map.rs &gt;index 67849d896270..bdb6b84521b3 100644 &gt;--- a/servo/components/style/invalidation/element/invalidation_map.rs &gt;+++ b/servo/components/style/invalidation/element/invalidation_map.rs &gt;@@ -1,40 +1,40 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Code for invalidations due to state or attribute changes. &gt; &gt;-use {Atom, LocalName, Namespace}; &gt; use context::QuirksMode; &gt; use element_state::{DocumentState, ElementState}; &gt; use fallible::FallibleVec; &gt; use hashglobe::FailedAllocationError; &gt; use selector_map::{MaybeCaseInsensitiveHashMap, SelectorMap, SelectorMapEntry}; &gt; #[cfg(feature = "gecko")] &gt; use selector_parser::Direction; &gt; use selector_parser::SelectorImpl; &gt; use selectors::attr::NamespaceConstraint; &gt; use selectors::parser::{Combinator, Component}; &gt; use selectors::parser::{Selector, SelectorIter, Visit}; &gt; use selectors::visitor::SelectorVisitor; &gt; use smallvec::SmallVec; &gt;+use {Atom, LocalName, Namespace}; &gt; &gt; #[cfg(feature = "gecko")] &gt; /// Gets the element state relevant to the given `:dir` pseudo-class selector. &gt; pub fn dir_selector_to_state(dir: &amp;Direction) -&gt; ElementState { &gt; match *dir { &gt; Direction::Ltr =&gt; ElementState::IN_LTR_STATE, &gt; Direction::Rtl =&gt; ElementState::IN_RTL_STATE, &gt; Direction::Other(_) =&gt; { &gt; // :dir(something-random) is a valid selector, but shouldn't &gt; // match anything. &gt; ElementState::empty() &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Mapping between (partial) CompoundSelectors (and the combinator to their &gt; /// right) and the states and attributes they depend on. &gt; /// &gt; /// In general, for all selectors in all applicable stylesheets of the form: &gt; /// &gt;@@ -49,18 +49,20 @@ pub fn dir_selector_to_state(dir: &amp;Direction) -&gt; ElementState { &gt; /// We generate a Dependency for both |a _ b:X _| and |a _ b:X _ c _ d:Y _|, &gt; /// even though those selectors may not appear on their own in any stylesheet. &gt; /// This allows us to quickly scan through the dependency sites of all style &gt; /// rules and determine the maximum effect that a given state or attribute &gt; /// change may have on the style of elements in the document. &gt; #[derive(Clone, Debug, MallocSizeOf)] &gt; pub struct Dependency { &gt; /// The dependency selector. &gt;- #[cfg_attr(feature = "gecko", &gt;- ignore_malloc_size_of = "CssRules have primary refs, we measure there")] &gt;+ #[cfg_attr( &gt;+ feature = "gecko", &gt;+ ignore_malloc_size_of = "CssRules have primary refs, we measure there" &gt;+ )] &gt; #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] &gt; pub selector: Selector&lt;SelectorImpl&gt;, &gt; &gt; /// The offset into the selector that we should match on. &gt; pub selector_offset: usize, &gt; } &gt; &gt; /// The kind of elements down the tree this dependency may affect. &gt;@@ -99,20 +101,20 @@ impl Dependency { &gt; } &gt; &gt; /// The kind of invalidation that this would generate. &gt; pub fn invalidation_kind(&amp;self) -&gt; DependencyInvalidationKind { &gt; match self.combinator() { &gt; None =&gt; DependencyInvalidationKind::Element, &gt; Some(Combinator::Child) | Some(Combinator::Descendant) =&gt; { &gt; DependencyInvalidationKind::Descendants &gt;- }, &gt;+ } &gt; Some(Combinator::LaterSibling) | Some(Combinator::NextSibling) =&gt; { &gt; DependencyInvalidationKind::Siblings &gt;- }, &gt;+ } &gt; // TODO(emilio): We could look at the selector itself to see if it's &gt; // an eager pseudo, and return only Descendants here if not. &gt; Some(Combinator::PseudoElement) =&gt; DependencyInvalidationKind::ElementAndDescendants, &gt; Some(Combinator::SlotAssignment) =&gt; DependencyInvalidationKind::SlottedElements, &gt; } &gt; } &gt; } &gt; &gt;@@ -138,18 +140,20 @@ impl SelectorMapEntry for StateDependency { &gt; } &gt; } &gt; &gt; /// The same, but for document state selectors. &gt; #[derive(Clone, Debug, MallocSizeOf)] &gt; pub struct DocumentStateDependency { &gt; /// The selector that is affected. We don't need to track an offset, since &gt; /// when it changes it changes for the whole document anyway. &gt;- #[cfg_attr(feature = "gecko", &gt;- ignore_malloc_size_of = "CssRules have primary refs, we measure there")] &gt;+ #[cfg_attr( &gt;+ feature = "gecko", &gt;+ ignore_malloc_size_of = "CssRules have primary refs, we measure there" &gt;+ )] &gt; #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] &gt; pub selector: Selector&lt;SelectorImpl&gt;, &gt; /// The state this dependency is affected by. &gt; pub state: DocumentState, &gt; } &gt; &gt; /// A map where we store invalidations. &gt; /// &gt;@@ -196,22 +200,25 @@ impl InvalidationMap { &gt; other_attribute_affecting_selectors: SelectorMap::new(), &gt; has_class_attribute_selectors: false, &gt; has_id_attribute_selectors: false, &gt; } &gt; } &gt; &gt; /// Returns the number of dependencies stored in the invalidation map. &gt; pub fn len(&amp;self) -&gt; usize { &gt;- self.state_affecting_selectors.len() + self.document_state_selectors.len() + &gt;- self.other_attribute_affecting_selectors.len() + &gt;- self.id_to_selector &gt;+ self.state_affecting_selectors.len() &gt;+ + self.document_state_selectors.len() &gt;+ + self.other_attribute_affecting_selectors.len() &gt;+ + self &gt;+ .id_to_selector &gt; .iter() &gt;- .fold(0, |accum, (_, ref v)| accum + v.len()) + &gt;- self.class_to_selector &gt;+ .fold(0, |accum, (_, ref v)| accum + v.len()) &gt;+ + self &gt;+ .class_to_selector &gt; .iter() &gt; .fold(0, |accum, (_, ref v)| accum + v.len()) &gt; } &gt; &gt; /// Clears this map, leaving it empty. &gt; pub fn clear(&amp;mut self) { &gt; self.class_to_selector.clear(); &gt; self.id_to_selector.clear(); &gt;@@ -369,30 +376,30 @@ impl&lt;'a&gt; SelectorVisitor for CompoundSelectorDependencyCollector&lt;'a&gt; { &gt; &gt; fn visit_simple_selector(&amp;mut self, s: &amp;Component&lt;SelectorImpl&gt;) -&gt; bool { &gt; #[cfg(feature = "gecko")] &gt; use selector_parser::NonTSPseudoClass; &gt; &gt; match *s { &gt; Component::ID(ref id) =&gt; { &gt; self.ids.push(id.clone()); &gt;- }, &gt;+ } &gt; Component::Class(ref class) =&gt; { &gt; self.classes.push(class.clone()); &gt;- }, &gt;+ } &gt; Component::NonTSPseudoClass(ref pc) =&gt; { &gt; self.other_attributes |= pc.is_attr_based(); &gt; self.state |= match *pc { &gt; #[cfg(feature = "gecko")] &gt; NonTSPseudoClass::Dir(ref dir) =&gt; dir_selector_to_state(dir), &gt; _ =&gt; pc.state_flag(), &gt; }; &gt; *self.document_state |= pc.document_state_flag(); &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; &gt; true &gt; } &gt; &gt; fn visit_attribute_selector( &gt; &amp;mut self, &gt; constraint: &amp;NamespaceConstraint&lt;&amp;Namespace&gt;, &gt;diff --git a/servo/components/style/invalidation/element/invalidator.rs b/servo/components/style/invalidation/element/invalidator.rs &gt;index 8d60ade88e26..42035e16a893 100644 &gt;--- a/servo/components/style/invalidation/element/invalidator.rs &gt;+++ b/servo/components/style/invalidation/element/invalidator.rs &gt;@@ -3,18 +3,18 @@ &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! The struct that takes care of encapsulating all the logic on where and how &gt; //! element styles need to be invalidated. &gt; &gt; use context::StackLimitChecker; &gt; use dom::{TElement, TNode, TShadowRoot}; &gt; use selector_parser::SelectorImpl; &gt;-use selectors::matching::{CompoundSelectorMatchingResult, MatchingContext}; &gt; use selectors::matching::matches_compound_selector_from; &gt;+use selectors::matching::{CompoundSelectorMatchingResult, MatchingContext}; &gt; use selectors::parser::{Combinator, Component, Selector}; &gt; use smallvec::SmallVec; &gt; use std::fmt; &gt; &gt; /// A trait to abstract the collection of invalidations for a given pass. &gt; pub trait InvalidationProcessor&lt;'a, E&gt; &gt; where &gt; E: TElement, &gt;@@ -165,20 +165,20 @@ impl&lt;'a&gt; Invalidation&lt;'a&gt; { &gt; fn kind(&amp;self) -&gt; InvalidationKind { &gt; if self.offset == 0 { &gt; return InvalidationKind::Descendant(DescendantInvalidationKind::Dom); &gt; } &gt; &gt; match self.selector.combinator_at_parse_order(self.offset - 1) { &gt; Combinator::Child | Combinator::Descendant | Combinator::PseudoElement =&gt; { &gt; InvalidationKind::Descendant(DescendantInvalidationKind::Dom) &gt;- }, &gt;+ } &gt; Combinator::SlotAssignment =&gt; { &gt; InvalidationKind::Descendant(DescendantInvalidationKind::Slotted) &gt;- }, &gt;+ } &gt; Combinator::NextSibling | Combinator::LaterSibling =&gt; InvalidationKind::Sibling, &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; fmt::Debug for Invalidation&lt;'a&gt; { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; use cssparser::ToCss; &gt;@@ -689,17 +689,17 @@ where &gt; &gt; let mut invalidated_self = false; &gt; let mut matched = false; &gt; match matching_result { &gt; CompoundSelectorMatchingResult::FullyMatched =&gt; { &gt; debug!(" &gt; Invalidation matched completely"); &gt; matched = true; &gt; invalidated_self = true; &gt;- }, &gt;+ } &gt; CompoundSelectorMatchingResult::Matched { &gt; next_combinator_offset, &gt; } =&gt; { &gt; let next_combinator = invalidation &gt; .selector &gt; .combinator_at_parse_order(next_combinator_offset); &gt; matched = true; &gt; &gt;@@ -809,44 +809,44 @@ where &gt; // &gt; // [div div div, div div, div div, div] &gt; // &gt; // While skipping it, we won't arrive here with duplicating &gt; // dependencies: &gt; // &gt; // [div div div, div div, div] &gt; // &gt;- let can_skip_pushing = next_invalidation_kind == invalidation_kind &amp;&amp; &gt;- invalidation.matched_by_any_previous &amp;&amp; &gt;- next_invalidation.effective_for_next(); &gt;+ let can_skip_pushing = next_invalidation_kind == invalidation_kind &gt;+ &amp;&amp; invalidation.matched_by_any_previous &gt;+ &amp;&amp; next_invalidation.effective_for_next(); &gt; &gt; if can_skip_pushing { &gt; debug!( &gt; " &gt; Can avoid push, since the invalidation had \ &gt; already been matched before" &gt; ); &gt; } else { &gt; match next_invalidation_kind { &gt; InvalidationKind::Descendant(DescendantInvalidationKind::Dom) =&gt; { &gt; descendant_invalidations &gt; .dom_descendants &gt; .push(next_invalidation); &gt;- }, &gt;+ } &gt; InvalidationKind::Descendant(DescendantInvalidationKind::Slotted) =&gt; { &gt; descendant_invalidations &gt; .slotted_descendants &gt; .push(next_invalidation); &gt;- }, &gt;+ } &gt; InvalidationKind::Sibling =&gt; { &gt; sibling_invalidations.push(next_invalidation); &gt;- }, &gt;+ } &gt; } &gt; } &gt;- }, &gt;- CompoundSelectorMatchingResult::NotMatched =&gt; {}, &gt;+ } &gt;+ CompoundSelectorMatchingResult::NotMatched =&gt; {} &gt; } &gt; &gt; SingleInvalidationResult { &gt; invalidated_self, &gt; matched, &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/style/invalidation/element/restyle_hints.rs b/servo/components/style/invalidation/element/restyle_hints.rs &gt;index 4ac06c8b1631..ec241d40d3f1 100644 &gt;--- a/servo/components/style/invalidation/element/restyle_hints.rs &gt;+++ b/servo/components/style/invalidation/element/restyle_hints.rs &gt;@@ -62,18 +62,19 @@ impl RestyleHint { &gt; /// descendants. &gt; pub fn contains_subtree(&amp;self) -&gt; bool { &gt; self.contains(RestyleHint::RESTYLE_SELF | RestyleHint::RESTYLE_DESCENDANTS) &gt; } &gt; &gt; /// Returns whether we need to restyle this element. &gt; pub fn has_non_animation_invalidations(&amp;self) -&gt; bool { &gt; self.intersects( &gt;- RestyleHint::RESTYLE_SELF | RestyleHint::RECASCADE_SELF | &gt;- (Self::replacements() &amp; !Self::for_animations()), &gt;+ RestyleHint::RESTYLE_SELF &gt;+ | RestyleHint::RECASCADE_SELF &gt;+ | (Self::replacements() &amp; !Self::for_animations()), &gt; ) &gt; } &gt; &gt; /// Propagates this restyle hint to a child element. &gt; pub fn propagate(&amp;mut self, traversal_flags: &amp;TraversalFlags) -&gt; Self { &gt; use std::mem; &gt; &gt; // In the middle of an animation only restyle, we don't need to &gt;@@ -114,18 +115,19 @@ impl RestyleHint { &gt; /// Returns a hint that contains all the replacement hints. &gt; pub fn replacements() -&gt; Self { &gt; RestyleHint::RESTYLE_STYLE_ATTRIBUTE | Self::for_animations() &gt; } &gt; &gt; /// The replacements for the animation cascade levels. &gt; #[inline] &gt; pub fn for_animations() -&gt; Self { &gt;- RestyleHint::RESTYLE_SMIL | RestyleHint::RESTYLE_CSS_ANIMATIONS | &gt;- RestyleHint::RESTYLE_CSS_TRANSITIONS &gt;+ RestyleHint::RESTYLE_SMIL &gt;+ | RestyleHint::RESTYLE_CSS_ANIMATIONS &gt;+ | RestyleHint::RESTYLE_CSS_TRANSITIONS &gt; } &gt; &gt; /// Returns whether the hint specifies that the currently element must be &gt; /// recascaded. &gt; pub fn has_recascade_self(&amp;self) -&gt; bool { &gt; self.contains(RestyleHint::RECASCADE_SELF) &gt; } &gt; &gt;diff --git a/servo/components/style/invalidation/element/state_and_attributes.rs b/servo/components/style/invalidation/element/state_and_attributes.rs &gt;index 1eb022b298a7..76a17bb3b2da 100644 &gt;--- a/servo/components/style/invalidation/element/state_and_attributes.rs &gt;+++ b/servo/components/style/invalidation/element/state_and_attributes.rs &gt;@@ -1,33 +1,33 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! An invalidation processor for style changes due to state and attribute &gt; //! changes. &gt; &gt;-use {Atom, WeakAtom}; &gt; use context::SharedStyleContext; &gt; use data::ElementData; &gt; use dom::TElement; &gt; use element_state::ElementState; &gt; use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper}; &gt; use invalidation::element::invalidation_map::*; &gt; use invalidation::element::invalidator::{DescendantInvalidationLists, InvalidationVector}; &gt; use invalidation::element::invalidator::{Invalidation, InvalidationProcessor}; &gt; use invalidation::element::restyle_hints::RestyleHint; &gt; use selector_map::SelectorMap; &gt; use selector_parser::Snapshot; &gt;-use selectors::NthIndexCache; &gt; use selectors::attr::CaseSensitivity; &gt;-use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode}; &gt; use selectors::matching::matches_selector; &gt;+use selectors::matching::{MatchingContext, MatchingMode, VisitedHandlingMode}; &gt;+use selectors::NthIndexCache; &gt; use smallvec::SmallVec; &gt; use stylesheets::origin::{Origin, OriginSet}; &gt;+use {Atom, WeakAtom}; &gt; &gt; /// The collector implementation. &gt; struct Collector&lt;'a, 'b: 'a, 'selectors: 'a, E&gt; &gt; where &gt; E: TElement, &gt; { &gt; element: E, &gt; wrapper: ElementWrapper&lt;'b, E&gt;, &gt;@@ -201,27 +201,22 @@ where &gt; } &gt; &gt; if log_enabled!(::log::Level::Debug) { &gt; debug!("Collecting changes for: {:?}", element); &gt; if !state_changes.is_empty() { &gt; debug!(" &gt; state: {:?}", state_changes); &gt; } &gt; if snapshot.id_changed() { &gt;- debug!( &gt;- " &gt; id changed: +{:?} -{:?}", &gt;- id_added, &gt;- id_removed &gt;- ); &gt;+ debug!(" &gt; id changed: +{:?} -{:?}", id_added, id_removed); &gt; } &gt; if snapshot.class_changed() { &gt; debug!( &gt; " &gt; class changed: +{:?} -{:?}", &gt;- classes_added, &gt;- classes_removed &gt;+ classes_added, classes_removed &gt; ); &gt; } &gt; if snapshot.other_attr_changed() { &gt; debug!( &gt; " &gt; attributes changed, old: {}", &gt; snapshot.debug_list_attributes() &gt; ) &gt; } &gt;@@ -234,17 +229,16 @@ where &gt; }; &gt; &gt; let mut shadow_rule_datas = SmallVec::&lt;[_; 3]&gt;::new(); &gt; let matches_document_author_rules = &gt; element.each_applicable_non_document_style_rule_data(|data, quirks_mode, host| { &gt; shadow_rule_datas.push((data, quirks_mode, host.map(|h| h.opaque()))) &gt; }); &gt; &gt;- &gt; let invalidated_self = { &gt; let mut collector = Collector { &gt; wrapper, &gt; lookup_element, &gt; state_changes, &gt; element, &gt; snapshot: &amp;snapshot, &gt; matching_context: &amp;mut self.matching_context, &gt;@@ -363,19 +357,19 @@ where &gt; for class in self.classes_added.iter().chain(self.classes_removed.iter()) { &gt; if let Some(deps) = map.class_to_selector.get(class, quirks_mode) { &gt; for dep in deps { &gt; self.scan_dependency(dep); &gt; } &gt; } &gt; } &gt; &gt;- let should_examine_attribute_selector_map = self.snapshot.other_attr_changed() || &gt;- (self.snapshot.class_changed() &amp;&amp; map.has_class_attribute_selectors) || &gt;- (self.snapshot.id_changed() &amp;&amp; map.has_id_attribute_selectors); &gt;+ let should_examine_attribute_selector_map = self.snapshot.other_attr_changed() &gt;+ || (self.snapshot.class_changed() &amp;&amp; map.has_class_attribute_selectors) &gt;+ || (self.snapshot.id_changed() &amp;&amp; map.has_id_attribute_selectors); &gt; &gt; if should_examine_attribute_selector_map { &gt; self.collect_dependencies_in_map(&amp;map.other_attribute_affecting_selectors) &gt; } &gt; &gt; let state_changes = self.state_changes; &gt; if !state_changes.is_empty() { &gt; self.collect_state_dependencies(&amp;map.state_affecting_selectors, state_changes) &gt;@@ -411,20 +405,17 @@ where &gt; } &gt; self.scan_dependency(&amp;dependency.dep); &gt; true &gt; }, &gt; ); &gt; } &gt; &gt; /// Check whether a dependency should be taken into account. &gt;- fn check_dependency( &gt;- &amp;mut self, &gt;- dependency: &amp;Dependency, &gt;- ) -&gt; bool { &gt;+ fn check_dependency(&amp;mut self, dependency: &amp;Dependency) -&gt; bool { &gt; let element = &amp;self.element; &gt; let wrapper = &amp;self.wrapper; &gt; let matches_now = matches_selector( &gt; &amp;dependency.selector, &gt; dependency.selector_offset, &gt; None, &gt; element, &gt; &amp;mut self.matching_context, &gt;@@ -477,37 +468,37 @@ where &gt; &gt; match invalidation_kind { &gt; DependencyInvalidationKind::Element =&gt; unreachable!(), &gt; DependencyInvalidationKind::ElementAndDescendants =&gt; { &gt; self.invalidates_self = true; &gt; self.descendant_invalidations &gt; .dom_descendants &gt; .push(invalidation); &gt;- }, &gt;+ } &gt; DependencyInvalidationKind::Descendants =&gt; { &gt; self.descendant_invalidations &gt; .dom_descendants &gt; .push(invalidation); &gt;- }, &gt;+ } &gt; DependencyInvalidationKind::Siblings =&gt; { &gt; self.sibling_invalidations.push(invalidation); &gt;- }, &gt;+ } &gt; DependencyInvalidationKind::SlottedElements =&gt; { &gt; self.descendant_invalidations &gt; .slotted_descendants &gt; .push(invalidation); &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Returns whether `dependency` may cause us to invalidate the style of &gt; /// more elements than what we've already invalidated. &gt; fn dependency_may_be_relevant(&amp;self, dependency: &amp;Dependency) -&gt; bool { &gt; match dependency.invalidation_kind() { &gt; DependencyInvalidationKind::Element =&gt; !self.invalidates_self, &gt; DependencyInvalidationKind::SlottedElements =&gt; self.element.is_html_slot_element(), &gt;- DependencyInvalidationKind::ElementAndDescendants | &gt;- DependencyInvalidationKind::Siblings | &gt;- DependencyInvalidationKind::Descendants =&gt; true, &gt;+ DependencyInvalidationKind::ElementAndDescendants &gt;+ | DependencyInvalidationKind::Siblings &gt;+ | DependencyInvalidationKind::Descendants =&gt; true, &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/style/invalidation/stylesheets.rs b/servo/components/style/invalidation/stylesheets.rs &gt;index 1889d325630f..802156e171bf 100644 &gt;--- a/servo/components/style/invalidation/stylesheets.rs &gt;+++ b/servo/components/style/invalidation/stylesheets.rs &gt;@@ -2,29 +2,29 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! A collection of invalidations due to changes in which stylesheets affect a &gt; //! document. &gt; &gt; #![deny(unsafe_code)] &gt; &gt;-use Atom; &gt;-use CaseSensitivityExt; &gt;-use LocalName as SelectorLocalName; &gt; use dom::{TDocument, TElement, TNode}; &gt; use fxhash::FxHashSet; &gt; use invalidation::element::element_wrapper::{ElementSnapshot, ElementWrapper}; &gt; use invalidation::element::restyle_hints::RestyleHint; &gt; use media_queries::Device; &gt; use selector_parser::{SelectorImpl, Snapshot, SnapshotMap}; &gt; use selectors::attr::CaseSensitivity; &gt; use selectors::parser::{Component, LocalName, Selector}; &gt; use shared_lock::SharedRwLockReadGuard; &gt; use stylesheets::{CssRule, StylesheetInDocument}; &gt;+use Atom; &gt;+use CaseSensitivityExt; &gt;+use LocalName as SelectorLocalName; &gt; &gt; /// A style sheet invalidation represents a kind of element or subtree that may &gt; /// need to be restyled. Whether it represents a whole subtree or just a single &gt; /// element is determined by whether the invalidation is stored in the &gt; /// StylesheetInvalidationSet's invalid_scopes or invalid_elements table. &gt; #[derive(Debug, Eq, Hash, MallocSizeOf, PartialEq)] &gt; enum Invalidation { &gt; /// An element with a given id. &gt;@@ -62,42 +62,42 @@ impl Invalidation { &gt; return true; &gt; } &gt; &gt; if let Some(snapshot) = snapshot { &gt; if snapshot.has_class(class, case_sensitivity) { &gt; return true; &gt; } &gt; } &gt;- }, &gt;+ } &gt; Invalidation::ID(ref id) =&gt; { &gt; if let Some(ref element_id) = element.id() { &gt; if case_sensitivity.eq_atom(element_id, id) { &gt; return true; &gt; } &gt; } &gt; &gt; if let Some(snapshot) = snapshot { &gt; if let Some(ref old_id) = snapshot.id_attr() { &gt; if case_sensitivity.eq_atom(old_id, id) { &gt; return true; &gt; } &gt; } &gt; } &gt;- }, &gt;+ } &gt; Invalidation::LocalName { &gt; ref name, &gt; ref lower_name, &gt; } =&gt; { &gt; // This could look at the quirks mode of the document, instead &gt; // of testing against both names, but it's probably not worth &gt; // it. &gt; let local_name = element.local_name(); &gt; return *local_name == **name || *local_name == **lower_name; &gt;- }, &gt;+ } &gt; } &gt; &gt; false &gt; } &gt; } &gt; &gt; /// A set of invalidations due to stylesheet additions. &gt; /// &gt;@@ -331,30 +331,30 @@ impl StylesheetInvalidationSet { &gt; ref lower_name, &gt; }) =&gt; { &gt; if invalidation.as_ref().map_or(true, |s| !s.is_id_or_class()) { &gt; *invalidation = Some(Invalidation::LocalName { &gt; name: name.clone(), &gt; lower_name: lower_name.clone(), &gt; }); &gt; } &gt;- }, &gt;+ } &gt; Component::Class(ref class) =&gt; { &gt; if invalidation.as_ref().map_or(true, |s| !s.is_id()) { &gt; *invalidation = Some(Invalidation::Class(class.clone())); &gt; } &gt;- }, &gt;+ } &gt; Component::ID(ref id) =&gt; { &gt; if invalidation.is_none() { &gt; *invalidation = Some(Invalidation::ID(id.clone())); &gt; } &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; // Ignore everything else, at least for now. &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Collect invalidations for a given selector. &gt; /// &gt; /// We look at the outermost local name, class, or ID selector to the left &gt; /// of an ancestor combinator, in order to restyle only a given subtree. &gt; /// &gt;@@ -388,17 +388,17 @@ impl StylesheetInvalidationSet { &gt; } else if scan_for_subtree_invalidation { &gt; Self::scan_component(component, &amp;mut subtree_invalidation); &gt; } &gt; } &gt; match iter.next_sequence() { &gt; None =&gt; break, &gt; Some(combinator) =&gt; { &gt; scan_for_subtree_invalidation = combinator.is_ancestor(); &gt;- }, &gt;+ } &gt; } &gt; scan_for_element_invalidation = false; &gt; } &gt; &gt; if let Some(s) = subtree_invalidation { &gt; debug!(" &gt; Found subtree invalidation: {:?}", s); &gt; self.invalid_scopes.insert(s); &gt; } else if let Some(s) = element_invalidation { &gt;@@ -427,46 +427,46 @@ impl StylesheetInvalidationSet { &gt; Style(ref lock) =&gt; { &gt; let style_rule = lock.read_with(guard); &gt; for selector in &amp;style_rule.selectors.0 { &gt; self.collect_invalidations(selector); &gt; if self.fully_invalid { &gt; return; &gt; } &gt; } &gt;- }, &gt;+ } &gt; Document(..) | Namespace(..) | Import(..) | Media(..) | Supports(..) =&gt; { &gt; // Do nothing, relevant nested rules are visited as part of the &gt; // iteration. &gt;- }, &gt;+ } &gt; FontFace(..) =&gt; { &gt; // Do nothing, @font-face doesn't affect computed style &gt; // information. We'll restyle when the font face loads, if &gt; // needed. &gt;- }, &gt;+ } &gt; Keyframes(ref lock) =&gt; { &gt; let keyframes_rule = lock.read_with(guard); &gt; if device.animation_name_may_be_referenced(&amp;keyframes_rule.name) { &gt; debug!( &gt; " &gt; Found @keyframes rule potentially referenced \ &gt; from the page, marking the whole tree invalid." &gt; ); &gt; self.fully_invalid = true; &gt; } else { &gt; // Do nothing, this animation can't affect the style of &gt; // existing elements. &gt; } &gt;- }, &gt;+ } &gt; CounterStyle(..) | Page(..) | Viewport(..) | FontFeatureValues(..) =&gt; { &gt; debug!( &gt; " &gt; Found unsupported rule, marking the whole subtree \ &gt; invalid." &gt; ); &gt; &gt; // TODO(emilio): Can we do better here? &gt; // &gt; // At least in `@page`, we could check the relevant media, I &gt; // guess. &gt; self.fully_invalid = true; &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/style/lib.rs b/servo/components/style/lib.rs &gt;index 1c3630b09864..a9b2deafd5e2 100644 &gt;--- a/servo/components/style/lib.rs &gt;+++ b/servo/components/style/lib.rs &gt;@@ -161,30 +161,30 @@ pub mod traversal_flags; &gt; #[allow(non_camel_case_types)] &gt; pub mod values; &gt; &gt; #[cfg(feature = "gecko")] &gt; pub use gecko_string_cache as string_cache; &gt; #[cfg(feature = "gecko")] &gt; pub use gecko_string_cache::Atom; &gt; #[cfg(feature = "gecko")] &gt;-pub use gecko_string_cache::Namespace; &gt;-#[cfg(feature = "gecko")] &gt; pub use gecko_string_cache::Atom as Prefix; &gt; #[cfg(feature = "gecko")] &gt; pub use gecko_string_cache::Atom as LocalName; &gt;+#[cfg(feature = "gecko")] &gt;+pub use gecko_string_cache::Namespace; &gt; &gt;-#[cfg(feature = "servo")] &gt;-pub use servo_atoms::Atom; &gt;-#[cfg(feature = "servo")] &gt;-pub use html5ever::Prefix; &gt; #[cfg(feature = "servo")] &gt; pub use html5ever::LocalName; &gt; #[cfg(feature = "servo")] &gt; pub use html5ever::Namespace; &gt;+#[cfg(feature = "servo")] &gt;+pub use html5ever::Prefix; &gt;+#[cfg(feature = "servo")] &gt;+pub use servo_atoms::Atom; &gt; &gt; /// The CSS properties supported by the style system. &gt; /// Generated from the properties.mako.rs template by build.rs &gt; #[macro_use] &gt; #[allow(unsafe_code)] &gt; #[deny(missing_docs)] &gt; pub mod properties { &gt; include!(concat!(env!("OUT_DIR"), "/properties.rs")); &gt;@@ -194,17 +194,16 @@ pub mod properties { &gt; #[allow(unsafe_code)] &gt; pub mod gecko; &gt; &gt; // uses a macro from properties &gt; #[cfg(feature = "servo")] &gt; #[allow(unsafe_code)] &gt; pub mod servo; &gt; &gt;- &gt; #[cfg(feature = "gecko")] &gt; #[allow(unsafe_code, missing_docs)] &gt; pub mod gecko_properties { &gt; include!(concat!(env!("OUT_DIR"), "/gecko_properties.rs")); &gt; } &gt; &gt; macro_rules! reexport_computed_values { &gt; ( $( { $name: ident, $boxed: expr } )+ ) =&gt; { &gt;diff --git a/servo/components/style/logical_geometry.rs b/servo/components/style/logical_geometry.rs &gt;index b345c2ad3752..5d12ac21af40 100644 &gt;--- a/servo/components/style/logical_geometry.rs &gt;+++ b/servo/components/style/logical_geometry.rs &gt;@@ -1,16 +1,16 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Geometry in flow-relative space. &gt; &gt;-use euclid::{Point2D, Rect, SideOffsets2D, Size2D}; &gt; use euclid::num::Zero; &gt;+use euclid::{Point2D, Rect, SideOffsets2D, Size2D}; &gt; use properties::style_structs; &gt; use std::cmp::{max, min}; &gt; use std::fmt::{self, Debug, Error, Formatter}; &gt; use std::ops::{Add, Sub}; &gt; use unicode_bidi as bidi; &gt; &gt; pub enum BlockFlowDirection { &gt; TopToBottom, &gt;@@ -43,61 +43,61 @@ impl WritingMode { &gt; /// Return a WritingMode bitflags from the relevant CSS properties. &gt; pub fn new(inheritedbox_style: &amp;style_structs::InheritedBox) -&gt; Self { &gt; use properties::longhands::direction::computed_value::T as Direction; &gt; use properties::longhands::writing_mode::computed_value::T as SpecifiedWritingMode; &gt; &gt; let mut flags = WritingMode::empty(); &gt; &gt; match inheritedbox_style.clone_direction() { &gt;- Direction::Ltr =&gt; {}, &gt;+ Direction::Ltr =&gt; {} &gt; Direction::Rtl =&gt; { &gt; flags.insert(WritingMode::RTL); &gt;- }, &gt;+ } &gt; } &gt; &gt; match inheritedbox_style.clone_writing_mode() { &gt;- SpecifiedWritingMode::HorizontalTb =&gt; {}, &gt;+ SpecifiedWritingMode::HorizontalTb =&gt; {} &gt; SpecifiedWritingMode::VerticalRl =&gt; { &gt; flags.insert(WritingMode::VERTICAL); &gt;- }, &gt;+ } &gt; SpecifiedWritingMode::VerticalLr =&gt; { &gt; flags.insert(WritingMode::VERTICAL); &gt; flags.insert(WritingMode::VERTICAL_LR); &gt;- }, &gt;+ } &gt; #[cfg(feature = "gecko")] &gt; SpecifiedWritingMode::SidewaysRl =&gt; { &gt; flags.insert(WritingMode::VERTICAL); &gt; flags.insert(WritingMode::SIDEWAYS); &gt;- }, &gt;+ } &gt; #[cfg(feature = "gecko")] &gt; SpecifiedWritingMode::SidewaysLr =&gt; { &gt; flags.insert(WritingMode::VERTICAL); &gt; flags.insert(WritingMode::VERTICAL_LR); &gt; flags.insert(WritingMode::LINE_INVERTED); &gt; flags.insert(WritingMode::SIDEWAYS); &gt;- }, &gt;+ } &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt; { &gt; use properties::longhands::text_orientation::computed_value::T as TextOrientation; &gt; &gt; // If FLAG_SIDEWAYS is already set, this means writing-mode is &gt; // either sideways-rl or sideways-lr, and for both of these values, &gt; // text-orientation has no effect. &gt; if !flags.intersects(WritingMode::SIDEWAYS) { &gt; match inheritedbox_style.clone_text_orientation() { &gt;- TextOrientation::Mixed =&gt; {}, &gt;+ TextOrientation::Mixed =&gt; {} &gt; TextOrientation::Upright =&gt; { &gt; flags.insert(WritingMode::UPRIGHT); &gt;- }, &gt;+ } &gt; TextOrientation::Sideways =&gt; { &gt; flags.insert(WritingMode::SIDEWAYS); &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; flags &gt; } &gt; &gt; #[inline] &gt;@@ -952,18 +952,20 @@ impl&lt;T: Copy&gt; LogicalMargin&lt;T&gt; { &gt; LogicalMargin::from_physical(mode_to, self.to_physical(mode_from)) &gt; } &gt; } &gt; } &gt; &gt; impl&lt;T: PartialEq + Zero&gt; LogicalMargin&lt;T&gt; { &gt; #[inline] &gt; pub fn is_zero(&amp;self) -&gt; bool { &gt;- self.block_start == Zero::zero() &amp;&amp; self.inline_end == Zero::zero() &amp;&amp; &gt;- self.block_end == Zero::zero() &amp;&amp; self.inline_start == Zero::zero() &gt;+ self.block_start == Zero::zero() &gt;+ &amp;&amp; self.inline_end == Zero::zero() &gt;+ &amp;&amp; self.block_end == Zero::zero() &gt;+ &amp;&amp; self.inline_start == Zero::zero() &gt; } &gt; } &gt; &gt; impl&lt;T: Copy + Add&lt;T, Output = T&gt;&gt; LogicalMargin&lt;T&gt; { &gt; #[inline] &gt; pub fn inline_start_end(&amp;self) -&gt; T { &gt; self.inline_start + self.inline_end &gt; } &gt;diff --git a/servo/components/style/macros.rs b/servo/components/style/macros.rs &gt;index 671ba35b8bc0..588893893365 100644 &gt;--- a/servo/components/style/macros.rs &gt;+++ b/servo/components/style/macros.rs &gt;@@ -63,19 +63,29 @@ macro_rules! try_match_ident_ignore_ascii_case { &gt; )) &gt; } &gt; }} &gt; } &gt; &gt; macro_rules! define_keyword_type { &gt; ($name:ident, $css:expr) =&gt; { &gt; #[allow(missing_docs)] &gt;- #[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, &gt;- ToComputedValue, ToCss)] &gt;+ #[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+ )] &gt; pub struct $name; &gt; &gt; impl fmt::Debug for $name { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; f.write_str($css) &gt; } &gt; } &gt; &gt;diff --git a/servo/components/style/matching.rs b/servo/components/style/matching.rs &gt;index 6f239d361d86..4684da864f41 100644 &gt;--- a/servo/components/style/matching.rs &gt;+++ b/servo/components/style/matching.rs &gt;@@ -7,18 +7,18 @@ &gt; #![allow(unsafe_code)] &gt; #![deny(missing_docs)] &gt; &gt; use context::{ElementCascadeInputs, QuirksMode, SelectorFlagsMap}; &gt; use context::{SharedStyleContext, StyleContext}; &gt; use data::ElementData; &gt; use dom::TElement; &gt; use invalidation::element::restyle_hints::RestyleHint; &gt;-use properties::ComputedValues; &gt; use properties::longhands::display::computed_value::T as Display; &gt;+use properties::ComputedValues; &gt; use rule_tree::{CascadeLevel, StrongRuleNode}; &gt; use selector_parser::{PseudoElement, RestyleDamage}; &gt; use selectors::matching::ElementSelectorFlags; &gt; use servo_arc::{Arc, ArcBorrow}; &gt; use style_resolver::ResolvedElementStyles; &gt; use traversal_flags::TraversalFlags; &gt; &gt; /// Represents the result of comparing an element's old and new style. &gt;@@ -92,18 +92,18 @@ trait PrivateMatchMethods: TElement { &gt; context: &amp;mut StyleContext&lt;Self&gt;, &gt; cascade_visited: CascadeVisitedMode, &gt; cascade_inputs: &amp;mut ElementCascadeInputs, &gt; ) -&gt; bool { &gt; use properties::PropertyDeclarationBlock; &gt; use shared_lock::Locked; &gt; &gt; debug_assert!( &gt;- replacements.intersects(RestyleHint::replacements()) &amp;&amp; &gt;- (replacements &amp; !RestyleHint::replacements()).is_empty() &gt;+ replacements.intersects(RestyleHint::replacements()) &gt;+ &amp;&amp; (replacements &amp; !RestyleHint::replacements()).is_empty() &gt; ); &gt; &gt; let stylist = &amp;context.shared.stylist; &gt; let guards = &amp;context.shared.guards; &gt; &gt; let primary_rules = match cascade_visited { &gt; CascadeVisitedMode::Unvisited =&gt; cascade_inputs.primary.rules.as_mut(), &gt; CascadeVisitedMode::Visited =&gt; cascade_inputs.primary.visited_rules.as_mut(), &gt;@@ -351,20 +351,19 @@ trait PrivateMatchMethods: TElement { &gt; // Bug 868975: These steps should examine and update the visited styles &gt; // in addition to the unvisited styles. &gt; &gt; let mut tasks = UpdateAnimationsTasks::empty(); &gt; if self.needs_animations_update(context, old_values.as_ref().map(|s| &amp;**s), new_values) { &gt; tasks.insert(UpdateAnimationsTasks::CSS_ANIMATIONS); &gt; } &gt; &gt;- let before_change_style = if self.might_need_transitions_update( &gt;- old_values.as_ref().map(|s| &amp;**s), &gt;- new_values, &gt;- ) { &gt;+ let before_change_style = if self &gt;+ .might_need_transitions_update(old_values.as_ref().map(|s| &amp;**s), new_values) &gt;+ { &gt; let after_change_style = if self.has_css_transitions() { &gt; self.after_change_style(context, new_values) &gt; } else { &gt; None &gt; }; &gt; &gt; // In order to avoid creating a SequentialTask for transitions which &gt; // may not be updated, we check it per property to make sure Gecko &gt;@@ -464,19 +463,21 @@ trait PrivateMatchMethods: TElement { &gt; &amp;self, &gt; shared_context: &amp;SharedStyleContext, &gt; damage: &amp;mut RestyleDamage, &gt; old_values: &amp;ComputedValues, &gt; new_values: &amp;ComputedValues, &gt; pseudo: Option&lt;&amp;PseudoElement&gt;, &gt; ) -&gt; ChildCascadeRequirement { &gt; debug!("accumulate_damage_for: {:?}", self); &gt;- debug_assert!(!shared_context &gt;- .traversal_flags &gt;- .contains(TraversalFlags::Forgetful)); &gt;+ debug_assert!( &gt;+ !shared_context &gt;+ .traversal_flags &gt;+ .contains(TraversalFlags::Forgetful) &gt;+ ); &gt; &gt; let difference = self.compute_style_difference(old_values, new_values, pseudo); &gt; &gt; *damage |= difference.damage; &gt; &gt; debug!(" &gt; style difference: {:?}", difference); &gt; &gt; // We need to cascade the children in order to ensure the correct &gt;@@ -492,17 +493,17 @@ trait PrivateMatchMethods: TElement { &gt; match difference.change { &gt; StyleChange::Unchanged =&gt; return ChildCascadeRequirement::CanSkipCascade, &gt; StyleChange::Changed { reset_only } =&gt; { &gt; // If inherited properties changed, the best we can do is &gt; // cascade the children. &gt; if !reset_only { &gt; return ChildCascadeRequirement::MustCascadeChildren; &gt; } &gt;- }, &gt;+ } &gt; } &gt; &gt; let old_display = old_values.get_box().clone_display(); &gt; let new_display = new_values.get_box().clone_display(); &gt; &gt; // If we used to be a display: none element, and no longer are, &gt; // our children need to be restyled because they're unstyled. &gt; // &gt;@@ -768,33 +769,33 @@ pub trait MatchMethods: TElement { &gt; (&amp;Some(ref old), &amp;Some(ref new)) =&gt; { &gt; self.accumulate_damage_for( &gt; context.shared, &gt; &amp;mut data.damage, &gt; old, &gt; new, &gt; Some(&amp;PseudoElement::from_eager_index(i)), &gt; ); &gt;- }, &gt;- (&amp;None, &amp;None) =&gt; {}, &gt;+ } &gt;+ (&amp;None, &amp;None) =&gt; {} &gt; _ =&gt; { &gt; // It's possible that we're switching from not having &gt; // ::before/::after at all to having styles for them but not &gt; // actually having a useful pseudo-element. Check for that &gt; // case. &gt; let pseudo = PseudoElement::from_eager_index(i); &gt; let new_pseudo_should_exist = &gt; new.as_ref().map_or(false, |s| pseudo.should_exist(s)); &gt; let old_pseudo_should_exist = &gt; old.as_ref().map_or(false, |s| pseudo.should_exist(s)); &gt; if new_pseudo_should_exist != old_pseudo_should_exist { &gt; data.damage |= RestyleDamage::reconstruct(); &gt; return cascade_requirement; &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; cascade_requirement &gt; } &gt; &gt; /// Applies selector flags to an element, deferring mutations of the parent &gt; /// until after the traversal. &gt;diff --git a/servo/components/style/media_queries/media_condition.rs b/servo/components/style/media_queries/media_condition.rs &gt;index dbd677d0aee4..55e8779167b4 100644 &gt;--- a/servo/components/style/media_queries/media_condition.rs &gt;+++ b/servo/components/style/media_queries/media_condition.rs &gt;@@ -1,22 +1,22 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! A media query condition: &gt; //! &gt; //! https://drafts.csswg.org/mediaqueries-4/#typedef-media-condition &gt; &gt;+use super::{Device, MediaFeatureExpression}; &gt; use context::QuirksMode; &gt; use cssparser::{Parser, Token}; &gt; use parser::ParserContext; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt;-use super::{Device, MediaFeatureExpression}; &gt; &gt; /// A binary `and` or `or` operator. &gt; #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)] &gt; #[allow(missing_docs)] &gt; pub enum Operator { &gt; And, &gt; Or, &gt; } &gt;@@ -99,24 +99,22 @@ impl MediaCondition { &gt; allow_or: AllowOr, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let location = input.current_source_location(); &gt; &gt; // FIXME(emilio): This can be cleaner with nll. &gt; let is_negation = match *input.next()? { &gt; Token::ParenthesisBlock =&gt; false, &gt; Token::Ident(ref ident) if ident.eq_ignore_ascii_case("not") =&gt; true, &gt;- ref t =&gt; { &gt;- return Err(location.new_unexpected_token_error(t.clone())) &gt;- } &gt;+ ref t =&gt; return Err(location.new_unexpected_token_error(t.clone())), &gt; }; &gt; &gt; if is_negation { &gt; let inner_condition = Self::parse_in_parens(context, input)?; &gt;- return Ok(MediaCondition::Not(Box::new(inner_condition))) &gt;+ return Ok(MediaCondition::Not(Box::new(inner_condition))); &gt; } &gt; &gt; // ParenthesisBlock. &gt; let first_condition = Self::parse_paren_block(context, input)?; &gt; let operator = match input.try(Operator::parse) { &gt; Ok(op) =&gt; op, &gt; Err(..) =&gt; return Ok(first_condition), &gt; }; &gt;@@ -157,35 +155,31 @@ impl MediaCondition { &gt; &gt; fn parse_paren_block&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; input.parse_nested_block(|input| { &gt; // Base case. &gt; if let Ok(inner) = input.try(|i| Self::parse(context, i)) { &gt;- return Ok(MediaCondition::InParens(Box::new(inner))) &gt;+ return Ok(MediaCondition::InParens(Box::new(inner))); &gt; } &gt; let expr = MediaFeatureExpression::parse_in_parenthesis_block(context, input)?; &gt; Ok(MediaCondition::Feature(expr)) &gt; }) &gt; } &gt; &gt; /// Whether this condition matches the device and quirks mode. &gt; pub fn matches(&amp;self, device: &amp;Device, quirks_mode: QuirksMode) -&gt; bool { &gt; match *self { &gt; MediaCondition::Feature(ref f) =&gt; f.matches(device, quirks_mode), &gt; MediaCondition::InParens(ref c) =&gt; c.matches(device, quirks_mode), &gt; MediaCondition::Not(ref c) =&gt; !c.matches(device, quirks_mode), &gt; MediaCondition::Operation(ref conditions, op) =&gt; { &gt; let mut iter = conditions.iter(); &gt; match op { &gt;- Operator::And =&gt; { &gt;- iter.all(|c| c.matches(device, quirks_mode)) &gt;- } &gt;- Operator::Or =&gt; { &gt;- iter.any(|c| c.matches(device, quirks_mode)) &gt;- } &gt;+ Operator::And =&gt; iter.all(|c| c.matches(device, quirks_mode)), &gt;+ Operator::Or =&gt; iter.any(|c| c.matches(device, quirks_mode)), &gt; } &gt; } &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/style/media_queries/media_feature.rs b/servo/components/style/media_queries/media_feature.rs &gt;index 7c0bfc12bef4..82ec236a87d0 100644 &gt;--- a/servo/components/style/media_queries/media_feature.rs &gt;+++ b/servo/components/style/media_queries/media_feature.rs &gt;@@ -1,23 +1,23 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Media features. &gt; &gt;-use super::Device; &gt; use super::media_feature_expression::{AspectRatio, RangeOrOperator}; &gt;+use super::Device; &gt; &gt;-use Atom; &gt; use cssparser::Parser; &gt; use parser::ParserContext; &gt; use std::fmt; &gt; use style_traits::ParseError; &gt; use values::computed::{CSSPixelLength, Resolution}; &gt;+use Atom; &gt; &gt; /// A generic discriminant for an enum value. &gt; pub type KeywordDiscriminant = u8; &gt; &gt; type MediaFeatureEvaluator&lt;T&gt; = fn( &gt; device: &amp;Device, &gt; // null == no value was given in the query. &gt; value: Option&lt;T&gt;, &gt;@@ -26,20 +26,19 @@ type MediaFeatureEvaluator&lt;T&gt; = fn( &gt; &gt; /// Serializes a given discriminant. &gt; /// &gt; /// FIXME(emilio): we could prevent this allocation if the ToCss code would &gt; /// generate a method for keywords to get the static string or something. &gt; pub type KeywordSerializer = fn(KeywordDiscriminant) -&gt; String; &gt; &gt; /// Parses a given identifier. &gt;-pub type KeywordParser = for &lt;'a, 'i, 't&gt; fn( &gt;- context: &amp;'a ParserContext, &gt;- input: &amp;'a mut Parser&lt;'i, 't&gt;, &gt;-) -&gt; Result&lt;KeywordDiscriminant, ParseError&lt;'i&gt;&gt;; &gt;+pub type KeywordParser = &gt;+ for&lt;'a, 'i, 't&gt; fn(context: &amp;'a ParserContext, input: &amp;'a mut Parser&lt;'i, 't&gt;) &gt;+ -&gt; Result&lt;KeywordDiscriminant, ParseError&lt;'i&gt;&gt;; &gt; &gt; /// An evaluator for a given media feature. &gt; /// &gt; /// This determines the kind of values that get parsed, too. &gt; #[allow(missing_docs)] &gt; pub enum Evaluator { &gt; Length(MediaFeatureEvaluator&lt;CSSPixelLength&gt;), &gt; Integer(MediaFeatureEvaluator&lt;u32&gt;), &gt;@@ -66,60 +65,59 @@ pub enum Evaluator { &gt; } &gt; &gt; /// A simple helper macro to create a keyword evaluator. &gt; /// &gt; /// This assumes that keyword feature expressions don't accept ranges, and &gt; /// asserts if that's not true. As of today there's nothing like that (does that &gt; /// even make sense?). &gt; macro_rules! keyword_evaluator { &gt;- ($actual_evaluator:ident, $keyword_type:ty) =&gt; { &gt;- { &gt;- fn __parse&lt;'i, 't&gt;( &gt;- context: &amp;$crate::parser::ParserContext, &gt;- input: &amp;mut $crate::cssparser::Parser&lt;'i, 't&gt;, &gt;- ) -&gt; Result&lt; &gt;- $crate::media_queries::media_feature::KeywordDiscriminant, &gt;- ::style_traits::ParseError&lt;'i&gt;, &gt;- &gt; { &gt;- let kw = &lt;$keyword_type as $crate::parser::Parse&gt;::parse(context, input)?; &gt;- Ok(kw as $crate::media_queries::media_feature::KeywordDiscriminant) &gt;- } &gt;+ ($actual_evaluator:ident, $keyword_type:ty) =&gt; {{ &gt;+ fn __parse&lt;'i, 't&gt;( &gt;+ context: &amp;$crate::parser::ParserContext, &gt;+ input: &amp;mut $crate::cssparser::Parser&lt;'i, 't&gt;, &gt;+ ) -&gt; Result&lt; &gt;+ $crate::media_queries::media_feature::KeywordDiscriminant, &gt;+ ::style_traits::ParseError&lt;'i&gt;, &gt;+ &gt; { &gt;+ let kw = &lt;$keyword_type as $crate::parser::Parse&gt;::parse(context, input)?; &gt;+ Ok(kw as $crate::media_queries::media_feature::KeywordDiscriminant) &gt;+ } &gt; &gt;- fn __serialize(kw: $crate::media_queries::media_feature::KeywordDiscriminant) -&gt; String { &gt;- // This unwrap is ok because the only discriminants that get &gt;- // back to us is the ones that `parse` produces. &gt;- let value: $keyword_type = &gt;- ::num_traits::cast::FromPrimitive::from_u8(kw).unwrap(); &gt;- &lt;$keyword_type as ::style_traits::ToCss&gt;::to_css_string(&amp;value) &gt;- } &gt;+ fn __serialize(kw: $crate::media_queries::media_feature::KeywordDiscriminant) -&gt; String { &gt;+ // This unwrap is ok because the only discriminants that get &gt;+ // back to us is the ones that `parse` produces. &gt;+ let value: $keyword_type = ::num_traits::cast::FromPrimitive::from_u8(kw).unwrap(); &gt;+ &lt;$keyword_type as ::style_traits::ToCss&gt;::to_css_string(&amp;value) &gt;+ } &gt; &gt;- fn __evaluate( &gt;- device: &amp;$crate::media_queries::Device, &gt;- value: Option&lt;$crate::media_queries::media_feature::KeywordDiscriminant&gt;, &gt;- range_or_operator: Option&lt;$crate::media_queries::media_feature_expression::RangeOrOperator&gt;, &gt;- ) -&gt; bool { &gt;- debug_assert!( &gt;- range_or_operator.is_none(), &gt;- "Since when do keywords accept ranges?" &gt;- ); &gt;- // This unwrap is ok because the only discriminants that get &gt;- // back to us is the ones that `parse` produces. &gt;- let value: Option&lt;$keyword_type&gt; = &gt;- value.map(|kw| ::num_traits::cast::FromPrimitive::from_u8(kw).unwrap()); &gt;- $actual_evaluator(device, value) &gt;- } &gt;+ fn __evaluate( &gt;+ device: &amp;$crate::media_queries::Device, &gt;+ value: Option&lt;$crate::media_queries::media_feature::KeywordDiscriminant&gt;, &gt;+ range_or_operator: Option&lt; &gt;+ $crate::media_queries::media_feature_expression::RangeOrOperator, &gt;+ &gt;, &gt;+ ) -&gt; bool { &gt;+ debug_assert!( &gt;+ range_or_operator.is_none(), &gt;+ "Since when do keywords accept ranges?" &gt;+ ); &gt;+ // This unwrap is ok because the only discriminants that get &gt;+ // back to us is the ones that `parse` produces. &gt;+ let value: Option&lt;$keyword_type&gt; = &gt;+ value.map(|kw| ::num_traits::cast::FromPrimitive::from_u8(kw).unwrap()); &gt;+ $actual_evaluator(device, value) &gt;+ } &gt; &gt;- $crate::media_queries::media_feature::Evaluator::Enumerated { &gt;- parser: __parse, &gt;- serializer: __serialize, &gt;- evaluator: __evaluate, &gt;- } &gt;+ $crate::media_queries::media_feature::Evaluator::Enumerated { &gt;+ parser: __parse, &gt;+ serializer: __serialize, &gt;+ evaluator: __evaluate, &gt; } &gt;- } &gt;+ }}; &gt; } &gt; &gt; bitflags! { &gt; /// Different requirements or toggles that change how a expression is &gt; /// parsed. &gt; pub struct ParsingRequirements: u8 { &gt; /// The feature should only be parsed in chrome and ua sheets. &gt; const CHROME_AND_UA_ONLY = 1 &lt;&lt; 0; &gt;diff --git a/servo/components/style/media_queries/media_feature_expression.rs b/servo/components/style/media_queries/media_feature_expression.rs &gt;index 81bbb69c1a10..853cae35957a 100644 &gt;--- a/servo/components/style/media_queries/media_feature_expression.rs &gt;+++ b/servo/components/style/media_queries/media_feature_expression.rs &gt;@@ -1,32 +1,32 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Parsing for media feature expressions, like `(foo: bar)` or &gt; //! `(width &gt;= 400px)`. &gt; &gt;-use super::Device; &gt; use super::media_feature::{Evaluator, MediaFeatureDescription}; &gt;-use super::media_feature::{ParsingRequirements, KeywordDiscriminant}; &gt;+use super::media_feature::{KeywordDiscriminant, ParsingRequirements}; &gt;+use super::Device; &gt; &gt;-use Atom; &gt;-use cssparser::{Parser, Token}; &gt; use context::QuirksMode; &gt;+use cssparser::{Parser, Token}; &gt; use num_traits::Zero; &gt; use parser::{Parse, ParserContext}; &gt;-use std::cmp::{PartialOrd, Ordering}; &gt;+use std::cmp::{Ordering, PartialOrd}; &gt; use std::fmt::{self, Write}; &gt; use str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase}; &gt; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt; use stylesheets::Origin; &gt;-use values::{serialize_atom_identifier, CSSFloat}; &gt;-use values::specified::{Integer, Length, Number, Resolution}; &gt; use values::computed::{self, ToComputedValue}; &gt;+use values::specified::{Integer, Length, Number, Resolution}; &gt;+use values::{serialize_atom_identifier, CSSFloat}; &gt;+use Atom; &gt; &gt; #[cfg(feature = "gecko")] &gt; use gecko_bindings::structs; &gt; &gt; #[cfg(feature = "gecko")] &gt; use gecko::media_features::MEDIA_FEATURES; &gt; #[cfg(feature = "servo")] &gt; use servo::media_queries::MEDIA_FEATURES; &gt;@@ -104,37 +104,29 @@ pub enum RangeOrOperator { &gt; Range(Range), &gt; /// An `Operator`. &gt; Operator(Operator), &gt; } &gt; &gt; impl RangeOrOperator { &gt; /// Evaluate a given range given an optional query value and a value from &gt; /// the browser. &gt;- pub fn evaluate&lt;T&gt;( &gt;- range_or_op: Option&lt;Self&gt;, &gt;- query_value: Option&lt;T&gt;, &gt;- value: T, &gt;- ) -&gt; bool &gt;+ pub fn evaluate&lt;T&gt;(range_or_op: Option&lt;Self&gt;, query_value: Option&lt;T&gt;, value: T) -&gt; bool &gt; where &gt;- T: PartialOrd + Zero &gt;+ T: PartialOrd + Zero, &gt; { &gt; match query_value { &gt; Some(v) =&gt; Self::evaluate_with_query_value(range_or_op, v, value), &gt; None =&gt; !value.is_zero(), &gt; } &gt; } &gt; &gt; /// Evaluate a given range given a non-optional query value and a value from &gt; /// the browser. &gt;- pub fn evaluate_with_query_value&lt;T&gt;( &gt;- range_or_op: Option&lt;Self&gt;, &gt;- query_value: T, &gt;- value: T, &gt;- ) -&gt; bool &gt;+ pub fn evaluate_with_query_value&lt;T&gt;(range_or_op: Option&lt;Self&gt;, query_value: T, value: T) -&gt; bool &gt; where &gt; T: PartialOrd, &gt; { &gt; let cmp = match value.partial_cmp(&amp;query_value) { &gt; Some(c) =&gt; c, &gt; None =&gt; return false, &gt; }; &gt; &gt;@@ -145,58 +137,56 @@ impl RangeOrOperator { &gt; &gt; match range_or_op { &gt; RangeOrOperator::Range(range) =&gt; { &gt; cmp == Ordering::Equal || match range { &gt; Range::Min =&gt; cmp == Ordering::Greater, &gt; Range::Max =&gt; cmp == Ordering::Less, &gt; } &gt; } &gt;- RangeOrOperator::Operator(op) =&gt; { &gt;- match op { &gt;- Operator::Equal =&gt; cmp == Ordering::Equal, &gt;- Operator::GreaterThan =&gt; cmp == Ordering::Greater, &gt;- Operator::GreaterThanEqual =&gt; { &gt;- cmp == Ordering::Equal || cmp == Ordering::Greater &gt;- } &gt;- Operator::LessThan =&gt; cmp == Ordering::Less, &gt;- Operator::LessThanEqual =&gt; { &gt;- cmp == Ordering::Equal || cmp == Ordering::Less &gt;- } &gt;- } &gt;- } &gt;+ RangeOrOperator::Operator(op) =&gt; match op { &gt;+ Operator::Equal =&gt; cmp == Ordering::Equal, &gt;+ Operator::GreaterThan =&gt; cmp == Ordering::Greater, &gt;+ Operator::GreaterThanEqual =&gt; cmp == Ordering::Equal || cmp == Ordering::Greater, &gt;+ Operator::LessThan =&gt; cmp == Ordering::Less, &gt;+ Operator::LessThanEqual =&gt; cmp == Ordering::Equal || cmp == Ordering::Less, &gt;+ }, &gt; } &gt; } &gt; } &gt; &gt; /// A feature expression contains a reference to the media feature, the value &gt; /// the media query contained, and the range to evaluate. &gt; #[derive(Clone, Debug, MallocSizeOf)] &gt; pub struct MediaFeatureExpression { &gt; feature: &amp;'static MediaFeatureDescription, &gt; value: Option&lt;MediaExpressionValue&gt;, &gt; range_or_operator: Option&lt;RangeOrOperator&gt;, &gt; } &gt; &gt; impl PartialEq for MediaFeatureExpression { &gt; fn eq(&amp;self, other: &amp;Self) -&gt; bool { &gt;- self.feature as *const _ == other.feature as *const _ &amp;&amp; &gt;- self.value == other.value &amp;&amp; &gt;- self.range_or_operator == other.range_or_operator &gt;+ self.feature as *const _ == other.feature as *const _ &gt;+ &amp;&amp; self.value == other.value &gt;+ &amp;&amp; self.range_or_operator == other.range_or_operator &gt; } &gt; } &gt; &gt; impl ToCss for MediaFeatureExpression { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: fmt::Write, &gt; { &gt; dest.write_str("(")?; &gt; &gt;- if self.feature.requirements.contains(ParsingRequirements::WEBKIT_PREFIX) { &gt;+ if self &gt;+ .feature &gt;+ .requirements &gt;+ .contains(ParsingRequirements::WEBKIT_PREFIX) &gt;+ { &gt; dest.write_str("-webkit-")?; &gt; } &gt; &gt; if let Some(RangeOrOperator::Range(range)) = self.range_or_operator { &gt; match range { &gt; Range::Min =&gt; dest.write_str("min-")?, &gt; Range::Max =&gt; dest.write_str("max-")?, &gt; } &gt;@@ -217,19 +207,17 @@ impl ToCss for MediaFeatureExpression { &gt; val.to_css(dest, self)?; &gt; } &gt; &gt; dest.write_str(")") &gt; } &gt; } &gt; &gt; /// Consumes an operation or a colon, or returns an error. &gt;-fn consume_operation_or_colon( &gt;- input: &amp;mut Parser, &gt;-) -&gt; Result&lt;Option&lt;Operator&gt;, ()&gt; { &gt;+fn consume_operation_or_colon(input: &amp;mut Parser) -&gt; Result&lt;Option&lt;Operator&gt;, ()&gt; { &gt; let first_delim = { &gt; let next_token = match input.next() { &gt; Ok(t) =&gt; t, &gt; Err(..) =&gt; return Err(()), &gt; }; &gt; &gt; match *next_token { &gt; Token::Colon =&gt; return Ok(None), &gt;@@ -258,32 +246,34 @@ fn consume_operation_or_colon( &gt; } &gt; &gt; impl MediaFeatureExpression { &gt; fn new( &gt; feature: &amp;'static MediaFeatureDescription, &gt; value: Option&lt;MediaExpressionValue&gt;, &gt; range_or_operator: Option&lt;RangeOrOperator&gt;, &gt; ) -&gt; Self { &gt;- Self { feature, value, range_or_operator } &gt;+ Self { &gt;+ feature, &gt;+ value, &gt;+ range_or_operator, &gt;+ } &gt; } &gt; &gt; /// Parse a media expression of the form: &gt; /// &gt; /// ``` &gt; /// (media-feature: media-value) &gt; /// ``` &gt; pub fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; input.expect_parenthesis_block()?; &gt;- input.parse_nested_block(|input| { &gt;- Self::parse_in_parenthesis_block(context, input) &gt;- }) &gt;+ input.parse_nested_block(|input| Self::parse_in_parenthesis_block(context, input)) &gt; } &gt; &gt; /// Parse a media feature expression where we've already consumed the &gt; /// parenthesis. &gt; pub fn parse_in_parenthesis_block&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt;@@ -291,36 +281,36 @@ impl MediaFeatureExpression { &gt; let feature; &gt; let range; &gt; { &gt; let location = input.current_source_location(); &gt; let ident = input.expect_ident()?; &gt; &gt; let mut requirements = ParsingRequirements::empty(); &gt; &gt;- if context.chrome_rules_enabled() || &gt;- context.stylesheet_origin == Origin::UserAgent &gt;- { &gt;+ if context.chrome_rules_enabled() || context.stylesheet_origin == Origin::UserAgent { &gt; requirements.insert(ParsingRequirements::CHROME_AND_UA_ONLY); &gt; } &gt; &gt; let result = { &gt; let mut feature_name = &amp;**ident; &gt; &gt; #[cfg(feature = "gecko")] &gt; { &gt;- if unsafe { structs::StaticPrefs_sVarCache_layout_css_prefixes_webkit } &amp;&amp; &gt;- starts_with_ignore_ascii_case(feature_name, "-webkit-") &gt;+ if unsafe { structs::StaticPrefs_sVarCache_layout_css_prefixes_webkit } &gt;+ &amp;&amp; starts_with_ignore_ascii_case(feature_name, "-webkit-") &gt; { &gt; feature_name = &amp;feature_name[8..]; &gt; requirements.insert(ParsingRequirements::WEBKIT_PREFIX); &gt; if unsafe { &gt; structs::StaticPrefs_sVarCache_layout_css_prefixes_device_pixel_ratio_webkit &gt; } { &gt;- requirements.insert(ParsingRequirements::WEBKIT_DEVICE_PIXEL_RATIO_PREF_ENABLED); &gt;+ requirements.insert( &gt;+ ParsingRequirements::WEBKIT_DEVICE_PIXEL_RATIO_PREF_ENABLED, &gt;+ ); &gt; } &gt; } &gt; } &gt; &gt; let range = if starts_with_ignore_ascii_case(feature_name, "min-") { &gt; feature_name = &amp;feature_name[4..]; &gt; Some(Range::Min) &gt; } else if starts_with_ignore_ascii_case(feature_name, "max-") { &gt;@@ -336,22 +326,22 @@ impl MediaFeatureExpression { &gt; None =&gt; Err(()), &gt; } &gt; }; &gt; &gt; match result { &gt; Ok((f, r)) =&gt; { &gt; feature = f; &gt; range = r; &gt;- }, &gt;+ } &gt; Err(()) =&gt; { &gt; return Err(location.new_custom_error( &gt; StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()), &gt; )) &gt;- }, &gt;+ } &gt; } &gt; &gt; if !(feature.requirements &amp; !requirements).is_empty() { &gt; return Err(location.new_custom_error( &gt; StyleParseErrorKind::MediaQueryExpectedFeatureName(ident.clone()), &gt; )); &gt; } &gt; &gt;@@ -367,113 +357,101 @@ impl MediaFeatureExpression { &gt; Err(..) =&gt; { &gt; // If there's no colon, this is a media query of the &gt; // form '(&lt;feature&gt;)', that is, there's no value &gt; // specified. &gt; // &gt; // Gecko doesn't allow ranged expressions without a &gt; // value, so just reject them here too. &gt; if range.is_some() { &gt;- return Err(input.new_custom_error( &gt;- StyleParseErrorKind::RangedExpressionWithNoValue &gt;- )); &gt;+ return Err( &gt;+ input.new_custom_error(StyleParseErrorKind::RangedExpressionWithNoValue) &gt;+ ); &gt; } &gt; &gt; return Ok(Self::new(feature, None, None)); &gt; } &gt; Ok(operator) =&gt; operator, &gt; }; &gt; &gt; let range_or_operator = match range { &gt; Some(range) =&gt; { &gt; if operator.is_some() { &gt;- return Err(input.new_custom_error( &gt;- StyleParseErrorKind::MediaQueryUnexpectedOperator &gt;- )); &gt;+ return Err( &gt;+ input.new_custom_error(StyleParseErrorKind::MediaQueryUnexpectedOperator) &gt;+ ); &gt; } &gt; Some(RangeOrOperator::Range(range)) &gt; } &gt;- None =&gt; { &gt;- match operator { &gt;- Some(operator) =&gt; { &gt;- if !feature.allows_ranges() { &gt;- return Err(input.new_custom_error( &gt;- StyleParseErrorKind::MediaQueryUnexpectedOperator &gt;- )); &gt;- } &gt;- Some(RangeOrOperator::Operator(operator)) &gt;+ None =&gt; match operator { &gt;+ Some(operator) =&gt; { &gt;+ if !feature.allows_ranges() { &gt;+ return Err(input &gt;+ .new_custom_error(StyleParseErrorKind::MediaQueryUnexpectedOperator)); &gt; } &gt;- None =&gt; None, &gt;+ Some(RangeOrOperator::Operator(operator)) &gt; } &gt;- } &gt;+ None =&gt; None, &gt;+ }, &gt; }; &gt; &gt;- let value = &gt;- MediaExpressionValue::parse(feature, context, input).map_err(|err| { &gt;- err.location &gt;- .new_custom_error(StyleParseErrorKind::MediaQueryExpectedFeatureValue) &gt;- })?; &gt;+ let value = MediaExpressionValue::parse(feature, context, input).map_err(|err| { &gt;+ err.location &gt;+ .new_custom_error(StyleParseErrorKind::MediaQueryExpectedFeatureValue) &gt;+ })?; &gt; &gt; Ok(Self::new(feature, Some(value), range_or_operator)) &gt; } &gt; &gt; /// Returns whether this media query evaluates to true for the given device. &gt; pub fn matches(&amp;self, device: &amp;Device, quirks_mode: QuirksMode) -&gt; bool { &gt; let value = self.value.as_ref(); &gt; &gt; macro_rules! expect { &gt; ($variant:ident) =&gt; { &gt;- value.map(|value| { &gt;- match *value { &gt;- MediaExpressionValue::$variant(ref v) =&gt; v, &gt;- _ =&gt; unreachable!("Unexpected MediaExpressionValue"), &gt;- } &gt;+ value.map(|value| match *value { &gt;+ MediaExpressionValue::$variant(ref v) =&gt; v, &gt;+ _ =&gt; unreachable!("Unexpected MediaExpressionValue"), &gt; }) &gt;- } &gt;+ }; &gt; } &gt; &gt; match self.feature.evaluator { &gt; Evaluator::Length(eval) =&gt; { &gt; let computed = expect!(Length).map(|specified| { &gt; computed::Context::for_media_query_evaluation(device, quirks_mode, |context| { &gt; specified.to_computed_value(context) &gt; }) &gt; }); &gt; eval(device, computed, self.range_or_operator) &gt; } &gt; Evaluator::Integer(eval) =&gt; { &gt; eval(device, expect!(Integer).cloned(), self.range_or_operator) &gt; } &gt;- Evaluator::Float(eval) =&gt; { &gt;- eval(device, expect!(Float).cloned(), self.range_or_operator) &gt;- } &gt;+ Evaluator::Float(eval) =&gt; eval(device, expect!(Float).cloned(), self.range_or_operator), &gt; Evaluator::IntRatio(eval) =&gt; { &gt; eval(device, expect!(IntRatio).cloned(), self.range_or_operator) &gt;- }, &gt;+ } &gt; Evaluator::Resolution(eval) =&gt; { &gt; let computed = expect!(Resolution).map(|specified| { &gt; computed::Context::for_media_query_evaluation(device, quirks_mode, |context| { &gt; specified.to_computed_value(context) &gt; }) &gt; }); &gt; eval(device, computed, self.range_or_operator) &gt; } &gt; Evaluator::Enumerated { evaluator, .. } =&gt; { &gt;- evaluator( &gt;- device, &gt;- expect!(Enumerated).cloned(), &gt;- self.range_or_operator, &gt;- ) &gt;- } &gt;- Evaluator::Ident(eval) =&gt; { &gt;- eval(device, expect!(Ident).cloned(), self.range_or_operator) &gt;- } &gt;- Evaluator::BoolInteger(eval) =&gt; { &gt;- eval(device, expect!(BoolInteger).cloned(), self.range_or_operator) &gt;+ evaluator(device, expect!(Enumerated).cloned(), self.range_or_operator) &gt; } &gt;+ Evaluator::Ident(eval) =&gt; eval(device, expect!(Ident).cloned(), self.range_or_operator), &gt;+ Evaluator::BoolInteger(eval) =&gt; eval( &gt;+ device, &gt;+ expect!(BoolInteger).cloned(), &gt;+ self.range_or_operator, &gt;+ ), &gt; } &gt; } &gt; } &gt; &gt; /// A value found or expected in a media expression. &gt; /// &gt; /// FIXME(emilio): How should calc() serialize in the Number / Integer / &gt; /// BoolInteger / IntRatio case, as computed or as specified value? &gt;@@ -499,41 +477,31 @@ pub enum MediaExpressionValue { &gt; /// An enumerated value, defined by the variant keyword table in the &gt; /// feature's `mData` member. &gt; Enumerated(KeywordDiscriminant), &gt; /// An identifier. &gt; Ident(Atom), &gt; } &gt; &gt; impl MediaExpressionValue { &gt;- fn to_css&lt;W&gt;( &gt;- &amp;self, &gt;- dest: &amp;mut CssWriter&lt;W&gt;, &gt;- for_expr: &amp;MediaFeatureExpression, &gt;- ) -&gt; fmt::Result &gt;+ fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;, for_expr: &amp;MediaFeatureExpression) -&gt; fmt::Result &gt; where &gt; W: fmt::Write, &gt; { &gt; match *self { &gt; MediaExpressionValue::Length(ref l) =&gt; l.to_css(dest), &gt; MediaExpressionValue::Integer(v) =&gt; v.to_css(dest), &gt; MediaExpressionValue::Float(v) =&gt; v.to_css(dest), &gt; MediaExpressionValue::BoolInteger(v) =&gt; dest.write_str(if v { "1" } else { "0" }), &gt;- MediaExpressionValue::IntRatio(ratio) =&gt; { &gt;- ratio.to_css(dest) &gt;- }, &gt;+ MediaExpressionValue::IntRatio(ratio) =&gt; ratio.to_css(dest), &gt; MediaExpressionValue::Resolution(ref r) =&gt; r.to_css(dest), &gt; MediaExpressionValue::Ident(ref ident) =&gt; serialize_atom_identifier(ident, dest), &gt;- MediaExpressionValue::Enumerated(value) =&gt; { &gt;- match for_expr.feature.evaluator { &gt;- Evaluator::Enumerated { serializer, .. } =&gt; { &gt;- dest.write_str(&amp;*serializer(value)) &gt;- } &gt;- _ =&gt; unreachable!(), &gt;- } &gt;+ MediaExpressionValue::Enumerated(value) =&gt; match for_expr.feature.evaluator { &gt;+ Evaluator::Enumerated { serializer, .. } =&gt; dest.write_str(&amp;*serializer(value)), &gt;+ _ =&gt; unreachable!(), &gt; }, &gt; } &gt; } &gt; &gt; fn parse&lt;'i, 't&gt;( &gt; for_feature: &amp;MediaFeatureDescription, &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt;@@ -558,20 +526,17 @@ impl MediaExpressionValue { &gt; Evaluator::Float(..) =&gt; { &gt; let number = Number::parse(context, input)?; &gt; MediaExpressionValue::Float(number.get()) &gt; } &gt; Evaluator::IntRatio(..) =&gt; { &gt; let a = Integer::parse_positive(context, input)?; &gt; input.expect_delim('/')?; &gt; let b = Integer::parse_positive(context, input)?; &gt;- MediaExpressionValue::IntRatio(AspectRatio( &gt;- a.value() as u32, &gt;- b.value() as u32 &gt;- )) &gt;+ MediaExpressionValue::IntRatio(AspectRatio(a.value() as u32, b.value() as u32)) &gt; } &gt; Evaluator::Resolution(..) =&gt; { &gt; MediaExpressionValue::Resolution(Resolution::parse(context, input)?) &gt; } &gt; Evaluator::Enumerated { parser, .. } =&gt; { &gt; MediaExpressionValue::Enumerated(parser(context, input)?) &gt; } &gt; Evaluator::Ident(..) =&gt; { &gt;diff --git a/servo/components/style/media_queries/media_list.rs b/servo/components/style/media_queries/media_list.rs &gt;index f8d15df7257d..7a49b14ae38e 100644 &gt;--- a/servo/components/style/media_queries/media_list.rs &gt;+++ b/servo/components/style/media_queries/media_list.rs &gt;@@ -1,22 +1,22 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! A media query list: &gt; //! &gt; //! https://drafts.csswg.org/mediaqueries/#typedef-media-query-list &gt; &gt;+use super::{Device, MediaQuery, Qualifier}; &gt; use context::QuirksMode; &gt; use cssparser::{Delimiter, Parser}; &gt; use cssparser::{ParserInput, Token}; &gt; use error_reporting::ContextualParseError; &gt; use parser::ParserContext; &gt;-use super::{Device, MediaQuery, Qualifier}; &gt; &gt; /// A type that encapsulates a media query list. &gt; #[css(comma, derive_debug)] &gt; #[derive(Clone, MallocSizeOf, ToCss)] &gt; pub struct MediaList { &gt; /// The list of media queries. &gt; #[css(iterable)] &gt; pub media_queries: Vec&lt;MediaQuery&gt;, &gt;@@ -25,42 +25,41 @@ pub struct MediaList { &gt; impl MediaList { &gt; /// Parse a media query list from CSS. &gt; /// &gt; /// Always returns a media query list. If any invalid media query is &gt; /// found, the media query list is only filled with the equivalent of &gt; /// "not all", see: &gt; /// &gt; /// &lt;https://drafts.csswg.org/mediaqueries/#error-handling&gt; &gt;- pub fn parse( &gt;- context: &amp;ParserContext, &gt;- input: &amp;mut Parser, &gt;- ) -&gt; Self { &gt;+ pub fn parse(context: &amp;ParserContext, input: &amp;mut Parser) -&gt; Self { &gt; if input.is_exhausted() { &gt; return Self::empty(); &gt; } &gt; &gt; let mut media_queries = vec![]; &gt; loop { &gt; let start_position = input.position(); &gt; match input.parse_until_before(Delimiter::Comma, |i| MediaQuery::parse(context, i)) { &gt; Ok(mq) =&gt; { &gt; media_queries.push(mq); &gt;- }, &gt;+ } &gt; Err(err) =&gt; { &gt; media_queries.push(MediaQuery::never_matching()); &gt; let location = err.location; &gt;- let error = &gt;- ContextualParseError::InvalidMediaRule(input.slice_from(start_position), err); &gt;+ let error = ContextualParseError::InvalidMediaRule( &gt;+ input.slice_from(start_position), &gt;+ err, &gt;+ ); &gt; context.log_css_error(location, error); &gt;- }, &gt;+ } &gt; } &gt; &gt; match input.next() { &gt;- Ok(&amp;Token::Comma) =&gt; {}, &gt;+ Ok(&amp;Token::Comma) =&gt; {} &gt; Ok(_) =&gt; unreachable!(), &gt; Err(_) =&gt; break, &gt; } &gt; } &gt; &gt; MediaList { media_queries } &gt; } &gt; &gt;@@ -74,18 +73,20 @@ impl MediaList { &gt; /// Evaluate a whole `MediaList` against `Device`. &gt; pub fn evaluate(&amp;self, device: &amp;Device, quirks_mode: QuirksMode) -&gt; bool { &gt; // Check if it is an empty media query list or any queries match. &gt; // https://drafts.csswg.org/mediaqueries-4/#mq-list &gt; self.media_queries.is_empty() || self.media_queries.iter().any(|mq| { &gt; let media_match = mq.media_type.matches(device.media_type()); &gt; &gt; // Check if the media condition match. &gt;- let query_match = media_match &amp;&amp; &gt;- mq.condition.as_ref().map_or(true, |c| c.matches(device, quirks_mode)); &gt;+ let query_match = media_match &amp;&amp; mq &gt;+ .condition &gt;+ .as_ref() &gt;+ .map_or(true, |c| c.matches(device, quirks_mode)); &gt; &gt; // Apply the logical NOT qualifier to the result &gt; match mq.qualifier { &gt; Some(Qualifier::Not) =&gt; !query_match, &gt; _ =&gt; query_match, &gt; } &gt; }) &gt; } &gt;@@ -101,17 +102,17 @@ impl MediaList { &gt; /// Returns true if added, false if fail to parse the medium string. &gt; pub fn append_medium(&amp;mut self, context: &amp;ParserContext, new_medium: &amp;str) -&gt; bool { &gt; let mut input = ParserInput::new(new_medium); &gt; let mut parser = Parser::new(&amp;mut input); &gt; let new_query = match MediaQuery::parse(&amp;context, &amp;mut parser) { &gt; Ok(query) =&gt; query, &gt; Err(_) =&gt; { &gt; return false; &gt;- }, &gt;+ } &gt; }; &gt; // This algorithm doesn't actually matches the current spec, &gt; // but it matches the behavior of Gecko and Edge. &gt; // See https://github.com/w3c/csswg-drafts/issues/697 &gt; self.media_queries.retain(|query| query != &amp;new_query); &gt; self.media_queries.push(new_query); &gt; true &gt; } &gt;@@ -122,15 +123,15 @@ impl MediaList { &gt; /// Returns true if found and deleted, false otherwise. &gt; pub fn delete_medium(&amp;mut self, context: &amp;ParserContext, old_medium: &amp;str) -&gt; bool { &gt; let mut input = ParserInput::new(old_medium); &gt; let mut parser = Parser::new(&amp;mut input); &gt; let old_query = match MediaQuery::parse(context, &amp;mut parser) { &gt; Ok(query) =&gt; query, &gt; Err(_) =&gt; { &gt; return false; &gt;- }, &gt;+ } &gt; }; &gt; let old_len = self.media_queries.len(); &gt; self.media_queries.retain(|query| query != &amp;old_query); &gt; old_len != self.media_queries.len() &gt; } &gt; } &gt;diff --git a/servo/components/style/media_queries/media_query.rs b/servo/components/style/media_queries/media_query.rs &gt;index 089fc9412b24..f2d11ccb58c6 100644 &gt;--- a/servo/components/style/media_queries/media_query.rs &gt;+++ b/servo/components/style/media_queries/media_query.rs &gt;@@ -1,25 +1,24 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! A media query: &gt; //! &gt; //! https://drafts.csswg.org/mediaqueries/#typedef-media-query &gt; &gt;-use Atom; &gt;+use super::media_condition::MediaCondition; &gt; use cssparser::Parser; &gt; use parser::ParserContext; &gt; use std::fmt::{self, Write}; &gt; use str::string_as_ascii_lowercase; &gt; use style_traits::{CssWriter, ParseError, ToCss}; &gt;-use super::media_condition::MediaCondition; &gt; use values::CustomIdent; &gt;- &gt;+use Atom; &gt; &gt; /// &lt;https://drafts.csswg.org/mediaqueries/#mq-prefix&gt; &gt; #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)] &gt; pub enum Qualifier { &gt; /// Hide a media query from legacy UAs: &gt; /// &lt;https://drafts.csswg.org/mediaqueries/#mq-only&gt; &gt; Only, &gt; /// Negate a media query: &gt;@@ -85,17 +84,17 @@ impl ToCss for MediaQuery { &gt; // We need to print "all" if there's a qualifier, or there's &gt; // just an empty list of expressions. &gt; // &gt; // Otherwise, we'd serialize media queries like "(min-width: &gt; // 40px)" in "all (min-width: 40px)", which is unexpected. &gt; if self.qualifier.is_some() || self.condition.is_none() { &gt; dest.write_str("all")?; &gt; } &gt;- }, &gt;+ } &gt; MediaQueryType::Concrete(MediaType(ref desc)) =&gt; desc.to_css(dest)?, &gt; } &gt; &gt; let condition = match self.condition { &gt; Some(ref c) =&gt; c, &gt; None =&gt; return Ok(()), &gt; }; &gt; &gt;@@ -120,33 +119,38 @@ impl MediaQuery { &gt; &gt; /// Parse a media query given css input. &gt; /// &gt; /// Returns an error if any of the expressions is unknown. &gt; pub fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt;- let (qualifier, explicit_media_type) = input.try(|input| -&gt; Result&lt;_, ()&gt; { &gt;- let qualifier = input.try(Qualifier::parse).ok(); &gt;- let ident = input.expect_ident().map_err(|_| ())?; &gt;- let media_type = MediaQueryType::parse(&amp;ident)?; &gt;- Ok((qualifier, Some(media_type))) &gt;- }).unwrap_or_default(); &gt;+ let (qualifier, explicit_media_type) = input &gt;+ .try(|input| -&gt; Result&lt;_, ()&gt; { &gt;+ let qualifier = input.try(Qualifier::parse).ok(); &gt;+ let ident = input.expect_ident().map_err(|_| ())?; &gt;+ let media_type = MediaQueryType::parse(&amp;ident)?; &gt;+ Ok((qualifier, Some(media_type))) &gt;+ }).unwrap_or_default(); &gt; &gt; let condition = if explicit_media_type.is_none() { &gt; Some(MediaCondition::parse(context, input)?) &gt; } else if input.try(|i| i.expect_ident_matching("and")).is_ok() { &gt; Some(MediaCondition::parse_disallow_or(context, input)?) &gt; } else { &gt; None &gt; }; &gt; &gt; let media_type = explicit_media_type.unwrap_or(MediaQueryType::All); &gt;- Ok(Self { qualifier, media_type, condition }) &gt;+ Ok(Self { &gt;+ qualifier, &gt;+ media_type, &gt;+ condition, &gt;+ }) &gt; } &gt; } &gt; &gt; /// &lt;http://dev.w3.org/csswg/mediaqueries-3/#media0&gt; &gt; #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq)] &gt; pub enum MediaQueryType { &gt; /// A media type that matches every device. &gt; All, &gt;diff --git a/servo/components/style/media_queries/mod.rs b/servo/components/style/media_queries/mod.rs &gt;index b59ec32443dc..93a5abf3b011 100644 &gt;--- a/servo/components/style/media_queries/mod.rs &gt;+++ b/servo/components/style/media_queries/mod.rs &gt;@@ -9,16 +9,16 @@ &gt; mod media_condition; &gt; mod media_list; &gt; mod media_query; &gt; #[macro_use] &gt; pub mod media_feature; &gt; pub mod media_feature_expression; &gt; &gt; pub use self::media_condition::MediaCondition; &gt;+pub use self::media_feature_expression::MediaFeatureExpression; &gt; pub use self::media_list::MediaList; &gt; pub use self::media_query::{MediaQuery, MediaQueryType, MediaType, Qualifier}; &gt;-pub use self::media_feature_expression::MediaFeatureExpression; &gt; &gt;-#[cfg(feature = "servo")] &gt;-pub use servo::media_queries::Device; &gt; #[cfg(feature = "gecko")] &gt; pub use gecko::media_queries::Device; &gt;+#[cfg(feature = "servo")] &gt;+pub use servo::media_queries::Device; &gt;diff --git a/servo/components/style/parser.rs b/servo/components/style/parser.rs &gt;index a4b7d8162035..e0476dadccbc 100644 &gt;--- a/servo/components/style/parser.rs &gt;+++ b/servo/components/style/parser.rs &gt;@@ -123,21 +123,17 @@ impl&lt;'a&gt; ParserContext&lt;'a&gt; { &gt; &gt; /// Get the rule type, which assumes that one is available. &gt; pub fn rule_type(&amp;self) -&gt; CssRuleType { &gt; self.rule_type &gt; .expect("Rule type expected, but none was found.") &gt; } &gt; &gt; /// Record a CSS parse error with this context’s error reporting. &gt;- pub fn log_css_error( &gt;- &amp;self, &gt;- location: SourceLocation, &gt;- error: ContextualParseError, &gt;- ) { &gt;+ pub fn log_css_error(&amp;self, location: SourceLocation, error: ContextualParseError) { &gt; let error_reporter = match self.error_reporter { &gt; Some(r) =&gt; r, &gt; None =&gt; return, &gt; }; &gt; &gt; error_reporter.report_error(self.url_data, location, error) &gt; } &gt; &gt;diff --git a/servo/components/style/rule_cache.rs b/servo/components/style/rule_cache.rs &gt;index 5e386d711cb1..ed1cd70b5556 100644 &gt;--- a/servo/components/style/rule_cache.rs &gt;+++ b/servo/components/style/rule_cache.rs &gt;@@ -100,20 +100,20 @@ impl RuleCache { &gt; match node.style_source() { &gt; Some(s) =&gt; match s.as_declarations() { &gt; Some(decls) =&gt; { &gt; let cascade_level = node.cascade_level(); &gt; let decls = decls.read_with(cascade_level.guard(guards)); &gt; if decls.contains_any_reset() { &gt; break; &gt; } &gt;- }, &gt;+ } &gt; None =&gt; break, &gt; }, &gt;- None =&gt; {}, &gt;+ None =&gt; {} &gt; } &gt; rule_node = node.parent(); &gt; } &gt; rule_node &gt; } &gt; &gt; /// Finds a node in the properties matched cache. &gt; /// &gt;diff --git a/servo/components/style/rule_tree/mod.rs b/servo/components/style/rule_tree/mod.rs &gt;index 5414b254aaec..53f9b0c15c14 100644 &gt;--- a/servo/components/style/rule_tree/mod.rs &gt;+++ b/servo/components/style/rule_tree/mod.rs &gt;@@ -235,35 +235,35 @@ impl RuleTree { &gt; if any_important { &gt; found_important = true; &gt; match level { &gt; InnerShadowNormal =&gt; { &gt; debug_assert!( &gt; shadow_cascade_order &gt;= last_cascade_order, &gt; "Not really ordered" &gt; ); &gt;- if shadow_cascade_order &gt; last_cascade_order &amp;&amp; &gt;- !important_inner_shadow.last().unwrap().is_empty() &gt;+ if shadow_cascade_order &gt; last_cascade_order &gt;+ &amp;&amp; !important_inner_shadow.last().unwrap().is_empty() &gt; { &gt; last_cascade_order = shadow_cascade_order; &gt; important_inner_shadow.push(SmallVec::new()); &gt; } &gt; important_inner_shadow &gt; .last_mut() &gt; .unwrap() &gt; .push(source.clone()) &gt;- }, &gt;+ } &gt; SameTreeAuthorNormal =&gt; important_same_tree.push(source.clone()), &gt; UANormal =&gt; important_ua.push(source.clone()), &gt; UserNormal =&gt; important_user.push(source.clone()), &gt; StyleAttributeNormal =&gt; { &gt; debug_assert!(important_style_attr.is_none()); &gt; important_style_attr = Some(source.clone()); &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; }; &gt; } &gt; &gt; // We don't optimize out empty rules, even though we could. &gt; // &gt; // Inspector relies on every rule being inserted in the normal level &gt; // at least once, in order to return the rules with the correct &gt; // specificity order. &gt;@@ -483,17 +483,18 @@ impl RuleTree { &gt; &gt; /// Returns new rule node without rules from declarative animations. &gt; pub fn remove_animation_rules(&amp;self, path: &amp;StrongRuleNode) -&gt; StrongRuleNode { &gt; // Return a clone if there are no animation rules. &gt; if !path.has_animation_or_transition_rules() { &gt; return path.clone(); &gt; } &gt; &gt;- let iter = path.self_and_ancestors() &gt;+ let iter = path &gt;+ .self_and_ancestors() &gt; .take_while(|node| node.cascade_level() &gt;= CascadeLevel::SMILOverride); &gt; let mut last = path; &gt; let mut children = SmallVec::&lt;[_; 10]&gt;::new(); &gt; for node in iter { &gt; if !node.cascade_level().is_animation() { &gt; children.push(( &gt; node.get().source.as_ref().unwrap().clone(), &gt; node.cascade_level(), &gt;@@ -605,47 +606,47 @@ impl CascadeLevel { &gt; pub unsafe fn from_byte(byte: u8) -&gt; Self { &gt; debug_assert!(byte &lt;= CascadeLevel::Transitions as u8); &gt; mem::transmute(byte) &gt; } &gt; &gt; /// Select a lock guard for this level &gt; pub fn guard&lt;'a&gt;(&amp;self, guards: &amp;'a StylesheetGuards&lt;'a&gt;) -&gt; &amp;'a SharedRwLockReadGuard&lt;'a&gt; { &gt; match *self { &gt;- CascadeLevel::UANormal | &gt;- CascadeLevel::UserNormal | &gt;- CascadeLevel::UserImportant | &gt;- CascadeLevel::UAImportant =&gt; guards.ua_or_user, &gt;+ CascadeLevel::UANormal &gt;+ | CascadeLevel::UserNormal &gt;+ | CascadeLevel::UserImportant &gt;+ | CascadeLevel::UAImportant =&gt; guards.ua_or_user, &gt; _ =&gt; guards.author, &gt; } &gt; } &gt; &gt; /// Returns whether this cascade level is unique per element, in which case &gt; /// we can replace the path in the cascade without fear. &gt; pub fn is_unique_per_element(&amp;self) -&gt; bool { &gt; match *self { &gt;- CascadeLevel::Transitions | &gt;- CascadeLevel::Animations | &gt;- CascadeLevel::SMILOverride | &gt;- CascadeLevel::StyleAttributeNormal | &gt;- CascadeLevel::StyleAttributeImportant =&gt; true, &gt;+ CascadeLevel::Transitions &gt;+ | CascadeLevel::Animations &gt;+ | CascadeLevel::SMILOverride &gt;+ | CascadeLevel::StyleAttributeNormal &gt;+ | CascadeLevel::StyleAttributeImportant =&gt; true, &gt; _ =&gt; false, &gt; } &gt; } &gt; &gt; /// Returns whether this cascade level represents important rules of some &gt; /// sort. &gt; #[inline] &gt; pub fn is_important(&amp;self) -&gt; bool { &gt; match *self { &gt;- CascadeLevel::SameTreeAuthorImportant | &gt;- CascadeLevel::InnerShadowImportant | &gt;- CascadeLevel::StyleAttributeImportant | &gt;- CascadeLevel::UserImportant | &gt;- CascadeLevel::UAImportant =&gt; true, &gt;+ CascadeLevel::SameTreeAuthorImportant &gt;+ | CascadeLevel::InnerShadowImportant &gt;+ | CascadeLevel::StyleAttributeImportant &gt;+ | CascadeLevel::UserImportant &gt;+ | CascadeLevel::UAImportant =&gt; true, &gt; _ =&gt; false, &gt; } &gt; } &gt; &gt; /// Returns the importance relevant for this rule. Pretty similar to &gt; /// `is_important`. &gt; #[inline] &gt; pub fn importance(&amp;self) -&gt; Importance { &gt;@@ -657,17 +658,17 @@ impl CascadeLevel { &gt; } &gt; &gt; /// Returns whether this cascade level represents an animation rules. &gt; #[inline] &gt; pub fn is_animation(&amp;self) -&gt; bool { &gt; match *self { &gt; CascadeLevel::SMILOverride | CascadeLevel::Animations | CascadeLevel::Transitions =&gt; { &gt; true &gt;- }, &gt;+ } &gt; _ =&gt; false, &gt; } &gt; } &gt; } &gt; &gt; // The root node never has siblings, but needs a free count. We use the same &gt; // storage for both to save memory. &gt; struct PrevSiblingOrFreeCount(AtomicPtr&lt;RuleNode&gt;); &gt;@@ -724,19 +725,19 @@ pub struct RuleNode { &gt; &gt; unsafe impl Sync for RuleTree {} &gt; unsafe impl Send for RuleTree {} &gt; &gt; // On Gecko builds, hook into the leak checking machinery. &gt; #[cfg(feature = "gecko")] &gt; #[cfg(debug_assertions)] &gt; mod gecko_leak_checking { &gt;+ use super::RuleNode; &gt; use std::mem::size_of; &gt; use std::os::raw::{c_char, c_void}; &gt;- use super::RuleNode; &gt; &gt; extern "C" { &gt; pub fn NS_LogCtor(aPtr: *const c_void, aTypeName: *const c_char, aSize: u32); &gt; pub fn NS_LogDtor(aPtr: *const c_void, aTypeName: *const c_char, aSize: u32); &gt; } &gt; &gt; static NAME: &amp;'static [u8] = b"RuleNode\0"; &gt; &gt;@@ -1101,18 +1102,18 @@ impl StrongRuleNode { &gt; &gt; // FIXME(#14213): Apparently the layout data can be gone from script. &gt; // &gt; // That's... suspicious, but it's fine if it happens for the rule tree &gt; // case, so just don't crash in the case we're doing the final GC in &gt; // script. &gt; &gt; debug_assert!( &gt;- !thread_state::get().is_worker() &amp;&amp; &gt;- (thread_state::get().is_layout() || thread_state::get().is_script()) &gt;+ !thread_state::get().is_worker() &gt;+ &amp;&amp; (thread_state::get().is_layout() || thread_state::get().is_script()) &gt; ); &gt; &gt; let current = me.next_free.load(Ordering::Relaxed); &gt; if current == FREE_LIST_SENTINEL { &gt; return None; &gt; } &gt; &gt; debug_assert!( &gt;@@ -1345,63 +1346,63 @@ impl StrongRuleNode { &gt; match declaration.id() { &gt; PropertyDeclarationId::Longhand(id) =&gt; Some((id, declaration)), &gt; _ =&gt; None, &gt; } &gt; }); &gt; &gt; match node.cascade_level() { &gt; // Non-author rules: &gt;- CascadeLevel::UANormal | &gt;- CascadeLevel::UAImportant | &gt;- CascadeLevel::UserNormal | &gt;- CascadeLevel::UserImportant =&gt; { &gt;+ CascadeLevel::UANormal &gt;+ | CascadeLevel::UAImportant &gt;+ | CascadeLevel::UserNormal &gt;+ | CascadeLevel::UserImportant =&gt; { &gt; for (id, declaration) in longhands { &gt; if properties.contains(id) { &gt; // This property was set by a non-author rule. &gt; // Stop looking for it in this element's rule &gt; // nodes. &gt; properties.remove(id); &gt; &gt; // However, if it is inherited, then it might be &gt; // inherited from an author rule from an &gt; // ancestor element's rule nodes. &gt;- if declaration.get_css_wide_keyword() == &gt;- Some(CSSWideKeyword::Inherit) &gt;+ if declaration.get_css_wide_keyword() &gt;+ == Some(CSSWideKeyword::Inherit) &gt; { &gt; have_explicit_ua_inherit = true; &gt; inherited_properties.insert(id); &gt; } &gt; } &gt; } &gt;- }, &gt;+ } &gt; // Author rules: &gt;- CascadeLevel::PresHints | &gt;- CascadeLevel::SameTreeAuthorNormal | &gt;- CascadeLevel::InnerShadowNormal | &gt;- CascadeLevel::StyleAttributeNormal | &gt;- CascadeLevel::SMILOverride | &gt;- CascadeLevel::Animations | &gt;- CascadeLevel::SameTreeAuthorImportant | &gt;- CascadeLevel::InnerShadowImportant | &gt;- CascadeLevel::StyleAttributeImportant | &gt;- CascadeLevel::Transitions =&gt; { &gt;+ CascadeLevel::PresHints &gt;+ | CascadeLevel::SameTreeAuthorNormal &gt;+ | CascadeLevel::InnerShadowNormal &gt;+ | CascadeLevel::StyleAttributeNormal &gt;+ | CascadeLevel::SMILOverride &gt;+ | CascadeLevel::Animations &gt;+ | CascadeLevel::SameTreeAuthorImportant &gt;+ | CascadeLevel::InnerShadowImportant &gt;+ | CascadeLevel::StyleAttributeImportant &gt;+ | CascadeLevel::Transitions =&gt; { &gt; for (id, declaration) in longhands { &gt; if properties.contains(id) { &gt; if !author_colors_allowed { &gt; if let PropertyDeclaration::BackgroundColor(ref color) = &gt; *declaration &gt; { &gt; return *color == Color::transparent(); &gt; } &gt; } &gt; return true; &gt; } &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; if !have_explicit_ua_inherit { &gt; break; &gt; } &gt; &gt; // Continue to the parent element and search for the inherited properties. &gt;@@ -1447,17 +1448,18 @@ impl StrongRuleNode { &gt; // We want to iterate over cascade levels that override the animations &gt; // level, i.e. !important levels and the transitions level. &gt; // &gt; // However, we actually want to skip the transitions level because &gt; // although it is higher in the cascade than animations, when both &gt; // transitions and animations are present for a given element and &gt; // property, transitions are suppressed so that they don't actually &gt; // override animations. &gt;- let iter = self.self_and_ancestors() &gt;+ let iter = self &gt;+ .self_and_ancestors() &gt; .skip_while(|node| node.cascade_level() == CascadeLevel::Transitions) &gt; .take_while(|node| node.cascade_level() &gt; CascadeLevel::Animations); &gt; let mut result = (LonghandIdSet::new(), false); &gt; for node in iter { &gt; let style = node.style_source().unwrap(); &gt; for (decl, important) in style &gt; .read(node.cascade_level().guard(guards)) &gt; .declaration_importance_iter() &gt;@@ -1554,18 +1556,18 @@ impl Drop for StrongRuleNode { &gt; // here to avoid leaking anything. We use the GC machinery, rather &gt; // than just dropping directly, so that we benefit from the iterative &gt; // destruction and don't trigger unbounded recursion during drop. See &gt; // [1] and the associated crashtest. &gt; // &gt; // [1] https://bugzilla.mozilla.org/show_bug.cgi?id=439184 &gt; if old_head.is_null() { &gt; debug_assert!( &gt;- !thread_state::get().is_worker() &amp;&amp; &gt;- (thread_state::get().is_layout() || thread_state::get().is_script()) &gt;+ !thread_state::get().is_worker() &gt;+ &amp;&amp; (thread_state::get().is_layout() || thread_state::get().is_script()) &gt; ); &gt; // Add the node as the sole entry in the free list. &gt; debug_assert!(node.next_free.load(Ordering::Relaxed).is_null()); &gt; node.next_free.store(FREE_LIST_SENTINEL, Ordering::Relaxed); &gt; free_list.store(node as *const _ as *mut _, Ordering::Relaxed); &gt; &gt; // Invoke the GC. &gt; // &gt;@@ -1609,17 +1611,17 @@ impl Drop for StrongRuleNode { &gt; FREE_LIST_LOCKED, &gt; Ordering::Acquire, &gt; Ordering::Relaxed, &gt; ) { &gt; Ok(..) =&gt; { &gt; if old_head != FREE_LIST_LOCKED { &gt; break; &gt; } &gt;- }, &gt;+ } &gt; Err(new) =&gt; old_head = new, &gt; } &gt; } &gt; &gt; // If other thread has raced with use while using the same rule node, &gt; // just store the old head again, we're done. &gt; // &gt; // Note that we can use relaxed operations for loading since we're &gt;diff --git a/servo/components/style/selector_map.rs b/servo/components/style/selector_map.rs &gt;index 3ab78ce2d87b..f3476e497381 100644 &gt;--- a/servo/components/style/selector_map.rs &gt;+++ b/servo/components/style/selector_map.rs &gt;@@ -1,31 +1,31 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! A data structure to efficiently index structs containing selectors by local &gt; //! name, ids and hash. &gt; &gt;-use {Atom, LocalName, Namespace, WeakAtom}; &gt; use applicable_declarations::ApplicableDeclarationList; &gt; use context::QuirksMode; &gt; use dom::TElement; &gt; use fallible::FallibleVec; &gt;-use hash::{HashMap, HashSet}; &gt; use hash::map as hash_map; &gt;+use hash::{HashMap, HashSet}; &gt; use hashglobe::FailedAllocationError; &gt; use precomputed_hash::PrecomputedHash; &gt; use rule_tree::{CascadeLevel, ShadowCascadeOrder}; &gt; use selector_parser::SelectorImpl; &gt; use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext}; &gt; use selectors::parser::{Combinator, Component, SelectorIter}; &gt; use smallvec::SmallVec; &gt; use std::hash::{BuildHasherDefault, Hash, Hasher}; &gt; use stylist::Rule; &gt;+use {Atom, LocalName, Namespace, WeakAtom}; &gt; &gt; /// A hasher implementation that doesn't hash anything, because it expects its &gt; /// input to be a suitable u32 hash. &gt; pub struct PrecomputedHasher { &gt; hash: Option&lt;u32&gt;, &gt; } &gt; &gt; impl Default for PrecomputedHasher { &gt;@@ -282,17 +282,19 @@ impl SelectorMap&lt;Rule&gt; { &gt; if matches_selector( &gt; &amp;rule.selector, &gt; 0, &gt; Some(&amp;rule.hashes), &gt; &amp;element, &gt; context, &gt; flags_setter, &gt; ) { &gt;- matching_rules.push(rule.to_applicable_declaration_block(cascade_level, shadow_cascade_order)); &gt;+ matching_rules.push( &gt;+ rule.to_applicable_declaration_block(cascade_level, shadow_cascade_order), &gt;+ ); &gt; } &gt; } &gt; } &gt; } &gt; &gt; impl&lt;T: SelectorMapEntry&gt; SelectorMap&lt;T&gt; { &gt; /// Inserts into the correct hash, trying id, class, localname and &gt; /// namespace. &gt;@@ -300,20 +302,22 @@ impl&lt;T: SelectorMapEntry&gt; SelectorMap&lt;T&gt; { &gt; &amp;mut self, &gt; entry: T, &gt; quirks_mode: QuirksMode, &gt; ) -&gt; Result&lt;(), FailedAllocationError&gt; { &gt; self.count += 1; &gt; &gt; let vector = match find_bucket(entry.selector()) { &gt; Bucket::Root =&gt; &amp;mut self.root, &gt;- Bucket::ID(id) =&gt; self.id_hash &gt;+ Bucket::ID(id) =&gt; self &gt;+ .id_hash &gt; .try_entry(id.clone(), quirks_mode)? &gt; .or_insert_with(SmallVec::new), &gt;- Bucket::Class(class) =&gt; self.class_hash &gt;+ Bucket::Class(class) =&gt; self &gt;+ .class_hash &gt; .try_entry(class.clone(), quirks_mode)? &gt; .or_insert_with(SmallVec::new), &gt; Bucket::LocalName { name, lower_name } =&gt; { &gt; // If the local name in the selector isn't lowercase, insert it &gt; // into the rule hash twice. This means that, during lookup, we &gt; // can always find the rules based on the local name of the &gt; // element, regardless of whether it's an html element in an &gt; // html document (in which case we match against lower_name) or &gt;@@ -327,18 +331,19 @@ impl&lt;T: SelectorMapEntry&gt; SelectorMap&lt;T&gt; { &gt; self.local_name_hash &gt; .try_entry(lower_name.clone())? &gt; .or_insert_with(SmallVec::new) &gt; .try_push(entry.clone())?; &gt; } &gt; self.local_name_hash &gt; .try_entry(name.clone())? &gt; .or_insert_with(SmallVec::new) &gt;- }, &gt;- Bucket::Namespace(url) =&gt; self.namespace_hash &gt;+ } &gt;+ Bucket::Namespace(url) =&gt; self &gt;+ .namespace_hash &gt; .try_entry(url.clone())? &gt; .or_insert_with(SmallVec::new), &gt; Bucket::Universal =&gt; &amp;mut self.other, &gt; }; &gt; &gt; vector.try_push(entry) &gt; } &gt; &gt;@@ -485,18 +490,19 @@ fn specific_bucket_for&lt;'a&gt;(component: &amp;'a Component&lt;SelectorImpl&gt;) -&gt; Bucket&lt;'a&gt; &gt; match *component { &gt; Component::Root =&gt; Bucket::Root, &gt; Component::ID(ref id) =&gt; Bucket::ID(id), &gt; Component::Class(ref class) =&gt; Bucket::Class(class), &gt; Component::LocalName(ref selector) =&gt; Bucket::LocalName { &gt; name: &amp;selector.name, &gt; lower_name: &amp;selector.lower_name, &gt; }, &gt;- Component::Namespace(_, ref url) | &gt;- Component::DefaultNamespace(ref url) =&gt; Bucket::Namespace(url), &gt;+ Component::Namespace(_, ref url) | Component::DefaultNamespace(ref url) =&gt; { &gt;+ Bucket::Namespace(url) &gt;+ } &gt; // ::slotted(..) isn't a normal pseudo-element, so we can insert it on &gt; // the rule hash normally without much problem. For example, in a &gt; // selector like: &gt; // &gt; // div::slotted(span)::before &gt; // &gt; // It looks like: &gt; // &gt;@@ -534,28 +540,28 @@ fn find_bucket&lt;'a&gt;(mut iter: SelectorIter&lt;'a, SelectorImpl&gt;) -&gt; Bucket&lt;'a&gt; { &gt; Bucket::Root =&gt; return new_bucket, &gt; Bucket::ID(..) =&gt; { &gt; current_bucket = new_bucket; &gt; } &gt; Bucket::Class(..) =&gt; { &gt; if !matches!(current_bucket, Bucket::ID(..)) { &gt; current_bucket = new_bucket; &gt; } &gt;- }, &gt;+ } &gt; Bucket::LocalName { .. } =&gt; { &gt; if matches!(current_bucket, Bucket::Universal | Bucket::Namespace(..)) { &gt; current_bucket = new_bucket; &gt; } &gt;- }, &gt;+ } &gt; Bucket::Namespace(..) =&gt; { &gt; if matches!(current_bucket, Bucket::Universal) { &gt; current_bucket = new_bucket; &gt; } &gt; } &gt;- Bucket::Universal =&gt; {}, &gt;+ Bucket::Universal =&gt; {} &gt; } &gt; } &gt; &gt; // Effectively, pseudo-elements are ignored, given only state &gt; // pseudo-classes may appear before them. &gt; if iter.next_sequence() != Some(Combinator::PseudoElement) { &gt; break; &gt; } &gt;diff --git a/servo/components/style/servo/media_queries.rs b/servo/components/style/servo/media_queries.rs &gt;index ba31cfcaf4b3..ef7c70bae570 100644 &gt;--- a/servo/components/style/servo/media_queries.rs &gt;+++ b/servo/components/style/servo/media_queries.rs &gt;@@ -9,21 +9,21 @@ use context::QuirksMode; &gt; use cssparser::{Parser, RGBA}; &gt; use euclid::{Size2D, TypedScale, TypedSize2D}; &gt; use media_queries::MediaType; &gt; use parser::ParserContext; &gt; use properties::ComputedValues; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use std::fmt::{self, Write}; &gt; use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; &gt;-use style_traits::{CSSPixel, CssWriter, DevicePixel, ParseError, ToCss}; &gt; use style_traits::viewport::ViewportConstraints; &gt;-use values::{specified, KeyframesName}; &gt;-use values::computed::{self, ToComputedValue}; &gt;+use style_traits::{CSSPixel, CssWriter, DevicePixel, ParseError, ToCss}; &gt; use values::computed::font::FontSize; &gt;+use values::computed::{self, ToComputedValue}; &gt;+use values::{specified, KeyframesName}; &gt; &gt; /// A device is a structure that represents the current media a given document &gt; /// is displayed in. &gt; /// &gt; /// This is the struct against which media queries are evaluated. &gt; #[derive(Debug, MallocSizeOf)] &gt; pub struct Device { &gt; /// The current media type used by de device. &gt;@@ -187,19 +187,17 @@ impl MediaFeatureExpression { &gt; /// ``` &gt; /// &gt; /// Only supports width ranges for now. &gt; pub fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; input.expect_parenthesis_block()?; &gt;- input.parse_nested_block(|input| { &gt;- Self::parse_in_parenthesis_block(context, input) &gt;- }) &gt;+ input.parse_nested_block(|input| Self::parse_in_parenthesis_block(context, input)) &gt; } &gt; &gt; /// Parse a media range expression where we've already consumed the &gt; /// parenthesis. &gt; pub fn parse_in_parenthesis_block&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt;@@ -227,17 +225,17 @@ impl MediaFeatureExpression { &gt; let value = viewport_size.width; &gt; match self.0 { &gt; ExpressionKind::Width(ref range) =&gt; { &gt; match range.to_computed_range(device, quirks_mode) { &gt; Range::Min(ref width) =&gt; value &gt;= *width, &gt; Range::Max(ref width) =&gt; value &lt;= *width, &gt; Range::Eq(ref width) =&gt; value == *width, &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl ToCss for MediaFeatureExpression { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt;diff --git a/servo/components/style/servo/restyle_damage.rs b/servo/components/style/servo/restyle_damage.rs &gt;index 5cde20c9658f..ff34df0aedce 100644 &gt;--- a/servo/components/style/servo/restyle_damage.rs &gt;+++ b/servo/components/style/servo/restyle_damage.rs &gt;@@ -75,41 +75,46 @@ impl ServoRestyleDamage { &gt; } &gt; &gt; /// Returns a bitmask that represents a flow that needs to be rebuilt and &gt; /// reflowed. &gt; /// &gt; /// FIXME(bholley): Do we ever actually need this? Shouldn't &gt; /// RECONSTRUCT_FLOW imply everything else? &gt; pub fn rebuild_and_reflow() -&gt; ServoRestyleDamage { &gt;- ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION | &gt;- ServoRestyleDamage::STORE_OVERFLOW | ServoRestyleDamage::BUBBLE_ISIZES | &gt;- ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW | &gt;- ServoRestyleDamage::RECONSTRUCT_FLOW &gt;+ ServoRestyleDamage::REPAINT &gt;+ | ServoRestyleDamage::REPOSITION &gt;+ | ServoRestyleDamage::STORE_OVERFLOW &gt;+ | ServoRestyleDamage::BUBBLE_ISIZES &gt;+ | ServoRestyleDamage::REFLOW_OUT_OF_FLOW &gt;+ | ServoRestyleDamage::REFLOW &gt;+ | ServoRestyleDamage::RECONSTRUCT_FLOW &gt; } &gt; &gt; /// Returns a bitmask indicating that the frame needs to be reconstructed. &gt; pub fn reconstruct() -&gt; ServoRestyleDamage { &gt; ServoRestyleDamage::RECONSTRUCT_FLOW &gt; } &gt; &gt; /// Supposing a flow has the given `position` property and this damage, &gt; /// returns the damage that we should add to the *parent* of this flow. &gt; pub fn damage_for_parent(self, child_is_absolutely_positioned: bool) -&gt; ServoRestyleDamage { &gt; if child_is_absolutely_positioned { &gt;- self &amp; (ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION | &gt;- ServoRestyleDamage::STORE_OVERFLOW | &gt;- ServoRestyleDamage::REFLOW_OUT_OF_FLOW | &gt;- ServoRestyleDamage::RESOLVE_GENERATED_CONTENT) &gt;+ self &amp; (ServoRestyleDamage::REPAINT &gt;+ | ServoRestyleDamage::REPOSITION &gt;+ | ServoRestyleDamage::STORE_OVERFLOW &gt;+ | ServoRestyleDamage::REFLOW_OUT_OF_FLOW &gt;+ | ServoRestyleDamage::RESOLVE_GENERATED_CONTENT) &gt; } else { &gt;- self &amp; (ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION | &gt;- ServoRestyleDamage::STORE_OVERFLOW | &gt;- ServoRestyleDamage::REFLOW | &gt;- ServoRestyleDamage::REFLOW_OUT_OF_FLOW | &gt;- ServoRestyleDamage::RESOLVE_GENERATED_CONTENT) &gt;+ self &amp; (ServoRestyleDamage::REPAINT &gt;+ | ServoRestyleDamage::REPOSITION &gt;+ | ServoRestyleDamage::STORE_OVERFLOW &gt;+ | ServoRestyleDamage::REFLOW &gt;+ | ServoRestyleDamage::REFLOW_OUT_OF_FLOW &gt;+ | ServoRestyleDamage::RESOLVE_GENERATED_CONTENT) &gt; } &gt; } &gt; &gt; /// Supposing the *parent* of a flow with the given `position` property has &gt; /// this damage, returns the damage that we should add to this flow. &gt; pub fn damage_for_child( &gt; self, &gt; parent_is_absolutely_positioned: bool, &gt;@@ -119,31 +124,32 @@ impl ServoRestyleDamage { &gt; parent_is_absolutely_positioned, &gt; child_is_absolutely_positioned, &gt; ) { &gt; (false, true) =&gt; { &gt; // Absolute children are out-of-flow and therefore insulated from changes. &gt; // &gt; // FIXME(pcwalton): Au contraire, if the containing block dimensions change! &gt; self &amp; (ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION) &gt;- }, &gt;+ } &gt; (true, false) =&gt; { &gt; // Changing the position of an absolutely-positioned block requires us to reflow &gt; // its kids. &gt; if self.contains(ServoRestyleDamage::REFLOW_OUT_OF_FLOW) { &gt; self | ServoRestyleDamage::REFLOW &gt; } else { &gt; self &gt; } &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; // TODO(pcwalton): Take floatedness into account. &gt;- self &amp; (ServoRestyleDamage::REPAINT | ServoRestyleDamage::REPOSITION | &gt;- ServoRestyleDamage::REFLOW) &gt;- }, &gt;+ self &amp; (ServoRestyleDamage::REPAINT &gt;+ | ServoRestyleDamage::REPOSITION &gt;+ | ServoRestyleDamage::REFLOW) &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl Default for ServoRestyleDamage { &gt; fn default() -&gt; Self { &gt; Self::empty() &gt; } &gt;@@ -200,56 +206,56 @@ fn compute_damage(old: &amp;ComputedValues, new: &amp;ComputedValues) -&gt; ServoRestyleDam &gt; ServoRestyleDamage::REPAINT, &gt; ServoRestyleDamage::REPOSITION, &gt; ServoRestyleDamage::STORE_OVERFLOW, &gt; ServoRestyleDamage::BUBBLE_ISIZES, &gt; ServoRestyleDamage::REFLOW_OUT_OF_FLOW, &gt; ServoRestyleDamage::REFLOW, &gt; ServoRestyleDamage::RECONSTRUCT_FLOW &gt; ] &gt;- ) || &gt;- (new.get_box().display == Display::Inline &amp;&amp; &gt;- restyle_damage_rebuild_and_reflow_inline!( &gt;- old, &gt;- new, &gt;- damage, &gt;- [ &gt;- ServoRestyleDamage::REPAINT, &gt;- ServoRestyleDamage::REPOSITION, &gt;- ServoRestyleDamage::STORE_OVERFLOW, &gt;- ServoRestyleDamage::BUBBLE_ISIZES, &gt;- ServoRestyleDamage::REFLOW_OUT_OF_FLOW, &gt;- ServoRestyleDamage::REFLOW, &gt;- ServoRestyleDamage::RECONSTRUCT_FLOW &gt;- ] &gt;- )) || &gt;- restyle_damage_reflow!( &gt;+ ) || (new.get_box().display == Display::Inline &gt;+ &amp;&amp; restyle_damage_rebuild_and_reflow_inline!( &gt;+ old, &gt;+ new, &gt;+ damage, &gt;+ [ &gt;+ ServoRestyleDamage::REPAINT, &gt;+ ServoRestyleDamage::REPOSITION, &gt;+ ServoRestyleDamage::STORE_OVERFLOW, &gt;+ ServoRestyleDamage::BUBBLE_ISIZES, &gt;+ ServoRestyleDamage::REFLOW_OUT_OF_FLOW, &gt;+ ServoRestyleDamage::REFLOW, &gt;+ ServoRestyleDamage::RECONSTRUCT_FLOW &gt;+ ] &gt;+ )) &gt;+ || restyle_damage_reflow!( &gt; old, &gt; new, &gt; damage, &gt; [ &gt; ServoRestyleDamage::REPAINT, &gt; ServoRestyleDamage::REPOSITION, &gt; ServoRestyleDamage::STORE_OVERFLOW, &gt; ServoRestyleDamage::BUBBLE_ISIZES, &gt; ServoRestyleDamage::REFLOW_OUT_OF_FLOW, &gt; ServoRestyleDamage::REFLOW &gt; ] &gt;- ) || &gt;- restyle_damage_reflow_out_of_flow!( &gt;+ ) &gt;+ || restyle_damage_reflow_out_of_flow!( &gt; old, &gt; new, &gt; damage, &gt; [ &gt; ServoRestyleDamage::REPAINT, &gt; ServoRestyleDamage::REPOSITION, &gt; ServoRestyleDamage::STORE_OVERFLOW, &gt; ServoRestyleDamage::REFLOW_OUT_OF_FLOW &gt; ] &gt;- ) || restyle_damage_repaint!(old, new, damage, [ServoRestyleDamage::REPAINT]); &gt;+ ) &gt;+ || restyle_damage_repaint!(old, new, damage, [ServoRestyleDamage::REPAINT]); &gt; &gt; // Paint worklets may depend on custom properties, &gt; // so if they have changed we should repaint. &gt; if old.custom_properties() != new.custom_properties() { &gt; damage.insert(ServoRestyleDamage::REPAINT); &gt; } &gt; &gt; // If the layer requirements of this flow have changed due to the value &gt;diff --git a/servo/components/style/servo/selector_parser.rs b/servo/components/style/servo/selector_parser.rs &gt;index 2083539f51b3..5762d4b54e33 100644 &gt;--- a/servo/components/style/servo/selector_parser.rs &gt;+++ b/servo/components/style/servo/selector_parser.rs &gt;@@ -1,34 +1,34 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; #![deny(missing_docs)] &gt; &gt; //! Servo's selector parser. &gt; &gt;-use {Atom, CaseSensitivityExt, LocalName, Namespace, Prefix}; &gt; use attr::{AttrIdentifier, AttrValue}; &gt; use cssparser::{serialize_identifier, CowRcStr, Parser as CssParser, SourceLocation, ToCss}; &gt; use dom::{OpaqueNode, TElement, TNode}; &gt; use element_state::{DocumentState, ElementState}; &gt; use fxhash::FxHashMap; &gt; use invalidation::element::document_state::InvalidationMatchingData; &gt; use invalidation::element::element_wrapper::ElementSnapshot; &gt;-use properties::{ComputedValues, PropertyFlags}; &gt; use properties::longhands::display::computed_value::T as Display; &gt;+use properties::{ComputedValues, PropertyFlags}; &gt; use selector_parser::{AttrValue as SelectorAttrValue, PseudoElementCascadeType, SelectorParser}; &gt; use selectors::attr::{AttrSelectorOperation, CaseSensitivity, NamespaceConstraint}; &gt; use selectors::parser::{SelectorParseErrorKind, Visit}; &gt; use selectors::visitor::SelectorVisitor; &gt; use std::fmt; &gt; use std::mem; &gt; use std::ops::{Deref, DerefMut}; &gt; use style_traits::{ParseError, StyleParseErrorKind}; &gt;+use {Atom, CaseSensitivityExt, LocalName, Namespace, Prefix}; &gt; &gt; /// A pseudo-element, both public and private. &gt; /// &gt; /// NB: If you add to this list, be sure to update `each_simple_pseudo_element` too. &gt; #[derive(Clone, Debug, Eq, Hash, PartialEq)] &gt; #[cfg_attr(feature = "servo", derive(MallocSizeOf))] &gt; #[allow(missing_docs)] &gt; #[repr(usize)] &gt;@@ -194,29 +194,29 @@ impl PseudoElement { &gt; /// For more info on cascade types, see docs/components/style.md &gt; /// &gt; /// Note: Keep this in sync with EAGER_PSEUDO_COUNT. &gt; #[inline] &gt; pub fn cascade_type(&amp;self) -&gt; PseudoElementCascadeType { &gt; match *self { &gt; PseudoElement::After | PseudoElement::Before | PseudoElement::Selection =&gt; { &gt; PseudoElementCascadeType::Eager &gt;- }, &gt;+ } &gt; PseudoElement::DetailsSummary =&gt; PseudoElementCascadeType::Lazy, &gt;- PseudoElement::DetailsContent | &gt;- PseudoElement::ServoText | &gt;- PseudoElement::ServoInputText | &gt;- PseudoElement::ServoTableWrapper | &gt;- PseudoElement::ServoAnonymousTableWrapper | &gt;- PseudoElement::ServoAnonymousTable | &gt;- PseudoElement::ServoAnonymousTableRow | &gt;- PseudoElement::ServoAnonymousTableCell | &gt;- PseudoElement::ServoAnonymousBlock | &gt;- PseudoElement::ServoInlineBlockWrapper | &gt;- PseudoElement::ServoInlineAbsolute =&gt; PseudoElementCascadeType::Precomputed, &gt;+ PseudoElement::DetailsContent &gt;+ | PseudoElement::ServoText &gt;+ | PseudoElement::ServoInputText &gt;+ | PseudoElement::ServoTableWrapper &gt;+ | PseudoElement::ServoAnonymousTableWrapper &gt;+ | PseudoElement::ServoAnonymousTable &gt;+ | PseudoElement::ServoAnonymousTableRow &gt;+ | PseudoElement::ServoAnonymousTableCell &gt;+ | PseudoElement::ServoAnonymousBlock &gt;+ | PseudoElement::ServoInlineBlockWrapper &gt;+ | PseudoElement::ServoInlineAbsolute =&gt; PseudoElementCascadeType::Precomputed, &gt; } &gt; } &gt; &gt; /// For most (but not all) anon-boxes, we inherit all values from the &gt; /// parent, this is the hook in the style system to allow this. &gt; /// &gt; /// FIXME(emilio): It's likely that this is broken in a variety of &gt; /// situations, and what it really wants is just inherit some reset &gt;@@ -328,23 +328,23 @@ impl ToCss for NonTSPseudoClass { &gt; W: fmt::Write, &gt; { &gt; use self::NonTSPseudoClass::*; &gt; match *self { &gt; Lang(ref lang) =&gt; { &gt; dest.write_str(":lang(")?; &gt; serialize_identifier(lang, dest)?; &gt; return dest.write_str(")"); &gt;- }, &gt;+ } &gt; ServoCaseSensitiveTypeAttr(ref value) =&gt; { &gt; dest.write_str(":-servo-case-sensitive-type-attr(")?; &gt; serialize_identifier(value, dest)?; &gt; return dest.write_str(")"); &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; &gt; dest.write_str(match *self { &gt; Active =&gt; ":active", &gt; AnyLink =&gt; ":any-link", &gt; Checked =&gt; ":checked", &gt; Disabled =&gt; ":disabled", &gt; Enabled =&gt; ":enabled", &gt;@@ -374,37 +374,37 @@ impl Visit for NonTSPseudoClass { &gt; true &gt; } &gt; } &gt; &gt; impl NonTSPseudoClass { &gt; /// Gets a given state flag for this pseudo-class. This is used to do &gt; /// selector matching, and it's set from the DOM. &gt; pub fn state_flag(&amp;self) -&gt; ElementState { &gt;+ use self::NonTSPseudoClass::*; &gt; use element_state::ElementState; &gt;- use self::NonTSPseudoClass::*; &gt; match *self { &gt; Active =&gt; ElementState::IN_ACTIVE_STATE, &gt; Focus =&gt; ElementState::IN_FOCUS_STATE, &gt; Fullscreen =&gt; ElementState::IN_FULLSCREEN_STATE, &gt; Hover =&gt; ElementState::IN_HOVER_STATE, &gt; Enabled =&gt; ElementState::IN_ENABLED_STATE, &gt; Disabled =&gt; ElementState::IN_DISABLED_STATE, &gt; Checked =&gt; ElementState::IN_CHECKED_STATE, &gt; Indeterminate =&gt; ElementState::IN_INDETERMINATE_STATE, &gt; ReadOnly | ReadWrite =&gt; ElementState::IN_READ_WRITE_STATE, &gt; PlaceholderShown =&gt; ElementState::IN_PLACEHOLDER_SHOWN_STATE, &gt; Target =&gt; ElementState::IN_TARGET_STATE, &gt; &gt;- AnyLink | &gt;- Lang(_) | &gt;- Link | &gt;- Visited | &gt;- ServoNonZeroBorder | &gt;- ServoCaseSensitiveTypeAttr(_) =&gt; ElementState::empty(), &gt;+ AnyLink &gt;+ | Lang(_) &gt;+ | Link &gt;+ | Visited &gt;+ | ServoNonZeroBorder &gt;+ | ServoCaseSensitiveTypeAttr(_) =&gt; ElementState::empty(), &gt; } &gt; } &gt; &gt; /// Get the document state flag associated with a pseudo-class, if any. &gt; pub fn document_state_flag(&amp;self) -&gt; DocumentState { &gt; DocumentState::empty() &gt; } &gt; &gt;@@ -757,38 +757,39 @@ impl ServoElementSnapshot { &gt; /// selectors::Element::attr_matches &gt; pub fn attr_matches( &gt; &amp;self, &gt; ns: &amp;NamespaceConstraint&lt;&amp;Namespace&gt;, &gt; local_name: &amp;LocalName, &gt; operation: &amp;AttrSelectorOperation&lt;&amp;String&gt;, &gt; ) -&gt; bool { &gt; match *ns { &gt;- NamespaceConstraint::Specific(ref ns) =&gt; self.get_attr(ns, local_name) &gt;+ NamespaceConstraint::Specific(ref ns) =&gt; self &gt;+ .get_attr(ns, local_name) &gt; .map_or(false, |value| value.eval_selector(operation)), &gt; NamespaceConstraint::Any =&gt; { &gt; self.any_attr_ignore_ns(local_name, |value| value.eval_selector(operation)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// Returns whether the language is matched, as defined by &gt; /// [RFC 4647](https://tools.ietf.org/html/rfc4647#section-3.3.2). &gt; pub fn extended_filtering(tag: &amp;str, range: &amp;str) -&gt; bool { &gt; range.split(',').any(|lang_range| { &gt; // step 1 &gt; let mut range_subtags = lang_range.split('\x2d'); &gt; let mut tag_subtags = tag.split('\x2d'); &gt; &gt; // step 2 &gt; // Note: [Level-4 spec](https://drafts.csswg.org/selectors/#lang-pseudo) check for wild card &gt; if let (Some(range_subtag), Some(tag_subtag)) = (range_subtags.next(), tag_subtags.next()) { &gt;- if !(range_subtag.eq_ignore_ascii_case(tag_subtag) || &gt;- range_subtag.eq_ignore_ascii_case("*")) &gt;+ if !(range_subtag.eq_ignore_ascii_case(tag_subtag) &gt;+ || range_subtag.eq_ignore_ascii_case("*")) &gt; { &gt; return false; &gt; } &gt; } &gt; &gt; let mut current_tag_subtag = tag_subtags.next(); &gt; &gt; // step 3 &gt;@@ -808,19 +809,19 @@ pub fn extended_filtering(tag: &amp;str, range: &amp;str) -&gt; bool { &gt; if tag_subtag.len() == 1 { &gt; return false; &gt; } &gt; // else step 3e - continue with loop &gt; current_tag_subtag = tag_subtags.next(); &gt; if current_tag_subtag.is_none() { &gt; return false; &gt; } &gt;- }, &gt;+ } &gt; // step 3b &gt; None =&gt; { &gt; return false; &gt;- }, &gt;+ } &gt; } &gt; } &gt; // step 4 &gt; true &gt; }) &gt; } &gt;diff --git a/servo/components/style/servo/url.rs b/servo/components/style/servo/url.rs &gt;index b4821f21e669..4c5275d45550 100644 &gt;--- a/servo/components/style/servo/url.rs &gt;+++ b/servo/components/style/servo/url.rs &gt;@@ -152,17 +152,17 @@ impl ToComputedValue for SpecifiedUrl { &gt; // but still return it as a ComputedUrl::Invalid &gt; fn to_computed_value(&amp;self, _: &amp;Context) -&gt; Self::ComputedValue { &gt; match self.resolved { &gt; Some(ref url) =&gt; ComputedUrl::Valid(url.clone()), &gt; None =&gt; match self.original { &gt; Some(ref url) =&gt; ComputedUrl::Invalid(url.clone()), &gt; None =&gt; { &gt; unreachable!("Found specified url with neither resolved or original URI!"); &gt;- }, &gt;+ } &gt; }, &gt; } &gt; } &gt; &gt; fn from_computed_value(computed: &amp;ComputedUrl) -&gt; Self { &gt; match *computed { &gt; ComputedUrl::Valid(ref url) =&gt; SpecifiedUrl { &gt; original: None, &gt;diff --git a/servo/components/style/sharing/mod.rs b/servo/components/style/sharing/mod.rs &gt;index d6148d16b49c..052764a6010e 100644 &gt;--- a/servo/components/style/sharing/mod.rs &gt;+++ b/servo/components/style/sharing/mod.rs &gt;@@ -59,37 +59,37 @@ &gt; //! the up-front checks but would have different matching results for the &gt; //! selector in question. In this case, "descendants" includes pseudo-elements, &gt; //! so there is a single selector map of revalidation selectors that includes &gt; //! both selectors targeting elements and selectors targeting pseudo-element &gt; //! originating elements. We ensure that the pseudo-element parts of all these &gt; //! selectors are effectively stripped off, so that matching them all against &gt; //! elements makes sense. &gt; &gt;-use Atom; &gt; use applicable_declarations::ApplicableDeclarationBlock; &gt; use atomic_refcell::{AtomicRefCell, AtomicRefMut}; &gt; use bloom::StyleBloom; &gt; use context::{SelectorFlagsMap, SharedStyleContext, StyleContext}; &gt; use dom::{SendElement, TElement}; &gt; use matching::MatchMethods; &gt; use owning_ref::OwningHandle; &gt; use properties::ComputedValues; &gt; use rule_tree::StrongRuleNode; &gt;-use selectors::NthIndexCache; &gt; use selectors::matching::{ElementSelectorFlags, VisitedHandlingMode}; &gt;+use selectors::NthIndexCache; &gt; use servo_arc::{Arc, NonZeroPtrMut}; &gt; use smallbitvec::SmallBitVec; &gt; use smallvec::SmallVec; &gt; use std::marker::PhantomData; &gt; use std::mem; &gt; use std::ops::Deref; &gt; use style_resolver::{PrimaryStyle, ResolvedElementStyles}; &gt; use stylist::Stylist; &gt; use uluru::{Entry, LRUCache}; &gt;+use Atom; &gt; &gt; mod checks; &gt; &gt; /// The amount of nodes that the style sharing candidate cache should hold at &gt; /// most. We'd somewhat like 32, but ArrayDeque only implements certain backing &gt; /// store sizes. A cache size of 32 would mean a backing store of 33, but &gt; /// that's not an implemented size: we can do 32 or 40. &gt; /// &gt;@@ -192,18 +192,17 @@ impl ValidationData { &gt; E: TElement, &gt; { &gt; self.parent_style_identity &gt; .get_or_insert_with(|| { &gt; let parent = el.inheritance_parent().unwrap(); &gt; let values = &gt; OpaqueComputedValues::from(parent.borrow_data().unwrap().styles.primary()); &gt; values &gt;- }) &gt;- .clone() &gt;+ }).clone() &gt; } &gt; &gt; /// Computes the revalidation results if needed, and returns it. &gt; /// Inline so we know at compile time what bloom_known_valid is. &gt; #[inline] &gt; fn revalidation_match_results&lt;E, F&gt;( &gt; &amp;mut self, &gt; element: E, &gt;@@ -557,17 +556,17 @@ impl&lt;E: TElement&gt; StyleSharingCache&lt;E&gt; { &gt; validation_data_holder: Option&lt;&amp;mut StyleSharingTarget&lt;E&gt;&gt;, &gt; dom_depth: usize, &gt; ) { &gt; let parent = match element.traversal_parent() { &gt; Some(element) =&gt; element, &gt; None =&gt; { &gt; debug!("Failing to insert to the cache: no parent element"); &gt; return; &gt;- }, &gt;+ } &gt; }; &gt; &gt; if element.is_in_native_anonymous_subtree() { &gt; debug!("Failing to insert into the cache: NAC"); &gt; return; &gt; } &gt; &gt; // We can't share style across shadow hosts right now, because they may &gt;@@ -755,18 +754,18 @@ impl&lt;E: TElement&gt; StyleSharingCache&lt;E&gt; { &gt; return None; &gt; } &gt; &gt; if target.element.shadow_root().is_some() { &gt; trace!("Miss: Shadow host"); &gt; return None; &gt; } &gt; &gt;- if target.matches_user_and_author_rules() != &gt;- candidate.element.matches_user_and_author_rules() &gt;+ if target.matches_user_and_author_rules() &gt;+ != candidate.element.matches_user_and_author_rules() &gt; { &gt; trace!("Miss: User and Author Rules"); &gt; return None; &gt; } &gt; &gt; // It's possible that there are no styles for either id. &gt; let may_match_different_id_rules = &gt; checks::may_match_different_id_rules(shared, target.element, candidate.element); &gt;diff --git a/servo/components/style/str.rs b/servo/components/style/str.rs &gt;index 4de65a235239..1d8fe0822872 100644 &gt;--- a/servo/components/style/str.rs &gt;+++ b/servo/components/style/str.rs &gt;@@ -122,21 +122,21 @@ pub fn read_exponent&lt;I: Iterator&lt;Item = char&gt;&gt;(mut iter: Peekable&lt;I&gt;) -&gt; Option&lt; &gt; } &gt; iter.next(); &gt; &gt; match iter.peek() { &gt; None =&gt; None, &gt; Some(&amp;'-') =&gt; { &gt; iter.next(); &gt; read_numbers(iter).0.map(|exp| -exp.to_i32().unwrap_or(0)) &gt;- }, &gt;+ } &gt; Some(&amp;'+') =&gt; { &gt; iter.next(); &gt; read_numbers(iter).0.map(|exp| exp.to_i32().unwrap_or(0)) &gt;- }, &gt;+ } &gt; Some(_) =&gt; read_numbers(iter).0.map(|exp| exp.to_i32().unwrap_or(0)), &gt; } &gt; } &gt; &gt; /// Join a set of strings with a given delimiter `join`. &gt; pub fn str_join&lt;I, T&gt;(strs: I, join: &amp;str) -&gt; String &gt; where &gt; I: IntoIterator&lt;Item = T&gt;, &gt;@@ -150,18 +150,18 @@ where &gt; } &gt; acc.push_str(s.as_ref()); &gt; acc &gt; }) &gt; } &gt; &gt; /// Returns true if a given string has a given prefix with case-insensitive match. &gt; pub fn starts_with_ignore_ascii_case(string: &amp;str, prefix: &amp;str) -&gt; bool { &gt;- string.len() &gt;= prefix.len() &amp;&amp; &gt;- string.as_bytes()[0..prefix.len()].eq_ignore_ascii_case(prefix.as_bytes()) &gt;+ string.len() &gt;= prefix.len() &gt;+ &amp;&amp; string.as_bytes()[0..prefix.len()].eq_ignore_ascii_case(prefix.as_bytes()) &gt; } &gt; &gt; /// Returns an ascii lowercase version of a string, only allocating if needed. &gt; pub fn string_as_ascii_lowercase&lt;'a&gt;(input: &amp;'a str) -&gt; Cow&lt;'a, str&gt; { &gt; if input.bytes().any(|c| matches!(c, b'A'...b'Z')) { &gt; input.to_ascii_lowercase().into() &gt; } else { &gt; // Already ascii lowercase. &gt;@@ -195,17 +195,17 @@ pub enum CssStringBorrow&lt;'a&gt; { &gt; #[cfg(feature = "gecko")] &gt; impl&lt;'a&gt; CssStringBorrow&lt;'a&gt; { &gt; /// Writes the borrowed string to the provided writer. &gt; pub fn append_to(&amp;self, dest: &amp;mut CssStringWriter) -&gt; fmt::Result { &gt; match *self { &gt; CssStringBorrow::UTF16(s) =&gt; { &gt; dest.append(s); &gt; Ok(()) &gt;- }, &gt;+ } &gt; CssStringBorrow::UTF8(s) =&gt; dest.write_str(s), &gt; } &gt; } &gt; &gt; /// Returns true of the borrowed string is empty. &gt; pub fn is_empty(&amp;self) -&gt; bool { &gt; match *self { &gt; CssStringBorrow::UTF16(s) =&gt; s.is_empty(), &gt;diff --git a/servo/components/style/style_adjuster.rs b/servo/components/style/style_adjuster.rs &gt;index 704c875a932e..73c5b6c5ee1c 100644 &gt;--- a/servo/components/style/style_adjuster.rs &gt;+++ b/servo/components/style/style_adjuster.rs &gt;@@ -2,22 +2,22 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! A struct to encapsulate all the style fixups and flags propagations &gt; //! a computed style needs in order for it to adhere to the CSS spec. &gt; &gt; use app_units::Au; &gt; use dom::TElement; &gt;-use properties::{self, ComputedValues, StyleBuilder}; &gt; use properties::computed_value_flags::ComputedValueFlags; &gt; use properties::longhands::display::computed_value::T as Display; &gt; use properties::longhands::float::computed_value::T as Float; &gt; use properties::longhands::overflow_x::computed_value::T as Overflow; &gt; use properties::longhands::position::computed_value::T as Position; &gt;+use properties::{self, ComputedValues, StyleBuilder}; &gt; &gt; /// A struct that implements all the adjustment methods. &gt; /// &gt; /// NOTE(emilio): If new adjustments are introduced that depend on reset &gt; /// properties of the parent, you may need tweaking the &gt; /// `ChildCascadeRequirement` code in `matching.rs`. &gt; /// &gt; /// NOTE(emilio): Also, if new adjustments are introduced that break the &gt;@@ -59,49 +59,68 @@ fn is_effective_display_none_for_display_contents&lt;E&gt;(element: E) -&gt; bool &gt; where &gt; E: TElement, &gt; { &gt; use Atom; &gt; &gt; // FIXME(emilio): This should be an actual static. &gt; lazy_static! { &gt; static ref SPECIAL_HTML_ELEMENTS: [Atom; 16] = [ &gt;- atom!("br"), atom!("wbr"), atom!("meter"), atom!("progress"), &gt;- atom!("canvas"), atom!("embed"), atom!("object"), atom!("audio"), &gt;- atom!("iframe"), atom!("img"), atom!("video"), atom!("frame"), &gt;- atom!("frameset"), atom!("input"), atom!("textarea"), &gt;+ atom!("br"), &gt;+ atom!("wbr"), &gt;+ atom!("meter"), &gt;+ atom!("progress"), &gt;+ atom!("canvas"), &gt;+ atom!("embed"), &gt;+ atom!("object"), &gt;+ atom!("audio"), &gt;+ atom!("iframe"), &gt;+ atom!("img"), &gt;+ atom!("video"), &gt;+ atom!("frame"), &gt;+ atom!("frameset"), &gt;+ atom!("input"), &gt;+ atom!("textarea"), &gt; atom!("select"), &gt; ]; &gt; } &gt; &gt; // https://drafts.csswg.org/css-display/#unbox-svg &gt; // &gt; // There's a note about "Unknown elements", but there's not a good way to &gt; // know what that means, or to get that information from here, and no other &gt; // UA implements this either. &gt; lazy_static! { &gt; static ref SPECIAL_SVG_ELEMENTS: [Atom; 6] = [ &gt;- atom!("svg"), atom!("a"), atom!("g"), atom!("use"), &gt;- atom!("tspan"), atom!("textPath"), &gt;+ atom!("svg"), &gt;+ atom!("a"), &gt;+ atom!("g"), &gt;+ atom!("use"), &gt;+ atom!("tspan"), &gt;+ atom!("textPath"), &gt; ]; &gt; } &gt; &gt; // https://drafts.csswg.org/css-display/#unbox-html &gt; if element.is_html_element() { &gt; let local_name = element.local_name(); &gt;- return SPECIAL_HTML_ELEMENTS.iter().any(|name| &amp;**name == local_name); &gt;+ return SPECIAL_HTML_ELEMENTS &gt;+ .iter() &gt;+ .any(|name| &amp;**name == local_name); &gt; } &gt; &gt; // https://drafts.csswg.org/css-display/#unbox-svg &gt; if element.is_svg_element() { &gt; if is_topmost_svg_svg_element(element) { &gt; return true; &gt; } &gt; let local_name = element.local_name(); &gt;- return !SPECIAL_SVG_ELEMENTS.iter().any(|name| &amp;**name == local_name); &gt;+ return !SPECIAL_SVG_ELEMENTS &gt;+ .iter() &gt;+ .any(|name| &amp;**name == local_name); &gt; } &gt; &gt; // https://drafts.csswg.org/css-display/#unbox-mathml &gt; // &gt; // We always treat XUL as display: none. We don't use display: &gt; // contents in XUL anyway, so should be fine to be consistent with &gt; // MathML unless there's a use case for it. &gt; if element.is_mathml_element() || element.is_xul_element() { &gt;@@ -196,21 +215,21 @@ impl&lt;'a, 'b: 'a&gt; StyleAdjuster&lt;'a, 'b&gt; { &gt; .set_adjusted_display(blockified_display, is_item_or_root); &gt; } &gt; } &gt; &gt; /// Compute a few common flags for both text and element's style. &gt; pub fn set_bits(&amp;mut self) { &gt; let display = self.style.get_box().clone_display(); &gt; &gt;- if !display.is_contents() &amp;&amp; &gt;- !self.style &gt;- .get_text() &gt;- .clone_text_decoration_line() &gt;- .is_empty() &gt;+ if !display.is_contents() &amp;&amp; !self &gt;+ .style &gt;+ .get_text() &gt;+ .clone_text_decoration_line() &gt;+ .is_empty() &gt; { &gt; self.style &gt; .flags &gt; .insert(ComputedValueFlags::HAS_TEXT_DECORATION_LINES); &gt; } &gt; &gt; if self.style.is_pseudo_element() { &gt; self.style &gt;@@ -254,18 +273,18 @@ impl&lt;'a, 'b: 'a&gt; StyleAdjuster&lt;'a, 'b&gt; { &gt; #[cfg(feature = "gecko")] &gt; fn adjust_for_text_combine_upright(&amp;mut self) { &gt; use computed_values::text_combine_upright::T as TextCombineUpright; &gt; use computed_values::writing_mode::T as WritingMode; &gt; &gt; let writing_mode = self.style.get_inherited_box().clone_writing_mode(); &gt; let text_combine_upright = self.style.get_inherited_text().clone_text_combine_upright(); &gt; &gt;- if writing_mode != WritingMode::HorizontalTb &amp;&amp; &gt;- text_combine_upright == TextCombineUpright::All &gt;+ if writing_mode != WritingMode::HorizontalTb &gt;+ &amp;&amp; text_combine_upright == TextCombineUpright::All &gt; { &gt; self.style &gt; .flags &gt; .insert(ComputedValueFlags::IS_TEXT_COMBINED); &gt; self.style &gt; .mutate_inherited_box() &gt; .set_writing_mode(WritingMode::HorizontalTb); &gt; } &gt;@@ -275,20 +294,20 @@ impl&lt;'a, 'b: 'a&gt; StyleAdjuster&lt;'a, 'b&gt; { &gt; /// additionally it applies it if it is in any ruby box. &gt; /// &gt; /// This is necessary because its parent may not itself have the flag set &gt; /// (e.g. ruby or ruby containers), thus we may not inherit the flag from &gt; /// them. &gt; #[cfg(feature = "gecko")] &gt; fn adjust_for_text_in_ruby(&amp;mut self) { &gt; let parent_display = self.style.get_parent_box().clone_display(); &gt;- if parent_display.is_ruby_type() || &gt;- self.style &gt;- .get_parent_flags() &gt;- .contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK) &gt;+ if parent_display.is_ruby_type() || self &gt;+ .style &gt;+ .get_parent_flags() &gt;+ .contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK) &gt; { &gt; self.style &gt; .flags &gt; .insert(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK); &gt; } &gt; } &gt; &gt; /// &lt;https://drafts.csswg.org/css-writing-modes-3/#block-flow:&gt; &gt;@@ -303,18 +322,18 @@ impl&lt;'a, 'b: 'a&gt; StyleAdjuster&lt;'a, 'b&gt; { &gt; /// the spec. See also: &gt; /// &gt; /// &lt;https://lists.w3.org/Archives/Public/www-style/2017Mar/0045.html&gt; &gt; /// &lt;https://github.com/servo/servo/issues/15754&gt; &gt; fn adjust_for_writing_mode(&amp;mut self, layout_parent_style: &amp;ComputedValues) { &gt; let our_writing_mode = self.style.get_inherited_box().clone_writing_mode(); &gt; let parent_writing_mode = layout_parent_style.get_inherited_box().clone_writing_mode(); &gt; &gt;- if our_writing_mode != parent_writing_mode &amp;&amp; &gt;- self.style.get_box().clone_display() == Display::Inline &gt;+ if our_writing_mode != parent_writing_mode &gt;+ &amp;&amp; self.style.get_box().clone_display() == Display::Inline &gt; { &gt; // TODO(emilio): Figure out if we can just set the adjusted display &gt; // on Gecko too and unify this code path. &gt; if cfg!(feature = "servo") { &gt; self.style &gt; .mutate_box() &gt; .set_adjusted_display(Display::InlineBlock, false); &gt; } else { &gt;@@ -341,18 +360,18 @@ impl&lt;'a, 'b: 'a&gt; StyleAdjuster&lt;'a, 'b&gt; { &gt; /// this to layout, which Gecko implements but Servo doesn't. &gt; /// &gt; /// See https://github.com/servo/servo/issues/15229 &gt; #[cfg(feature = "servo")] &gt; fn adjust_for_alignment(&amp;mut self, layout_parent_style: &amp;ComputedValues) { &gt; use computed_values::align_items::T as AlignItems; &gt; use computed_values::align_self::T as AlignSelf; &gt; &gt;- if self.style.get_position().clone_align_self() == AlignSelf::Auto &amp;&amp; &gt;- !self.style.out_of_flow_positioned() &gt;+ if self.style.get_position().clone_align_self() == AlignSelf::Auto &gt;+ &amp;&amp; !self.style.out_of_flow_positioned() &gt; { &gt; let self_align = match layout_parent_style.get_position().clone_align_items() { &gt; AlignItems::Stretch =&gt; AlignSelf::Stretch, &gt; AlignItems::Baseline =&gt; AlignSelf::Baseline, &gt; AlignItems::FlexStart =&gt; AlignSelf::FlexStart, &gt; AlignItems::FlexEnd =&gt; AlignSelf::FlexEnd, &gt; AlignItems::Center =&gt; AlignSelf::Center, &gt; }; &gt;@@ -365,20 +384,22 @@ impl&lt;'a, 'b: 'a&gt; StyleAdjuster&lt;'a, 'b&gt; { &gt; /// &gt; /// This is moved to properties.rs for convenience. &gt; fn adjust_for_border_width(&amp;mut self) { &gt; properties::adjust_border_width(self.style); &gt; } &gt; &gt; /// The initial value of outline-width may be changed at computed value time. &gt; fn adjust_for_outline(&amp;mut self) { &gt;- if self.style &gt;+ if self &gt;+ .style &gt; .get_outline() &gt; .clone_outline_style() &gt;- .none_or_hidden() &amp;&amp; self.style.get_outline().outline_has_nonzero_width() &gt;+ .none_or_hidden() &gt;+ &amp;&amp; self.style.get_outline().outline_has_nonzero_width() &gt; { &gt; self.style.mutate_outline().set_outline_width(Au(0).into()); &gt; } &gt; } &gt; &gt; /// CSS3 overflow-x and overflow-y require some fixup as well in some &gt; /// cases. &gt; /// &gt;@@ -459,17 +480,17 @@ impl&lt;'a, 'b: 'a&gt; StyleAdjuster&lt;'a, 'b&gt; { &gt; /// this type into its ::-moz-fieldset-content anonymous box. &gt; /// &gt; /// NOTE(emilio): We don't need to handle the display change for this case &gt; /// in matching.rs because anonymous box restyling works separately to the &gt; /// normal cascading process. &gt; #[cfg(feature = "gecko")] &gt; fn adjust_for_fieldset_content(&amp;mut self, layout_parent_style: &amp;ComputedValues) { &gt; match self.style.pseudo { &gt;- Some(ref p) if p.is_fieldset_content() =&gt; {}, &gt;+ Some(ref p) if p.is_fieldset_content() =&gt; {} &gt; _ =&gt; return, &gt; } &gt; &gt; debug_assert_eq!(self.style.get_box().clone_display(), Display::Block); &gt; // TODO We actually want style from parent rather than layout &gt; // parent, so that this fixup doesn't happen incorrectly when &gt; // when &lt;fieldset&gt; has "display: contents". &gt; let parent_display = layout_parent_style.get_box().clone_display(); &gt;@@ -492,17 +513,17 @@ impl&lt;'a, 'b: 'a&gt; StyleAdjuster&lt;'a, 'b&gt; { &gt; #[cfg(feature = "gecko")] &gt; fn adjust_for_table_text_align(&amp;mut self) { &gt; use properties::longhands::text_align::computed_value::T as TextAlign; &gt; if self.style.get_box().clone_display() != Display::Table { &gt; return; &gt; } &gt; &gt; match self.style.get_inherited_text().clone_text_align() { &gt;- TextAlign::MozLeft | TextAlign::MozCenter | TextAlign::MozRight =&gt; {}, &gt;+ TextAlign::MozLeft | TextAlign::MozCenter | TextAlign::MozRight =&gt; {} &gt; _ =&gt; return, &gt; } &gt; &gt; self.style &gt; .mutate_inherited_text() &gt; .set_text_align(TextAlign::Start) &gt; } &gt; &gt;@@ -512,17 +533,19 @@ impl&lt;'a, 'b: 'a&gt; StyleAdjuster&lt;'a, 'b&gt; { &gt; /// style, since otherwise we're going to have the same subtle bugs WebKit &gt; /// and Blink have with this very same thing. &gt; #[cfg(feature = "servo")] &gt; fn adjust_for_text_decorations_in_effect(&amp;mut self) { &gt; use values::computed::text::TextDecorationsInEffect; &gt; &gt; let decorations_in_effect = TextDecorationsInEffect::from_style(&amp;self.style); &gt; if self.style.get_inherited_text().text_decorations_in_effect != decorations_in_effect { &gt;- self.style.mutate_inherited_text().text_decorations_in_effect = decorations_in_effect; &gt;+ self.style &gt;+ .mutate_inherited_text() &gt;+ .text_decorations_in_effect = decorations_in_effect; &gt; } &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt; fn should_suppress_linebreak(&amp;self, layout_parent_style: &amp;ComputedValues) -&gt; bool { &gt; // Line break suppression should only be propagated to in-flow children. &gt; if self.style.floated() || self.style.out_of_flow_positioned() { &gt; return false; &gt;@@ -672,21 +695,18 @@ impl&lt;'a, 'b: 'a&gt; StyleAdjuster&lt;'a, 'b&gt; { &gt; } &gt; &gt; /// Adjusts the style to account for various fixups that don't fit naturally &gt; /// into the cascade. &gt; /// &gt; /// When comparing to Gecko, this is similar to the work done by &gt; /// `ComputedStyle::ApplyStyleFixups`, plus some parts of &gt; /// `nsStyleSet::GetContext`. &gt;- pub fn adjust&lt;E&gt;( &gt;- &amp;mut self, &gt;- layout_parent_style: &amp;ComputedValues, &gt;- element: Option&lt;E&gt;, &gt;- ) where &gt;+ pub fn adjust&lt;E&gt;(&amp;mut self, layout_parent_style: &amp;ComputedValues, element: Option&lt;E&gt;) &gt;+ where &gt; E: TElement, &gt; { &gt; if cfg!(debug_assertions) { &gt; if element &gt; .and_then(|e| e.implemented_pseudo_element()) &gt; .is_some() &gt; { &gt; // It'd be nice to assert `self.style.pseudo == Some(&amp;pseudo)`, &gt;diff --git a/servo/components/style/style_resolver.rs b/servo/components/style/style_resolver.rs &gt;index b31beff74603..2a15844cf953 100644 &gt;--- a/servo/components/style/style_resolver.rs &gt;+++ b/servo/components/style/style_resolver.rs &gt;@@ -5,21 +5,23 @@ &gt; //! Style resolution for a given element or pseudo-element. &gt; &gt; use applicable_declarations::ApplicableDeclarationList; &gt; use context::{CascadeInputs, ElementCascadeInputs, StyleContext}; &gt; use data::{EagerPseudoStyles, ElementStyles}; &gt; use dom::TElement; &gt; use log::Level::Trace; &gt; use matching::MatchMethods; &gt;-use properties::{AnimationRules, ComputedValues}; &gt; use properties::longhands::display::computed_value::T as Display; &gt;+use properties::{AnimationRules, ComputedValues}; &gt; use rule_tree::StrongRuleNode; &gt; use selector_parser::{PseudoElement, SelectorImpl}; &gt;-use selectors::matching::{ElementSelectorFlags, MatchingContext, MatchingMode, VisitedHandlingMode}; &gt;+use selectors::matching::{ &gt;+ ElementSelectorFlags, MatchingContext, MatchingMode, VisitedHandlingMode, &gt;+}; &gt; use servo_arc::Arc; &gt; use stylist::RuleInclusion; &gt; &gt; /// Whether pseudo-elements should be resolved or not. &gt; #[derive(Clone, Copy, Debug, Eq, PartialEq)] &gt; pub enum PseudoElementResolution { &gt; /// Only resolve pseudo-styles if possibly applicable. &gt; IfApplicable, &gt;@@ -110,24 +112,24 @@ fn eager_pseudo_is_definitely_not_generated( &gt; style: &amp;ComputedValues, &gt; ) -&gt; bool { &gt; use properties::computed_value_flags::ComputedValueFlags; &gt; &gt; if !pseudo.is_before_or_after() { &gt; return false; &gt; } &gt; &gt;- if !style.flags.intersects(ComputedValueFlags::INHERITS_DISPLAY) &amp;&amp; &gt;- style.get_box().clone_display() == Display::None &gt;+ if !style.flags.intersects(ComputedValueFlags::INHERITS_DISPLAY) &gt;+ &amp;&amp; style.get_box().clone_display() == Display::None &gt; { &gt; return true; &gt; } &gt; &gt;- if !style.flags.intersects(ComputedValueFlags::INHERITS_CONTENT) &amp;&amp; &gt;- style.ineffective_content_property() &gt;+ if !style.flags.intersects(ComputedValueFlags::INHERITS_CONTENT) &gt;+ &amp;&amp; style.ineffective_content_property() &gt; { &gt; return true; &gt; } &gt; &gt; false &gt; } &gt; &gt; impl&lt;'a, 'ctx, 'le, E&gt; StyleResolverForElement&lt;'a, 'ctx, 'le, E&gt; &gt;@@ -157,18 +159,18 @@ where &gt; &amp;mut self, &gt; parent_style: Option&lt;&amp;ComputedValues&gt;, &gt; layout_parent_style: Option&lt;&amp;ComputedValues&gt;, &gt; ) -&gt; PrimaryStyle { &gt; let primary_results = self.match_primary(VisitedHandlingMode::AllLinksUnvisited); &gt; &gt; let inside_link = parent_style.map_or(false, |s| s.visited_style().is_some()); &gt; &gt;- let visited_rules = if self.context.shared.visited_styles_enabled &amp;&amp; &gt;- (inside_link || self.element.is_link()) &gt;+ let visited_rules = if self.context.shared.visited_styles_enabled &gt;+ &amp;&amp; (inside_link || self.element.is_link()) &gt; { &gt; let visited_matching_results = &gt; self.match_primary(VisitedHandlingMode::RelevantLinkVisited); &gt; Some(visited_matching_results.rule_node) &gt; } else { &gt; None &gt; }; &gt; &gt;@@ -185,20 +187,19 @@ where &gt; fn cascade_primary_style( &gt; &amp;mut self, &gt; inputs: CascadeInputs, &gt; parent_style: Option&lt;&amp;ComputedValues&gt;, &gt; layout_parent_style: Option&lt;&amp;ComputedValues&gt;, &gt; ) -&gt; PrimaryStyle { &gt; // Before doing the cascade, check the sharing cache and see if we can &gt; // reuse the style via rule node identity. &gt;- let may_reuse = &gt;- !self.element.is_in_native_anonymous_subtree() &amp;&amp; &gt;- parent_style.is_some() &amp;&amp; &gt;- inputs.rules.is_some(); &gt;+ let may_reuse = !self.element.is_in_native_anonymous_subtree() &gt;+ &amp;&amp; parent_style.is_some() &gt;+ &amp;&amp; inputs.rules.is_some(); &gt; &gt; if may_reuse { &gt; let cached = self.context.thread_local.sharing_cache.lookup_by_rules( &gt; self.context.shared, &gt; parent_style.unwrap(), &gt; inputs.rules.as_ref().unwrap(), &gt; inputs.visited_rules.as_ref(), &gt; self.element, &gt;@@ -242,18 +243,18 @@ where &gt; SelectorImpl::each_eagerly_cascaded_pseudo_element(|pseudo| { &gt; let pseudo_style = self.resolve_pseudo_style( &gt; &amp;pseudo, &gt; &amp;primary_style, &gt; layout_parent_style_for_pseudo, &gt; ); &gt; &gt; if let Some(style) = pseudo_style { &gt;- if !matches!(self.pseudo_resolution, PseudoElementResolution::Force) &amp;&amp; &gt;- eager_pseudo_is_definitely_not_generated(&amp;pseudo, &amp;style.0) &gt;+ if !matches!(self.pseudo_resolution, PseudoElementResolution::Force) &gt;+ &amp;&amp; eager_pseudo_is_definitely_not_generated(&amp;pseudo, &amp;style.0) &gt; { &gt; return; &gt; } &gt; pseudo_styles.set(&amp;pseudo, style.0); &gt; } &gt; }) &gt; } &gt; &gt;@@ -350,18 +351,18 @@ where &gt; &gt; let style = self.cascade_style_and_visited( &gt; inputs, &gt; Some(primary_style.style()), &gt; layout_parent_style_for_pseudo, &gt; Some(&amp;pseudo), &gt; ); &gt; &gt;- if !matches!(self.pseudo_resolution, PseudoElementResolution::Force) &amp;&amp; &gt;- eager_pseudo_is_definitely_not_generated(&amp;pseudo, &amp;style.0) &gt;+ if !matches!(self.pseudo_resolution, PseudoElementResolution::Force) &gt;+ &amp;&amp; eager_pseudo_is_definitely_not_generated(&amp;pseudo, &amp;style.0) &gt; { &gt; continue; &gt; } &gt; &gt; pseudo_styles.set(&amp;pseudo, style.0); &gt; } &gt; } &gt; } &gt;@@ -480,17 +481,18 @@ where &gt; self.element.implemented_pseudo_element().is_none(), &gt; "Element pseudos can't have any other pseudo." &gt; ); &gt; &gt; let mut applicable_declarations = ApplicableDeclarationList::new(); &gt; &gt; let stylist = &amp;self.context.shared.stylist; &gt; &gt;- if !self.element &gt;+ if !self &gt;+ .element &gt; .may_generate_pseudo(pseudo_element, originating_element_style) &gt; { &gt; return None; &gt; } &gt; &gt; let bloom_filter = self.context.thread_local.bloom_filter.filter(); &gt; let nth_index_cache = &amp;mut self.context.thread_local.nth_index_cache; &gt; &gt;diff --git a/servo/components/style/stylesheet_set.rs b/servo/components/style/stylesheet_set.rs &gt;index a3b6e5cdc17e..19790aba9574 100644 &gt;--- a/servo/components/style/stylesheet_set.rs &gt;+++ b/servo/components/style/stylesheet_set.rs &gt;@@ -319,17 +319,18 @@ where &gt; // But we need to be marked as dirty, otherwise we'll never add the new &gt; // sheet! &gt; self.dirty = true; &gt; } &gt; &gt; fn insert_before(&amp;mut self, sheet: S, before_sheet: &amp;S) { &gt; debug_assert!(!self.contains(&amp;sheet)); &gt; &gt;- let index = self.entries &gt;+ let index = self &gt;+ .entries &gt; .iter() &gt; .position(|entry| entry.sheet == *before_sheet) &gt; .expect("`before_sheet` stylesheet not found"); &gt; &gt; // Inserting stylesheets somewhere but at the end changes the validity &gt; // of the cascade data, but not the invalidation data. &gt; self.set_data_validity_at_least(DataValidity::CascadeInvalid); &gt; self.entries.insert(index, StylesheetSetEntry::new(sheet)); &gt;diff --git a/servo/components/style/stylesheets/document_rule.rs b/servo/components/style/stylesheets/document_rule.rs &gt;index 56750ae7b66f..50e5433b86c6 100644 &gt;--- a/servo/components/style/stylesheets/document_rule.rs &gt;+++ b/servo/components/style/stylesheets/document_rule.rs &gt;@@ -31,18 +31,18 @@ pub struct DocumentRule { &gt; pub source_location: SourceLocation, &gt; } &gt; &gt; impl DocumentRule { &gt; /// Measure heap usage. &gt; #[cfg(feature = "gecko")] &gt; pub fn size_of(&amp;self, guard: &amp;SharedRwLockReadGuard, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; // Measurement of other fields may be added later. &gt;- self.rules.unconditional_shallow_size_of(ops) + &gt;- self.rules.read_with(guard).size_of(guard, ops) &gt;+ self.rules.unconditional_shallow_size_of(ops) &gt;+ + self.rules.read_with(guard).size_of(guard, ops) &gt; } &gt; } &gt; &gt; impl ToCssWithGuard for DocumentRule { &gt; fn to_css(&amp;self, guard: &amp;SharedRwLockReadGuard, dest: &amp;mut CssStringWriter) -&gt; fmt::Result { &gt; dest.write_str("@-moz-document ")?; &gt; self.condition.to_css(&amp;mut CssWriter::new(dest))?; &gt; dest.write_str(" {")?; &gt;@@ -104,44 +104,43 @@ pub enum DocumentMatchingFunction { &gt; Domain(String), &gt; /// Regular expression matching function. It evaluates to true &gt; /// whenever the regular expression matches the entirety of the URL &gt; /// of the document being styled. &gt; #[css(function)] &gt; Regexp(String), &gt; /// Matching function for a media document. &gt; #[css(function)] &gt;- MediaDocument(MediaDocumentKind) &gt;+ MediaDocument(MediaDocumentKind), &gt; } &gt; &gt; macro_rules! parse_quoted_or_unquoted_string { &gt; ($input:ident, $url_matching_function:expr) =&gt; { &gt; $input.parse_nested_block(|input| { &gt; let start = input.position(); &gt; input &gt; .parse_entirely(|input| { &gt; let string = input.expect_string()?; &gt; Ok($url_matching_function(string.as_ref().to_owned())) &gt;- }) &gt;- .or_else(|_: ParseError| { &gt;+ }).or_else(|_: ParseError| { &gt; while let Ok(_) = input.next() {} &gt; Ok($url_matching_function(input.slice_from(start).to_string())) &gt; }) &gt; }) &gt; }; &gt; } &gt; &gt; impl DocumentMatchingFunction { &gt; /// Parse a URL matching function for a`@document` rule's condition. &gt; pub fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; if let Ok(url) = input.try(|input| CssUrl::parse(context, input)) { &gt;- return Ok(DocumentMatchingFunction::Url(url)) &gt;+ return Ok(DocumentMatchingFunction::Url(url)); &gt; } &gt; &gt; let location = input.current_source_location(); &gt; let function = input.expect_function()?.clone(); &gt; match_ignore_ascii_case! { &amp;function, &gt; "url-prefix" =&gt; { &gt; parse_quoted_or_unquoted_string!(input, DocumentMatchingFunction::UrlPrefix) &gt; } &gt;@@ -176,32 +175,32 @@ impl DocumentMatchingFunction { &gt; use gecko_bindings::structs::DocumentMatchingFunction as GeckoDocumentMatchingFunction; &gt; use nsstring::nsCStr; &gt; &gt; let func = match *self { &gt; DocumentMatchingFunction::Url(_) =&gt; GeckoDocumentMatchingFunction::URL, &gt; DocumentMatchingFunction::UrlPrefix(_) =&gt; GeckoDocumentMatchingFunction::URLPrefix, &gt; DocumentMatchingFunction::Domain(_) =&gt; GeckoDocumentMatchingFunction::Domain, &gt; DocumentMatchingFunction::Regexp(_) =&gt; GeckoDocumentMatchingFunction::RegExp, &gt;- DocumentMatchingFunction::MediaDocument(_) =&gt; GeckoDocumentMatchingFunction::MediaDocument, &gt;+ DocumentMatchingFunction::MediaDocument(_) =&gt; { &gt;+ GeckoDocumentMatchingFunction::MediaDocument &gt;+ } &gt; }; &gt; &gt; let pattern = nsCStr::from(match *self { &gt; DocumentMatchingFunction::Url(ref url) =&gt; url.as_str(), &gt;- DocumentMatchingFunction::UrlPrefix(ref pat) | &gt;- DocumentMatchingFunction::Domain(ref pat) | &gt;- DocumentMatchingFunction::Regexp(ref pat) =&gt; pat, &gt;- DocumentMatchingFunction::MediaDocument(kind) =&gt; { &gt;- match kind { &gt;- MediaDocumentKind::All =&gt; "all", &gt;- MediaDocumentKind::Image =&gt; "image", &gt;- MediaDocumentKind::Plugin =&gt; "plugin", &gt;- MediaDocumentKind::Video =&gt; "video", &gt;- } &gt;- } &gt;+ DocumentMatchingFunction::UrlPrefix(ref pat) &gt;+ | DocumentMatchingFunction::Domain(ref pat) &gt;+ | DocumentMatchingFunction::Regexp(ref pat) =&gt; pat, &gt;+ DocumentMatchingFunction::MediaDocument(kind) =&gt; match kind { &gt;+ MediaDocumentKind::All =&gt; "all", &gt;+ MediaDocumentKind::Image =&gt; "image", &gt;+ MediaDocumentKind::Plugin =&gt; "plugin", &gt;+ MediaDocumentKind::Video =&gt; "video", &gt;+ }, &gt; }); &gt; unsafe { Gecko_DocumentRule_UseForPresentation(device.pres_context(), &amp;*pattern, func) } &gt; } &gt; &gt; #[cfg(not(feature = "gecko"))] &gt; /// Evaluate a URL matching function. &gt; pub fn evaluate(&amp;self, _: &amp;Device) -&gt; bool { &gt; false &gt;diff --git a/servo/components/style/stylesheets/font_feature_values_rule.rs b/servo/components/style/stylesheets/font_feature_values_rule.rs &gt;index c70a46c1c9d2..f1edaa2ea6b2 100644 &gt;--- a/servo/components/style/stylesheets/font_feature_values_rule.rs &gt;+++ b/servo/components/style/stylesheets/font_feature_values_rule.rs &gt;@@ -1,33 +1,33 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! The [`@font-feature-values`][font-feature-values] at-rule. &gt; //! &gt; //! [font-feature-values]: https://drafts.csswg.org/css-fonts-3/#at-font-feature-values-rule &gt; &gt;-use Atom; &gt; use cssparser::{AtRuleParser, AtRuleType, BasicParseErrorKind, CowRcStr}; &gt; use cssparser::{DeclarationListParser, DeclarationParser, Parser}; &gt; use cssparser::{QualifiedRuleParser, RuleListParser, SourceLocation, Token}; &gt; use error_reporting::ContextualParseError; &gt; #[cfg(feature = "gecko")] &gt; use gecko_bindings::bindings::Gecko_AppendFeatureValueHashEntry; &gt; #[cfg(feature = "gecko")] &gt; use gecko_bindings::structs::{self, gfxFontFeatureValueSet, nsTArray}; &gt; use parser::{Parse, ParserContext}; &gt; use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; &gt; use std::fmt::{self, Write}; &gt; use str::CssStringWriter; &gt; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt; use stylesheets::CssRuleType; &gt; use values::computed::font::FamilyName; &gt; use values::serialize_atom_identifier; &gt;+use Atom; &gt; &gt; /// A @font-feature-values block declaration. &gt; /// It is `&lt;ident&gt;: &lt;integer&gt;+`. &gt; /// This struct can take 3 value types. &gt; /// - `SingleValue` is to keep just one unsigned integer value. &gt; /// - `PairValues` is to keep one or two unsigned integer values. &gt; /// - `VectorValues` is to keep a list of unsigned integer values. &gt; #[derive(Clone, Debug, PartialEq)] &gt;@@ -65,20 +65,21 @@ impl Parse for SingleValue { &gt; fn parse&lt;'i, 't&gt;( &gt; _context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;SingleValue, ParseError&lt;'i&gt;&gt; { &gt; let location = input.current_source_location(); &gt; match *input.next()? { &gt; Token::Number { &gt; int_value: Some(v), .. &gt;- } if v &gt;= 0 =&gt; &gt;+ } &gt;+ if v &gt;= 0 =&gt; &gt; { &gt; Ok(SingleValue(v as u32)) &gt;- }, &gt;+ } &gt; ref t =&gt; Err(location.new_unexpected_token_error(t.clone())), &gt; } &gt; } &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt; impl ToGeckoFontFeatureValues for SingleValue { &gt; fn to_gecko_font_feature_values(&amp;self, array: &amp;mut nsTArray&lt;u32&gt;) { &gt;@@ -97,30 +98,32 @@ impl Parse for PairValues { &gt; fn parse&lt;'i, 't&gt;( &gt; _context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;PairValues, ParseError&lt;'i&gt;&gt; { &gt; let location = input.current_source_location(); &gt; let first = match *input.next()? { &gt; Token::Number { &gt; int_value: Some(a), .. &gt;- } if a &gt;= 0 =&gt; &gt;+ } &gt;+ if a &gt;= 0 =&gt; &gt; { &gt; a as u32 &gt;- }, &gt;+ } &gt; ref t =&gt; return Err(location.new_unexpected_token_error(t.clone())), &gt; }; &gt; let location = input.current_source_location(); &gt; match input.next() { &gt; Ok(&amp;Token::Number { &gt; int_value: Some(b), .. &gt;- }) if b &gt;= 0 =&gt; &gt;+ }) &gt;+ if b &gt;= 0 =&gt; &gt; { &gt; Ok(PairValues(first, Some(b as u32))) &gt;- }, &gt;+ } &gt; // It can't be anything other than number. &gt; Ok(t) =&gt; Err(location.new_unexpected_token_error(t.clone())), &gt; // It can be just one value. &gt; Err(_) =&gt; Ok(PairValues(first, None)), &gt; } &gt; } &gt; } &gt; &gt;@@ -149,17 +152,18 @@ impl Parse for VectorValues { &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;VectorValues, ParseError&lt;'i&gt;&gt; { &gt; let mut vec = vec![]; &gt; loop { &gt; let location = input.current_source_location(); &gt; match input.next() { &gt; Ok(&amp;Token::Number { &gt; int_value: Some(a), .. &gt;- }) if a &gt;= 0 =&gt; &gt;+ }) &gt;+ if a &gt;= 0 =&gt; &gt; { &gt; vec.push(a as u32); &gt; } &gt; // It can't be anything other than number. &gt; Ok(t) =&gt; return Err(location.new_unexpected_token_error(t.clone())), &gt; Err(_) =&gt; break, &gt; } &gt; } &gt;diff --git a/servo/components/style/stylesheets/import_rule.rs b/servo/components/style/stylesheets/import_rule.rs &gt;index 576cb31eff30..68b26734505c 100644 &gt;--- a/servo/components/style/stylesheets/import_rule.rs &gt;+++ b/servo/components/style/stylesheets/import_rule.rs &gt;@@ -72,17 +72,17 @@ impl DeepCloneWithLock for ImportSheet { &gt; use gecko::data::GeckoStyleSheet; &gt; use gecko_bindings::bindings; &gt; match *self { &gt; ImportSheet::Sheet(ref s) =&gt; { &gt; let clone = unsafe { &gt; bindings::Gecko_StyleSheet_Clone(s.raw() as *const _, params.reference_sheet) &gt; }; &gt; ImportSheet::Sheet(unsafe { GeckoStyleSheet::from_addrefed(clone) }) &gt;- }, &gt;+ } &gt; ImportSheet::Pending(ref p) =&gt; ImportSheet::Pending(p.clone()), &gt; } &gt; } &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt; impl StylesheetInDocument for ImportSheet { &gt; fn origin(&amp;self, _guard: &amp;SharedRwLockReadGuard) -&gt; Origin { &gt;@@ -199,15 +199,15 @@ impl ToCssWithGuard for ImportRule { &gt; fn to_css(&amp;self, guard: &amp;SharedRwLockReadGuard, dest: &amp;mut CssStringWriter) -&gt; fmt::Result { &gt; dest.write_str("@import ")?; &gt; self.url.to_css(&amp;mut CssWriter::new(dest))?; &gt; &gt; match self.stylesheet.media(guard) { &gt; Some(media) if !media.is_empty() =&gt; { &gt; dest.write_str(" ")?; &gt; media.to_css(&amp;mut CssWriter::new(dest))?; &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; }; &gt; &gt; dest.write_str(";") &gt; } &gt; } &gt;diff --git a/servo/components/style/stylesheets/keyframes_rule.rs b/servo/components/style/stylesheets/keyframes_rule.rs &gt;index 91bc14be5b59..633da6163df9 100644 &gt;--- a/servo/components/style/stylesheets/keyframes_rule.rs &gt;+++ b/servo/components/style/stylesheets/keyframes_rule.rs &gt;@@ -1,31 +1,31 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Keyframes: https://drafts.csswg.org/css-animations/#keyframes &gt; &gt;-use cssparser::{AtRuleParser, CowRcStr, Parser, ParserInput, QualifiedRuleParser, RuleListParser}; &gt; use cssparser::{parse_one_rule, DeclarationListParser, DeclarationParser, SourceLocation, Token}; &gt;+use cssparser::{AtRuleParser, CowRcStr, Parser, ParserInput, QualifiedRuleParser, RuleListParser}; &gt; use error_reporting::ContextualParseError; &gt; use parser::ParserContext; &gt;+use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction; &gt;+use properties::LonghandIdSet; &gt; use properties::{Importance, PropertyDeclaration}; &gt; use properties::{LonghandId, PropertyDeclarationBlock, PropertyId}; &gt; use properties::{PropertyDeclarationId, SourcePropertyDeclaration}; &gt;-use properties::LonghandIdSet; &gt;-use properties::longhands::transition_timing_function::single_value::SpecifiedValue as SpecifiedTimingFunction; &gt; use servo_arc::Arc; &gt; use shared_lock::{DeepCloneParams, DeepCloneWithLock, SharedRwLock, SharedRwLockReadGuard}; &gt; use shared_lock::{Locked, ToCssWithGuard}; &gt; use std::fmt::{self, Write}; &gt; use str::CssStringWriter; &gt; use style_traits::{CssWriter, ParseError, ParsingMode, StyleParseErrorKind, ToCss}; &gt;-use stylesheets::{CssRuleType, StylesheetContents}; &gt; use stylesheets::rule_parser::VendorPrefix; &gt;+use stylesheets::{CssRuleType, StylesheetContents}; &gt; use values::{serialize_percentage, KeyframesName}; &gt; &gt; /// A [`@keyframes`][keyframes] rule. &gt; /// &gt; /// [keyframes]: https://drafts.csswg.org/css-animations/#keyframes &gt; #[derive(Debug)] &gt; pub struct KeyframesRule { &gt; /// The name of the current animation. &gt;@@ -77,26 +77,24 @@ impl DeepCloneWithLock for KeyframesRule { &gt; fn deep_clone_with_lock( &gt; &amp;self, &gt; lock: &amp;SharedRwLock, &gt; guard: &amp;SharedRwLockReadGuard, &gt; params: &amp;DeepCloneParams, &gt; ) -&gt; Self { &gt; KeyframesRule { &gt; name: self.name.clone(), &gt;- keyframes: self.keyframes &gt;+ keyframes: self &gt;+ .keyframes &gt; .iter() &gt; .map(|x| { &gt;- Arc::new(lock.wrap(x.read_with(guard).deep_clone_with_lock( &gt;- lock, &gt;- guard, &gt;- params, &gt;- ))) &gt;- }) &gt;- .collect(), &gt;+ Arc::new( &gt;+ lock.wrap(x.read_with(guard).deep_clone_with_lock(lock, guard, params)), &gt;+ ) &gt;+ }).collect(), &gt; vendor_prefix: self.vendor_prefix.clone(), &gt; source_location: self.source_location.clone(), &gt; } &gt; } &gt; } &gt; &gt; /// A number from 0 to 1, indicating the percentage of the animation when this &gt; /// keyframe should run. &gt;@@ -130,27 +128,28 @@ impl KeyframePercentage { &gt; KeyframePercentage(value) &gt; } &gt; &gt; fn parse&lt;'i, 't&gt;(input: &amp;mut Parser&lt;'i, 't&gt;) -&gt; Result&lt;KeyframePercentage, ParseError&lt;'i&gt;&gt; { &gt; let token = input.next()?.clone(); &gt; match token { &gt; Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("from") =&gt; { &gt; Ok(KeyframePercentage::new(0.)) &gt;- }, &gt;+ } &gt; Token::Ident(ref identifier) if identifier.as_ref().eq_ignore_ascii_case("to") =&gt; { &gt; Ok(KeyframePercentage::new(1.)) &gt;- }, &gt;+ } &gt; Token::Percentage { &gt; unit_value: percentage, &gt; .. &gt;- } if percentage &gt;= 0. &amp;&amp; percentage &lt;= 1. =&gt; &gt;+ } &gt;+ if percentage &gt;= 0. &amp;&amp; percentage &lt;= 1. =&gt; &gt; { &gt; Ok(KeyframePercentage::new(percentage)) &gt;- }, &gt;+ } &gt; _ =&gt; Err(input.new_unexpected_token_error(token)), &gt; } &gt; } &gt; } &gt; &gt; /// A keyframes selector is a list of percentages or from/to symbols, which are &gt; /// converted at parse time to percentages. &gt; #[css(comma)] &gt;@@ -255,18 +254,20 @@ impl DeepCloneWithLock for Keyframe { &gt; /// declarations to apply. &gt; /// &gt; /// TODO: Find a better name for this? &gt; #[derive(Clone, Debug, MallocSizeOf)] &gt; pub enum KeyframesStepValue { &gt; /// A step formed by a declaration block specified by the CSS. &gt; Declarations { &gt; /// The declaration block per se. &gt;- #[cfg_attr(feature = "gecko", &gt;- ignore_malloc_size_of = "XXX: Primary ref, measure if DMD says it's worthwhile")] &gt;+ #[cfg_attr( &gt;+ feature = "gecko", &gt;+ ignore_malloc_size_of = "XXX: Primary ref, measure if DMD says it's worthwhile" &gt;+ )] &gt; #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] &gt; block: Arc&lt;Locked&lt;PropertyDeclarationBlock&gt;&gt;, &gt; }, &gt; /// A synthetic step computed from the current computed values at the time &gt; /// of the animation. &gt; ComputedValues, &gt; } &gt; &gt;@@ -320,31 +321,30 @@ impl KeyframesStep { &gt; return None; &gt; } &gt; match self.value { &gt; KeyframesStepValue::Declarations { ref block } =&gt; { &gt; let guard = block.read_with(guard); &gt; let (declaration, _) = guard &gt; .get(PropertyDeclarationId::Longhand( &gt; LonghandId::AnimationTimingFunction, &gt;- )) &gt;- .unwrap(); &gt;+ )).unwrap(); &gt; match *declaration { &gt; PropertyDeclaration::AnimationTimingFunction(ref value) =&gt; { &gt; // Use the first value. &gt; Some(value.0[0]) &gt;- }, &gt;+ } &gt; PropertyDeclaration::CSSWideKeyword(..) =&gt; None, &gt; PropertyDeclaration::WithVariables(..) =&gt; None, &gt; _ =&gt; panic!(), &gt; } &gt;- }, &gt;+ } &gt; KeyframesStepValue::ComputedValues =&gt; { &gt; panic!("Shouldn't happen to set animation-timing-function in missing keyframes") &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// This structure represents a list of animation steps computed from the list &gt; /// of keyframes, in order. &gt; /// &gt; /// It only takes into account animable properties. &gt;@@ -494,17 +494,17 @@ pub fn parse_keyframe_list( &gt; RuleListParser::new_for_nested_rule( &gt; input, &gt; KeyframeListParser { &gt; context: context, &gt; shared_lock: shared_lock, &gt; declarations: &amp;mut declarations, &gt; }, &gt; ).filter_map(Result::ok) &gt;- .collect() &gt;+ .collect() &gt; } &gt; &gt; impl&lt;'a, 'i&gt; AtRuleParser&lt;'i&gt; for KeyframeListParser&lt;'a&gt; { &gt; type PreludeNoBlock = (); &gt; type PreludeBlock = (); &gt; type AtRule = Arc&lt;Locked&lt;Keyframe&gt;&gt;; &gt; type Error = StyleParseErrorKind&lt;'i&gt;; &gt; } &gt;@@ -519,17 +519,17 @@ impl&lt;'a, 'i&gt; QualifiedRuleParser&lt;'i&gt; for KeyframeListParser&lt;'a&gt; { &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self::Prelude, ParseError&lt;'i&gt;&gt; { &gt; let start_position = input.position(); &gt; KeyframeSelector::parse(input).map_err(|e| { &gt; let location = e.location; &gt; let error = ContextualParseError::InvalidKeyframeRule( &gt; input.slice_from(start_position), &gt; e.clone(), &gt;- ); &gt;+ ); &gt; self.context.log_css_error(location, error); &gt; e &gt; }) &gt; } &gt; &gt; fn parse_block&lt;'t&gt;( &gt; &amp;mut self, &gt; selector: Self::Prelude, &gt;@@ -546,28 +546,25 @@ impl&lt;'a, 'i&gt; QualifiedRuleParser&lt;'i&gt; for KeyframeListParser&lt;'a&gt; { &gt; context: &amp;context, &gt; declarations: self.declarations, &gt; }; &gt; let mut iter = DeclarationListParser::new(input, parser); &gt; let mut block = PropertyDeclarationBlock::new(); &gt; while let Some(declaration) = iter.next() { &gt; match declaration { &gt; Ok(()) =&gt; { &gt;- block.extend( &gt;- iter.parser.declarations.drain(), &gt;- Importance::Normal, &gt;- ); &gt;- }, &gt;+ block.extend(iter.parser.declarations.drain(), Importance::Normal); &gt;+ } &gt; Err((error, slice)) =&gt; { &gt; iter.parser.declarations.clear(); &gt; let location = error.location; &gt; let error = &gt; ContextualParseError::UnsupportedKeyframePropertyDeclaration(slice, error); &gt; context.log_css_error(location, error); &gt;- }, &gt;+ } &gt; } &gt; // `parse_important` is not called here, `!important` is not allowed in keyframe blocks. &gt; } &gt; Ok(Arc::new(self.shared_lock.wrap(Keyframe { &gt; selector, &gt; block: Arc::new(self.shared_lock.wrap(block)), &gt; source_location, &gt; }))) &gt;@@ -593,19 +590,19 @@ impl&lt;'a, 'b, 'i&gt; DeclarationParser&lt;'i&gt; for KeyframeDeclarationParser&lt;'a, 'b&gt; { &gt; &gt; fn parse_value&lt;'t&gt;( &gt; &amp;mut self, &gt; name: CowRcStr&lt;'i&gt;, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;(), ParseError&lt;'i&gt;&gt; { &gt; let id = match PropertyId::parse(&amp;name, self.context) { &gt; Ok(id) =&gt; id, &gt;- Err(()) =&gt; return Err(input.new_custom_error( &gt;- StyleParseErrorKind::UnknownProperty(name) &gt;- )), &gt;+ Err(()) =&gt; { &gt;+ return Err(input.new_custom_error(StyleParseErrorKind::UnknownProperty(name))) &gt;+ } &gt; }; &gt; &gt; // TODO(emilio): Shouldn't this use parse_entirely? &gt; PropertyDeclaration::parse_into(self.declarations, id, self.context, input)?; &gt; &gt; // In case there is still unparsed text in the declaration, we should &gt; // roll back. &gt; input.expect_exhausted()?; &gt;diff --git a/servo/components/style/stylesheets/media_rule.rs b/servo/components/style/stylesheets/media_rule.rs &gt;index 4ae54c18f2b0..791a5c276caf 100644 &gt;--- a/servo/components/style/stylesheets/media_rule.rs &gt;+++ b/servo/components/style/stylesheets/media_rule.rs &gt;@@ -31,18 +31,18 @@ pub struct MediaRule { &gt; pub source_location: SourceLocation, &gt; } &gt; &gt; impl MediaRule { &gt; /// Measure heap usage. &gt; #[cfg(feature = "gecko")] &gt; pub fn size_of(&amp;self, guard: &amp;SharedRwLockReadGuard, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; // Measurement of other fields may be added later. &gt;- self.rules.unconditional_shallow_size_of(ops) + &gt;- self.rules.read_with(guard).size_of(guard, ops) &gt;+ self.rules.unconditional_shallow_size_of(ops) &gt;+ + self.rules.read_with(guard).size_of(guard, ops) &gt; } &gt; } &gt; &gt; impl ToCssWithGuard for MediaRule { &gt; // Serialization of MediaRule is not specced. &gt; // https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSMediaRule &gt; fn to_css(&amp;self, guard: &amp;SharedRwLockReadGuard, dest: &amp;mut CssStringWriter) -&gt; fmt::Result { &gt; dest.write_str("@media ")?; &gt;diff --git a/servo/components/style/stylesheets/mod.rs b/servo/components/style/stylesheets/mod.rs &gt;index e3641f3e5151..657af72c4706 100644 &gt;--- a/servo/components/style/stylesheets/mod.rs &gt;+++ b/servo/components/style/stylesheets/mod.rs &gt;@@ -40,35 +40,35 @@ pub use self::font_face_rule::FontFaceRule; &gt; pub use self::font_feature_values_rule::FontFeatureValuesRule; &gt; pub use self::import_rule::ImportRule; &gt; pub use self::keyframes_rule::KeyframesRule; &gt; pub use self::loader::StylesheetLoader; &gt; pub use self::media_rule::MediaRule; &gt; pub use self::namespace_rule::NamespaceRule; &gt; pub use self::origin::{Origin, OriginSet, OriginSetIterator, PerOrigin, PerOriginIter}; &gt; pub use self::page_rule::PageRule; &gt;-pub use self::rule_parser::{State, TopLevelRuleParser, InsertRuleContext}; &gt; pub use self::rule_list::{CssRules, CssRulesHelpers}; &gt;+pub use self::rule_parser::{InsertRuleContext, State, TopLevelRuleParser}; &gt; pub use self::rules_iterator::{AllRules, EffectiveRules}; &gt; pub use self::rules_iterator::{NestedRuleIterationCondition, RulesIterator}; &gt;+pub use self::style_rule::StyleRule; &gt; pub use self::stylesheet::{DocumentStyleSheet, Namespaces, Stylesheet}; &gt; pub use self::stylesheet::{StylesheetContents, StylesheetInDocument, UserAgentStylesheets}; &gt;-pub use self::style_rule::StyleRule; &gt; pub use self::supports_rule::SupportsRule; &gt; pub use self::viewport_rule::ViewportRule; &gt; &gt; /// Extra data that the backend may need to resolve url values. &gt; #[cfg(not(feature = "gecko"))] &gt; pub type UrlExtraData = ::servo_url::ServoUrl; &gt; &gt; /// Extra data that the backend may need to resolve url values. &gt; #[cfg(feature = "gecko")] &gt; #[derive(Clone, PartialEq)] &gt; pub struct UrlExtraData( &gt;- pub ::gecko_bindings::sugar::refptr::RefPtr&lt;::gecko_bindings::structs::URLExtraData&gt; &gt;+ pub ::gecko_bindings::sugar::refptr::RefPtr&lt;::gecko_bindings::structs::URLExtraData&gt;, &gt; ); &gt; &gt; #[cfg(feature = "gecko")] &gt; impl UrlExtraData { &gt; /// True if this URL scheme is chrome. &gt; #[inline] &gt; pub fn is_chrome(&amp;self) -&gt; bool { &gt; self.0.mIsChrome &gt;@@ -83,35 +83,38 @@ impl UrlExtraData { &gt; pub unsafe fn from_ptr_ref(ptr: &amp;*mut ::gecko_bindings::structs::URLExtraData) -&gt; &amp;Self { &gt; ::std::mem::transmute(ptr) &gt; } &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt; impl fmt::Debug for UrlExtraData { &gt; fn fmt(&amp;self, formatter: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- use gecko_bindings::{structs, bindings}; &gt;+ use gecko_bindings::{bindings, structs}; &gt; &gt; struct DebugURI(*mut structs::nsIURI); &gt; impl fmt::Debug for DebugURI { &gt; fn fmt(&amp;self, formatter: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; use nsstring::nsCString; &gt; let mut spec = nsCString::new(); &gt; unsafe { &gt; bindings::Gecko_nsIURI_Debug(self.0, &amp;mut spec); &gt; } &gt; spec.fmt(formatter) &gt; } &gt; } &gt; &gt;- formatter.debug_struct("URLExtraData") &gt;+ formatter &gt;+ .debug_struct("URLExtraData") &gt; .field("is_chrome", &amp;self.is_chrome()) &gt; .field("base", &amp;DebugURI(self.0.mBaseURI.raw::&lt;structs::nsIURI&gt;())) &gt;- .field("referrer", &amp;DebugURI(self.0.mReferrer.raw::&lt;structs::nsIURI&gt;())) &gt;- .finish() &gt;+ .field( &gt;+ "referrer", &gt;+ &amp;DebugURI(self.0.mReferrer.raw::&lt;structs::nsIURI&gt;()), &gt;+ ).finish() &gt; } &gt; } &gt; &gt; // XXX We probably need to figure out whether we should mark Eq here. &gt; // It is currently marked so because properties::UnparsedValue wants Eq. &gt; #[cfg(feature = "gecko")] &gt; impl Eq for UrlExtraData {} &gt; &gt;@@ -147,39 +150,39 @@ impl CssRule { &gt; CssRule::Namespace(_) =&gt; 0, &gt; &gt; // We don't need to measure ImportRule::stylesheet because we measure &gt; // it on the C++ side in the child list of the ServoStyleSheet. &gt; CssRule::Import(_) =&gt; 0, &gt; &gt; CssRule::Style(ref lock) =&gt; { &gt; lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops) &gt;- }, &gt;+ } &gt; &gt; CssRule::Media(ref lock) =&gt; { &gt; lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops) &gt;- }, &gt;+ } &gt; &gt; CssRule::FontFace(_) =&gt; 0, &gt; CssRule::FontFeatureValues(_) =&gt; 0, &gt; CssRule::CounterStyle(_) =&gt; 0, &gt; CssRule::Viewport(_) =&gt; 0, &gt; CssRule::Keyframes(_) =&gt; 0, &gt; &gt; CssRule::Supports(ref lock) =&gt; { &gt; lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops) &gt;- }, &gt;+ } &gt; &gt; CssRule::Page(ref lock) =&gt; { &gt; lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops) &gt;- }, &gt;+ } &gt; &gt; CssRule::Document(ref lock) =&gt; { &gt; lock.unconditional_shallow_size_of(ops) + lock.read_with(guard).size_of(guard, ops) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; #[allow(missing_docs)] &gt; #[derive(Clone, Copy, Debug, Eq, PartialEq)] &gt; pub enum CssRuleType { &gt; // https://drafts.csswg.org/cssom/#the-cssrule-interface &gt;@@ -279,104 +282,91 @@ impl CssRule { &gt; loader, &gt; state, &gt; dom_error: None, &gt; namespaces: &amp;mut *guard, &gt; insert_rule_context: Some(insert_rule_context), &gt; }; &gt; &gt; parse_one_rule(&amp;mut input, &amp;mut rule_parser) &gt;- .map_err(|_| { &gt;- rule_parser.dom_error.unwrap_or(RulesMutateError::Syntax) &gt;- }) &gt;+ .map_err(|_| rule_parser.dom_error.unwrap_or(RulesMutateError::Syntax)) &gt; } &gt; } &gt; &gt; impl DeepCloneWithLock for CssRule { &gt; /// Deep clones this CssRule. &gt; fn deep_clone_with_lock( &gt; &amp;self, &gt; lock: &amp;SharedRwLock, &gt; guard: &amp;SharedRwLockReadGuard, &gt; params: &amp;DeepCloneParams, &gt; ) -&gt; CssRule { &gt; match *self { &gt; CssRule::Namespace(ref arc) =&gt; { &gt; let rule = arc.read_with(guard); &gt; CssRule::Namespace(Arc::new(lock.wrap(rule.clone()))) &gt;- }, &gt;+ } &gt; CssRule::Import(ref arc) =&gt; { &gt;- let rule = arc.read_with(guard) &gt;+ let rule = arc &gt;+ .read_with(guard) &gt; .deep_clone_with_lock(lock, guard, params); &gt; CssRule::Import(Arc::new(lock.wrap(rule))) &gt;- }, &gt;+ } &gt; CssRule::Style(ref arc) =&gt; { &gt; let rule = arc.read_with(guard); &gt;- CssRule::Style(Arc::new(lock.wrap(rule.deep_clone_with_lock( &gt;- lock, &gt;- guard, &gt;- params, &gt;- )))) &gt;- }, &gt;+ CssRule::Style(Arc::new( &gt;+ lock.wrap(rule.deep_clone_with_lock(lock, guard, params)), &gt;+ )) &gt;+ } &gt; CssRule::Media(ref arc) =&gt; { &gt; let rule = arc.read_with(guard); &gt;- CssRule::Media(Arc::new(lock.wrap(rule.deep_clone_with_lock( &gt;- lock, &gt;- guard, &gt;- params, &gt;- )))) &gt;- }, &gt;+ CssRule::Media(Arc::new( &gt;+ lock.wrap(rule.deep_clone_with_lock(lock, guard, params)), &gt;+ )) &gt;+ } &gt; CssRule::FontFace(ref arc) =&gt; { &gt; let rule = arc.read_with(guard); &gt; CssRule::FontFace(Arc::new(lock.wrap(rule.clone()))) &gt;- }, &gt;+ } &gt; CssRule::FontFeatureValues(ref arc) =&gt; { &gt; let rule = arc.read_with(guard); &gt; CssRule::FontFeatureValues(Arc::new(lock.wrap(rule.clone()))) &gt;- }, &gt;+ } &gt; CssRule::CounterStyle(ref arc) =&gt; { &gt; let rule = arc.read_with(guard); &gt; CssRule::CounterStyle(Arc::new(lock.wrap(rule.clone()))) &gt;- }, &gt;+ } &gt; CssRule::Viewport(ref arc) =&gt; { &gt; let rule = arc.read_with(guard); &gt; CssRule::Viewport(Arc::new(lock.wrap(rule.clone()))) &gt;- }, &gt;+ } &gt; CssRule::Keyframes(ref arc) =&gt; { &gt; let rule = arc.read_with(guard); &gt;- CssRule::Keyframes(Arc::new(lock.wrap(rule.deep_clone_with_lock( &gt;- lock, &gt;- guard, &gt;- params, &gt;- )))) &gt;- }, &gt;+ CssRule::Keyframes(Arc::new( &gt;+ lock.wrap(rule.deep_clone_with_lock(lock, guard, params)), &gt;+ )) &gt;+ } &gt; CssRule::Supports(ref arc) =&gt; { &gt; let rule = arc.read_with(guard); &gt;- CssRule::Supports(Arc::new(lock.wrap(rule.deep_clone_with_lock( &gt;- lock, &gt;- guard, &gt;- params, &gt;- )))) &gt;- }, &gt;+ CssRule::Supports(Arc::new( &gt;+ lock.wrap(rule.deep_clone_with_lock(lock, guard, params)), &gt;+ )) &gt;+ } &gt; CssRule::Page(ref arc) =&gt; { &gt; let rule = arc.read_with(guard); &gt;- CssRule::Page(Arc::new(lock.wrap(rule.deep_clone_with_lock( &gt;- lock, &gt;- guard, &gt;- params, &gt;- )))) &gt;- }, &gt;+ CssRule::Page(Arc::new( &gt;+ lock.wrap(rule.deep_clone_with_lock(lock, guard, params)), &gt;+ )) &gt;+ } &gt; CssRule::Document(ref arc) =&gt; { &gt; let rule = arc.read_with(guard); &gt;- CssRule::Document(Arc::new(lock.wrap(rule.deep_clone_with_lock( &gt;- lock, &gt;- guard, &gt;- params, &gt;- )))) &gt;- }, &gt;+ CssRule::Document(Arc::new( &gt;+ lock.wrap(rule.deep_clone_with_lock(lock, guard, params)), &gt;+ )) &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl ToCssWithGuard for CssRule { &gt; // https://drafts.csswg.org/cssom/#serialize-a-css-rule &gt; fn to_css(&amp;self, guard: &amp;SharedRwLockReadGuard, dest: &amp;mut CssStringWriter) -&gt; fmt::Result { &gt; match *self { &gt;diff --git a/servo/components/style/stylesheets/namespace_rule.rs b/servo/components/style/stylesheets/namespace_rule.rs &gt;index f28f2ba0881a..1f927f08f172 100644 &gt;--- a/servo/components/style/stylesheets/namespace_rule.rs &gt;+++ b/servo/components/style/stylesheets/namespace_rule.rs &gt;@@ -1,19 +1,19 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! The `@namespace` at-rule. &gt; &gt;-use {Namespace, Prefix}; &gt; use cssparser::SourceLocation; &gt; use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard}; &gt; use std::fmt::{self, Write}; &gt; use str::CssStringWriter; &gt;+use {Namespace, Prefix}; &gt; &gt; /// A `@namespace` rule. &gt; #[derive(Clone, Debug, PartialEq)] &gt; #[allow(missing_docs)] &gt; pub struct NamespaceRule { &gt; /// The namespace prefix, and `None` if it's the default Namespace &gt; pub prefix: Option&lt;Prefix&gt;, &gt; /// The actual namespace url. &gt;diff --git a/servo/components/style/stylesheets/rule_list.rs b/servo/components/style/stylesheets/rule_list.rs &gt;index 35edc22b3dac..280f879a77b9 100644 &gt;--- a/servo/components/style/stylesheets/rule_list.rs &gt;+++ b/servo/components/style/stylesheets/rule_list.rs &gt;@@ -6,20 +6,20 @@ &gt; &gt; #[cfg(feature = "gecko")] &gt; use malloc_size_of::{MallocShallowSizeOf, MallocSizeOfOps}; &gt; use servo_arc::{Arc, RawOffsetArc}; &gt; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked}; &gt; use shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; &gt; use std::fmt::{self, Write}; &gt; use str::CssStringWriter; &gt;-use stylesheets::{CssRule, RulesMutateError}; &gt; use stylesheets::loader::StylesheetLoader; &gt; use stylesheets::rule_parser::{InsertRuleContext, State}; &gt; use stylesheets::stylesheet::StylesheetContents; &gt;+use stylesheets::{CssRule, RulesMutateError}; &gt; &gt; /// A list of CSS rules. &gt; #[derive(Debug)] &gt; pub struct CssRules(pub Vec&lt;CssRule&gt;); &gt; &gt; impl CssRules { &gt; /// Whether this CSS rules is empty. &gt; pub fn is_empty(&amp;self) -&gt; bool { &gt;@@ -151,17 +151,21 @@ impl CssRulesHelpers for RawOffsetArc&lt;Locked&lt;CssRules&gt;&gt; { &gt; } &gt; &gt; // Computes the parser state at the given index &gt; let state = if nested { &gt; State::Body &gt; } else if index == 0 { &gt; State::Start &gt; } else { &gt;- rules.0.get(index - 1).map(CssRule::rule_state).unwrap_or(State::Body) &gt;+ rules &gt;+ .0 &gt;+ .get(index - 1) &gt;+ .map(CssRule::rule_state) &gt;+ .unwrap_or(State::Body) &gt; }; &gt; &gt; let insert_rule_context = InsertRuleContext { &gt; rule_list: &amp;rules.0, &gt; index, &gt; }; &gt; &gt; // Steps 3, 4, 5, 6 &gt;diff --git a/servo/components/style/stylesheets/rule_parser.rs b/servo/components/style/stylesheets/rule_parser.rs &gt;index d2f9b691ad4e..58c9cd9e732e 100644 &gt;--- a/servo/components/style/stylesheets/rule_parser.rs &gt;+++ b/servo/components/style/stylesheets/rule_parser.rs &gt;@@ -1,40 +1,40 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Parsing of the stylesheet contents. &gt; &gt;-use {Namespace, Prefix}; &gt; use counter_style::{parse_counter_style_body, parse_counter_style_name_definition}; &gt; use cssparser::{AtRuleParser, AtRuleType, Parser, QualifiedRuleParser, RuleListParser}; &gt; use cssparser::{BasicParseError, BasicParseErrorKind, CowRcStr, SourceLocation}; &gt; use error_reporting::ContextualParseError; &gt; use font_face::parse_font_face_block; &gt; use media_queries::MediaList; &gt; use parser::{Parse, ParserContext}; &gt; use properties::parse_property_declaration_list; &gt; use selector_parser::{SelectorImpl, SelectorParser}; &gt; use selectors::SelectorList; &gt; use servo_arc::Arc; &gt; use shared_lock::{Locked, SharedRwLock}; &gt; use str::starts_with_ignore_ascii_case; &gt; use style_traits::{ParseError, StyleParseErrorKind}; &gt;-use stylesheets::{CssRule, CssRuleType, CssRules, Origin, RulesMutateError, StylesheetLoader}; &gt;-use stylesheets::{DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule}; &gt;-use stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule}; &gt; use stylesheets::document_rule::DocumentCondition; &gt; use stylesheets::font_feature_values_rule::parse_family_name_list; &gt; use stylesheets::keyframes_rule::parse_keyframe_list; &gt; use stylesheets::stylesheet::Namespaces; &gt; use stylesheets::supports_rule::SupportsCondition; &gt; use stylesheets::viewport_rule; &gt;-use values::{CssUrl, CustomIdent, KeyframesName}; &gt;+use stylesheets::{CssRule, CssRuleType, CssRules, Origin, RulesMutateError, StylesheetLoader}; &gt;+use stylesheets::{DocumentRule, FontFeatureValuesRule, KeyframesRule, MediaRule}; &gt;+use stylesheets::{NamespaceRule, PageRule, StyleRule, SupportsRule, ViewportRule}; &gt; use values::computed::font::FamilyName; &gt;+use values::{CssUrl, CustomIdent, KeyframesName}; &gt;+use {Namespace, Prefix}; &gt; &gt; /// The information we need particularly to do CSSOM insertRule stuff. &gt; pub struct InsertRuleContext&lt;'a&gt; { &gt; /// The rule list we're about to insert into. &gt; pub rule_list: &amp;'a [CssRule], &gt; /// The index we're about to get inserted at. &gt; pub index: usize, &gt; } &gt;@@ -105,18 +105,19 @@ impl&lt;'b&gt; TopLevelRuleParser&lt;'b&gt; { &gt; if new_state &gt; next_rule_state { &gt; self.dom_error = Some(RulesMutateError::HierarchyRequest); &gt; return false; &gt; } &gt; &gt; // If there's anything that isn't a namespace rule (or import rule, but &gt; // we checked that already at the beginning), reject with a &gt; // StateError. &gt;- if new_state == State::Namespaces &amp;&amp; &gt;- ctx.rule_list[ctx.index..].iter().any(|r| !matches!(*r, CssRule::Namespace(..))) &gt;+ if new_state == State::Namespaces &amp;&amp; ctx.rule_list[ctx.index..] &gt;+ .iter() &gt;+ .any(|r| !matches!(*r, CssRule::Namespace(..))) &gt; { &gt; self.dom_error = Some(RulesMutateError::InvalidState); &gt; return false; &gt; } &gt; &gt; true &gt; } &gt; } &gt;@@ -222,17 +223,17 @@ impl&lt;'a, 'i&gt; AtRuleParser&lt;'i&gt; for TopLevelRuleParser&lt;'a&gt; { &gt; "charset" =&gt; { &gt; self.dom_error = Some(RulesMutateError::HierarchyRequest); &gt; return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedCharsetRule)) &gt; } &gt; _ =&gt; {} &gt; } &gt; &gt; if !self.check_state(State::Body) { &gt;- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt;+ return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt; &gt; AtRuleParser::parse_prelude(&amp;mut self.nested(), name, input) &gt; } &gt; &gt; #[inline] &gt; fn parse_block&lt;'t&gt;( &gt; &amp;mut self, &gt;@@ -249,83 +250,81 @@ impl&lt;'a, 'i&gt; AtRuleParser&lt;'i&gt; for TopLevelRuleParser&lt;'a&gt; { &gt; #[inline] &gt; fn rule_without_block( &gt; &amp;mut self, &gt; prelude: AtRuleNonBlockPrelude, &gt; source_location: SourceLocation, &gt; ) -&gt; CssRule { &gt; match prelude { &gt; AtRuleNonBlockPrelude::Import(url, media) =&gt; { &gt;- let loader = self.loader &gt;+ let loader = self &gt;+ .loader &gt; .expect("Expected a stylesheet loader for @import"); &gt; &gt; let import_rule = loader.request_stylesheet( &gt; url, &gt; source_location, &gt; &amp;self.context, &gt; &amp;self.shared_lock, &gt; media, &gt; ); &gt; &gt; self.state = State::Imports; &gt; CssRule::Import(import_rule) &gt;- }, &gt;+ } &gt; AtRuleNonBlockPrelude::Namespace(prefix, url) =&gt; { &gt; let prefix = if let Some(prefix) = prefix { &gt; self.namespaces.prefixes.insert(prefix.clone(), url.clone()); &gt; Some(prefix) &gt; } else { &gt; self.namespaces.default = Some(url.clone()); &gt; None &gt; }; &gt; &gt; self.state = State::Namespaces; &gt; CssRule::Namespace(Arc::new(self.shared_lock.wrap(NamespaceRule { &gt; prefix, &gt; url, &gt; source_location, &gt; }))) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a, 'i&gt; QualifiedRuleParser&lt;'i&gt; for TopLevelRuleParser&lt;'a&gt; { &gt; type Prelude = SelectorList&lt;SelectorImpl&gt;; &gt; type QualifiedRule = CssRule; &gt; type Error = StyleParseErrorKind&lt;'i&gt;; &gt; &gt; #[inline] &gt; fn parse_prelude&lt;'t&gt;( &gt; &amp;mut self, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self::Prelude, ParseError&lt;'i&gt;&gt; { &gt; if !self.check_state(State::Body) { &gt;- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt;+ return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt; &gt; QualifiedRuleParser::parse_prelude(&amp;mut self.nested(), input) &gt; } &gt; &gt; #[inline] &gt; fn parse_block&lt;'t&gt;( &gt; &amp;mut self, &gt; prelude: Self::Prelude, &gt; location: SourceLocation, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;CssRule, ParseError&lt;'i&gt;&gt; { &gt;- QualifiedRuleParser::parse_block( &gt;- &amp;mut self.nested(), &gt;- prelude, &gt;- location, &gt;- input, &gt;- ).map(|result| { &gt;- self.state = State::Body; &gt;- result &gt;- }) &gt;+ QualifiedRuleParser::parse_block(&amp;mut self.nested(), prelude, location, input).map( &gt;+ |result| { &gt;+ self.state = State::Body; &gt;+ result &gt;+ }, &gt;+ ) &gt; } &gt; } &gt; &gt; #[derive(Clone)] // shallow, relatively cheap .clone &gt; struct NestedRuleParser&lt;'a, 'b: 'a&gt; { &gt; stylesheet_origin: Origin, &gt; shared_lock: &amp;'a SharedRwLock, &gt; context: &amp;'a ParserContext&lt;'b&gt;, &gt;@@ -333,21 +332,17 @@ struct NestedRuleParser&lt;'a, 'b: 'a&gt; { &gt; } &gt; &gt; impl&lt;'a, 'b&gt; NestedRuleParser&lt;'a, 'b&gt; { &gt; fn parse_nested_rules( &gt; &amp;mut self, &gt; input: &amp;mut Parser, &gt; rule_type: CssRuleType, &gt; ) -&gt; Arc&lt;Locked&lt;CssRules&gt;&gt; { &gt;- let context = ParserContext::new_with_rule_type( &gt;- self.context, &gt;- rule_type, &gt;- self.namespaces, &gt;- ); &gt;+ let context = ParserContext::new_with_rule_type(self.context, rule_type, self.namespaces); &gt; &gt; let nested_parser = NestedRuleParser { &gt; stylesheet_origin: self.stylesheet_origin, &gt; shared_lock: self.shared_lock, &gt; context: &amp;context, &gt; namespaces: self.namespaces, &gt; }; &gt; &gt;@@ -355,17 +350,17 @@ impl&lt;'a, 'b&gt; NestedRuleParser&lt;'a, 'b&gt; { &gt; let mut rules = Vec::new(); &gt; while let Some(result) = iter.next() { &gt; match result { &gt; Ok(rule) =&gt; rules.push(rule), &gt; Err((error, slice)) =&gt; { &gt; let location = error.location; &gt; let error = ContextualParseError::InvalidRule(slice, error); &gt; self.context.log_css_error(location, error); &gt;- }, &gt;+ } &gt; } &gt; } &gt; CssRules::new(rules, self.shared_lock) &gt; } &gt; } &gt; &gt; impl&lt;'a, 'b, 'i&gt; AtRuleParser&lt;'i&gt; for NestedRuleParser&lt;'a, 'b&gt; { &gt; type PreludeNoBlock = AtRuleNonBlockPrelude; &gt;@@ -464,132 +459,115 @@ impl&lt;'a, 'b, 'i&gt; AtRuleParser&lt;'i&gt; for NestedRuleParser&lt;'a, 'b&gt; { &gt; self.context, &gt; CssRuleType::FontFace, &gt; self.namespaces, &gt; ); &gt; &gt; Ok(CssRule::FontFace(Arc::new(self.shared_lock.wrap( &gt; parse_font_face_block(&amp;context, input, source_location).into(), &gt; )))) &gt;- }, &gt;+ } &gt; AtRuleBlockPrelude::FontFeatureValues(family_names) =&gt; { &gt; let context = ParserContext::new_with_rule_type( &gt; self.context, &gt; CssRuleType::FontFeatureValues, &gt; self.namespaces, &gt; ); &gt; &gt; Ok(CssRule::FontFeatureValues(Arc::new(self.shared_lock.wrap( &gt;- FontFeatureValuesRule::parse( &gt;- &amp;context, &gt;- input, &gt;- family_names, &gt;- source_location, &gt;- ), &gt;+ FontFeatureValuesRule::parse(&amp;context, input, family_names, source_location), &gt; )))) &gt;- }, &gt;+ } &gt; AtRuleBlockPrelude::CounterStyle(name) =&gt; { &gt; let context = ParserContext::new_with_rule_type( &gt; self.context, &gt; CssRuleType::CounterStyle, &gt; self.namespaces, &gt; ); &gt; &gt;- Ok(CssRule::CounterStyle(Arc::new( &gt;- self.shared_lock.wrap( &gt;- parse_counter_style_body( &gt;- name, &gt;- &amp;context, &gt;- input, &gt;- source_location, &gt;- )?.into(), &gt;- ), &gt;- ))) &gt;- }, &gt;+ Ok(CssRule::CounterStyle(Arc::new(self.shared_lock.wrap( &gt;+ parse_counter_style_body(name, &amp;context, input, source_location)?.into(), &gt;+ )))) &gt;+ } &gt; AtRuleBlockPrelude::Media(media_queries) =&gt; { &gt; Ok(CssRule::Media(Arc::new(self.shared_lock.wrap(MediaRule { &gt; media_queries, &gt; rules: self.parse_nested_rules(input, CssRuleType::Media), &gt; source_location, &gt; })))) &gt;- }, &gt;+ } &gt; AtRuleBlockPrelude::Supports(condition) =&gt; { &gt; let eval_context = ParserContext::new_with_rule_type( &gt; self.context, &gt; CssRuleType::Style, &gt; self.namespaces, &gt; ); &gt; &gt; let enabled = condition.eval(&amp;eval_context); &gt; Ok(CssRule::Supports(Arc::new(self.shared_lock.wrap( &gt; SupportsRule { &gt; condition, &gt; rules: self.parse_nested_rules(input, CssRuleType::Supports), &gt; enabled, &gt; source_location, &gt; }, &gt; )))) &gt;- }, &gt;+ } &gt; AtRuleBlockPrelude::Viewport =&gt; { &gt; let context = ParserContext::new_with_rule_type( &gt; self.context, &gt; CssRuleType::Viewport, &gt; self.namespaces, &gt; ); &gt; &gt;- Ok(CssRule::Viewport(Arc::new(self.shared_lock.wrap( &gt;- ViewportRule::parse(&amp;context, input)?, &gt;- )))) &gt;- }, &gt;+ Ok(CssRule::Viewport(Arc::new( &gt;+ self.shared_lock.wrap(ViewportRule::parse(&amp;context, input)?), &gt;+ ))) &gt;+ } &gt; AtRuleBlockPrelude::Keyframes(name, vendor_prefix) =&gt; { &gt; let context = ParserContext::new_with_rule_type( &gt; self.context, &gt; CssRuleType::Keyframes, &gt; self.namespaces, &gt; ); &gt; &gt; Ok(CssRule::Keyframes(Arc::new(self.shared_lock.wrap( &gt; KeyframesRule { &gt; name, &gt;- keyframes: parse_keyframe_list( &gt;- &amp;context, &gt;- input, &gt;- self.shared_lock, &gt;- ), &gt;+ keyframes: parse_keyframe_list(&amp;context, input, self.shared_lock), &gt; vendor_prefix, &gt; source_location, &gt; }, &gt; )))) &gt;- }, &gt;+ } &gt; AtRuleBlockPrelude::Page =&gt; { &gt; let context = ParserContext::new_with_rule_type( &gt; self.context, &gt; CssRuleType::Page, &gt; self.namespaces, &gt; ); &gt; &gt;- let declarations = &gt;- parse_property_declaration_list(&amp;context, input); &gt;+ let declarations = parse_property_declaration_list(&amp;context, input); &gt; Ok(CssRule::Page(Arc::new(self.shared_lock.wrap(PageRule { &gt; block: Arc::new(self.shared_lock.wrap(declarations)), &gt; source_location, &gt; })))) &gt;- }, &gt;+ } &gt; AtRuleBlockPrelude::Document(condition) =&gt; { &gt; if !cfg!(feature = "gecko") { &gt; unreachable!() &gt; } &gt; Ok(CssRule::Document(Arc::new(self.shared_lock.wrap( &gt; DocumentRule { &gt; condition, &gt; rules: self.parse_nested_rules(input, CssRuleType::Document), &gt; source_location, &gt; }, &gt; )))) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl&lt;'a, 'b, 'i&gt; QualifiedRuleParser&lt;'i&gt; for NestedRuleParser&lt;'a, 'b&gt; { &gt; type Prelude = SelectorList&lt;SelectorImpl&gt;; &gt; type QualifiedRule = CssRule; &gt; type Error = StyleParseErrorKind&lt;'i&gt;; &gt;diff --git a/servo/components/style/stylesheets/rules_iterator.rs b/servo/components/style/stylesheets/rules_iterator.rs &gt;index b46e24c22c72..a93532750cbd 100644 &gt;--- a/servo/components/style/stylesheets/rules_iterator.rs &gt;+++ b/servo/components/style/stylesheets/rules_iterator.rs &gt;@@ -4,18 +4,18 @@ &gt; &gt; //! An iterator over a list of rules. &gt; &gt; use context::QuirksMode; &gt; use media_queries::Device; &gt; use shared_lock::SharedRwLockReadGuard; &gt; use smallvec::SmallVec; &gt; use std::slice; &gt;-use stylesheets::{CssRule, DocumentRule, ImportRule, MediaRule, SupportsRule}; &gt; use stylesheets::StylesheetInDocument; &gt;+use stylesheets::{CssRule, DocumentRule, ImportRule, MediaRule, SupportsRule}; &gt; &gt; /// An iterator over a list of rules. &gt; pub struct RulesIterator&lt;'a, 'b, C&gt; &gt; where &gt; 'b: 'a, &gt; C: NestedRuleIterationCondition + 'static, &gt; { &gt; device: &amp;'a Device, &gt;@@ -73,71 +73,68 @@ where &gt; let rule; &gt; let sub_iter = { &gt; let nested_iter = self.stack.last_mut().unwrap(); &gt; rule = match nested_iter.next() { &gt; Some(r) =&gt; r, &gt; None =&gt; { &gt; nested_iter_finished = true; &gt; continue; &gt;- }, &gt;+ } &gt; }; &gt; &gt; match *rule { &gt;- CssRule::Namespace(_) | &gt;- CssRule::Style(_) | &gt;- CssRule::FontFace(_) | &gt;- CssRule::CounterStyle(_) | &gt;- CssRule::Viewport(_) | &gt;- CssRule::Keyframes(_) | &gt;- CssRule::Page(_) | &gt;- CssRule::FontFeatureValues(_) =&gt; return Some(rule), &gt;+ CssRule::Namespace(_) &gt;+ | CssRule::Style(_) &gt;+ | CssRule::FontFace(_) &gt;+ | CssRule::CounterStyle(_) &gt;+ | CssRule::Viewport(_) &gt;+ | CssRule::Keyframes(_) &gt;+ | CssRule::Page(_) &gt;+ | CssRule::FontFeatureValues(_) =&gt; return Some(rule), &gt; CssRule::Import(ref import_rule) =&gt; { &gt; let import_rule = import_rule.read_with(self.guard); &gt; if !C::process_import( &gt; self.guard, &gt; self.device, &gt; self.quirks_mode, &gt; import_rule, &gt; ) { &gt; continue; &gt; } &gt;- import_rule &gt;- .stylesheet &gt;- .rules(self.guard) &gt;- .iter() &gt;- }, &gt;+ import_rule.stylesheet.rules(self.guard).iter() &gt;+ } &gt; CssRule::Document(ref doc_rule) =&gt; { &gt; let doc_rule = doc_rule.read_with(self.guard); &gt; if !C::process_document(self.guard, self.device, self.quirks_mode, doc_rule) &gt; { &gt; continue; &gt; } &gt; doc_rule.rules.read_with(self.guard).0.iter() &gt;- }, &gt;+ } &gt; CssRule::Media(ref lock) =&gt; { &gt; let media_rule = lock.read_with(self.guard); &gt; if !C::process_media(self.guard, self.device, self.quirks_mode, media_rule) &gt; { &gt; continue; &gt; } &gt; media_rule.rules.read_with(self.guard).0.iter() &gt;- }, &gt;+ } &gt; CssRule::Supports(ref lock) =&gt; { &gt; let supports_rule = lock.read_with(self.guard); &gt; if !C::process_supports( &gt; self.guard, &gt; self.device, &gt; self.quirks_mode, &gt; supports_rule, &gt; ) { &gt; continue; &gt; } &gt; supports_rule.rules.read_with(self.guard).0.iter() &gt;- }, &gt;+ } &gt; } &gt; }; &gt; &gt; self.stack.push(sub_iter); &gt; return Some(rule); &gt; } &gt; &gt; None &gt;diff --git a/servo/components/style/stylesheets/style_rule.rs b/servo/components/style/stylesheets/style_rule.rs &gt;index c161cc43ee21..90cc6eb8b6e6 100644 &gt;--- a/servo/components/style/stylesheets/style_rule.rs &gt;+++ b/servo/components/style/stylesheets/style_rule.rs &gt;@@ -1,19 +1,19 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! A style rule. &gt; &gt; use cssparser::SourceLocation; &gt; #[cfg(feature = "gecko")] &gt;-use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; &gt;-#[cfg(feature = "gecko")] &gt; use malloc_size_of::MallocUnconditionalShallowSizeOf; &gt;+#[cfg(feature = "gecko")] &gt;+use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; &gt; use properties::PropertyDeclarationBlock; &gt; use selector_parser::SelectorImpl; &gt; use selectors::SelectorList; &gt; use servo_arc::Arc; &gt; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked}; &gt; use shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; &gt; use std::fmt::{self, Write}; &gt; use str::CssStringWriter; &gt;@@ -46,18 +46,18 @@ impl DeepCloneWithLock for StyleRule { &gt; } &gt; &gt; impl StyleRule { &gt; /// Measure heap usage. &gt; #[cfg(feature = "gecko")] &gt; pub fn size_of(&amp;self, guard: &amp;SharedRwLockReadGuard, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; let mut n = 0; &gt; n += self.selectors.0.size_of(ops); &gt;- n += self.block.unconditional_shallow_size_of(ops) + &gt;- self.block.read_with(guard).size_of(ops); &gt;+ n += self.block.unconditional_shallow_size_of(ops) &gt;+ + self.block.read_with(guard).size_of(ops); &gt; n &gt; } &gt; } &gt; &gt; impl ToCssWithGuard for StyleRule { &gt; /// https://drafts.csswg.org/cssom/#serialize-a-css-rule CSSStyleRule &gt; fn to_css(&amp;self, guard: &amp;SharedRwLockReadGuard, dest: &amp;mut CssStringWriter) -&gt; fmt::Result { &gt; use cssparser::ToCss; &gt;diff --git a/servo/components/style/stylesheets/stylesheet.rs b/servo/components/style/stylesheets/stylesheet.rs &gt;index 02730f7090d5..68419d0ca74a 100644 &gt;--- a/servo/components/style/stylesheets/stylesheet.rs &gt;+++ b/servo/components/style/stylesheets/stylesheet.rs &gt;@@ -1,34 +1,36 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt;-use {Namespace, Prefix}; &gt; use context::QuirksMode; &gt; use cssparser::{Parser, ParserInput, RuleListParser}; &gt; use error_reporting::{ContextualParseError, ParseErrorReporter}; &gt; use fallible::FallibleVec; &gt; use fxhash::FxHashMap; &gt; use invalidation::media_queries::{MediaListKey, ToMediaListKey}; &gt; #[cfg(feature = "gecko")] &gt; use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf}; &gt; use media_queries::{Device, MediaList}; &gt; use parking_lot::RwLock; &gt; use parser::ParserContext; &gt; use servo_arc::Arc; &gt;-use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard}; &gt;+use shared_lock::{ &gt;+ DeepCloneParams, DeepCloneWithLock, Locked, SharedRwLock, SharedRwLockReadGuard, &gt;+}; &gt; use std::mem; &gt; use std::sync::atomic::{AtomicBool, Ordering}; &gt; use style_traits::ParsingMode; &gt;-use stylesheets::{CssRule, CssRules, Origin, UrlExtraData}; &gt; use stylesheets::loader::StylesheetLoader; &gt; use stylesheets::rule_parser::{State, TopLevelRuleParser}; &gt; use stylesheets::rules_iterator::{EffectiveRules, EffectiveRulesIterator}; &gt; use stylesheets::rules_iterator::{NestedRuleIterationCondition, RulesIterator}; &gt;+use stylesheets::{CssRule, CssRules, Origin, UrlExtraData}; &gt;+use {Namespace, Prefix}; &gt; &gt; /// This structure holds the user-agent and user stylesheets. &gt; pub struct UserAgentStylesheets { &gt; /// The lock used for user-agent stylesheets. &gt; pub shared_lock: SharedRwLock, &gt; /// The user or user agent stylesheets. &gt; pub user_or_user_agent_stylesheets: Vec&lt;DocumentStyleSheet&gt;, &gt; /// The quirks mode stylesheet. &gt;@@ -108,30 +110,31 @@ impl StylesheetContents { &gt; pub fn rules&lt;'a, 'b: 'a&gt;(&amp;'a self, guard: &amp;'b SharedRwLockReadGuard) -&gt; &amp;'a [CssRule] { &gt; &amp;self.rules.read_with(guard).0 &gt; } &gt; &gt; /// Measure heap usage. &gt; #[cfg(feature = "gecko")] &gt; pub fn size_of(&amp;self, guard: &amp;SharedRwLockReadGuard, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; // Measurement of other fields may be added later. &gt;- self.rules.unconditional_shallow_size_of(ops) + &gt;- self.rules.read_with(guard).size_of(guard, ops) &gt;+ self.rules.unconditional_shallow_size_of(ops) &gt;+ + self.rules.read_with(guard).size_of(guard, ops) &gt; } &gt; } &gt; &gt; impl DeepCloneWithLock for StylesheetContents { &gt; fn deep_clone_with_lock( &gt; &amp;self, &gt; lock: &amp;SharedRwLock, &gt; guard: &amp;SharedRwLockReadGuard, &gt; params: &amp;DeepCloneParams, &gt; ) -&gt; Self { &gt; // Make a deep clone of the rules, using the new lock. &gt;- let rules = self.rules &gt;+ let rules = self &gt;+ .rules &gt; .read_with(guard) &gt; .deep_clone_with_lock(lock, guard, params); &gt; &gt; Self { &gt; rules: Arc::new(lock.wrap(rules)), &gt; quirks_mode: self.quirks_mode, &gt; origin: self.origin, &gt; url_data: RwLock::new((*self.url_data.read()).clone()), &gt;@@ -171,17 +174,17 @@ macro_rules! rule_filter { &gt; } &gt; } &gt; } &gt; )+ &gt; } &gt; } &gt; &gt; /// A trait to represent a given stylesheet in a document. &gt;-pub trait StylesheetInDocument : ::std::fmt::Debug { &gt;+pub trait StylesheetInDocument: ::std::fmt::Debug { &gt; /// Get the stylesheet origin. &gt; fn origin(&amp;self, guard: &amp;SharedRwLockReadGuard) -&gt; Origin; &gt; &gt; /// Get the stylesheet quirks mode. &gt; fn quirks_mode(&amp;self, guard: &amp;SharedRwLockReadGuard) -&gt; QuirksMode; &gt; &gt; /// Get whether this stylesheet is enabled. &gt; fn enabled(&amp;self) -&gt; bool; &gt;@@ -382,25 +385,22 @@ impl Stylesheet { &gt; match result { &gt; Ok(rule) =&gt; { &gt; // Use a fallible push here, and if it fails, just &gt; // fall out of the loop. This will cause the page to &gt; // be shown incorrectly, but it's better than OOMing. &gt; if rules.try_push(rule).is_err() { &gt; break; &gt; } &gt;- }, &gt;+ } &gt; Err((error, slice)) =&gt; { &gt; let location = error.location; &gt; let error = ContextualParseError::InvalidRule(slice, error); &gt;- iter.parser.context.log_css_error( &gt;- location, &gt;- error, &gt;- ); &gt;- }, &gt;+ iter.parser.context.log_css_error(location, error); &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; let source_map_url = input.current_source_map_url().map(String::from); &gt; let source_url = input.current_source_url().map(String::from); &gt; (rules, source_map_url, source_url) &gt; } &gt;@@ -463,17 +463,18 @@ impl Clone for Stylesheet { &gt; fn clone(&amp;self) -&gt; Self { &gt; // Create a new lock for our clone. &gt; let lock = self.shared_lock.clone(); &gt; let guard = self.shared_lock.read(); &gt; &gt; // Make a deep clone of the media, using the new lock. &gt; let media = self.media.read_with(&amp;guard).clone(); &gt; let media = Arc::new(lock.wrap(media)); &gt;- let contents = self.contents &gt;+ let contents = self &gt;+ .contents &gt; .deep_clone_with_lock(&amp;lock, &amp;guard, &amp;DeepCloneParams); &gt; &gt; Stylesheet { &gt; contents, &gt; media: media, &gt; shared_lock: lock, &gt; disabled: AtomicBool::new(self.disabled.load(Ordering::SeqCst)), &gt; } &gt;diff --git a/servo/components/style/stylesheets/supports_rule.rs b/servo/components/style/stylesheets/supports_rule.rs &gt;index f8c3235f2952..1223a55adc0f 100644 &gt;--- a/servo/components/style/stylesheets/supports_rule.rs &gt;+++ b/servo/components/style/stylesheets/supports_rule.rs &gt;@@ -1,17 +1,17 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! [@supports rules](https://drafts.csswg.org/css-conditional-3/#at-supports) &gt; &gt;+use cssparser::parse_important; &gt; use cssparser::{Delimiter, Parser, SourceLocation, Token}; &gt; use cssparser::{ParseError as CssParseError, ParserInput}; &gt;-use cssparser::parse_important; &gt; #[cfg(feature = "gecko")] &gt; use malloc_size_of::{MallocSizeOfOps, MallocUnconditionalShallowSizeOf}; &gt; use parser::ParserContext; &gt; use properties::{PropertyDeclaration, PropertyId, SourcePropertyDeclaration}; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use servo_arc::Arc; &gt; use shared_lock::{DeepCloneParams, DeepCloneWithLock, Locked}; &gt; use shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; &gt;@@ -37,18 +37,18 @@ pub struct SupportsRule { &gt; pub source_location: SourceLocation, &gt; } &gt; &gt; impl SupportsRule { &gt; /// Measure heap usage. &gt; #[cfg(feature = "gecko")] &gt; pub fn size_of(&amp;self, guard: &amp;SharedRwLockReadGuard, ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; // Measurement of other fields may be added later. &gt;- self.rules.unconditional_shallow_size_of(ops) + &gt;- self.rules.read_with(guard).size_of(guard, ops) &gt;+ self.rules.unconditional_shallow_size_of(ops) &gt;+ + self.rules.read_with(guard).size_of(guard, ops) &gt; } &gt; } &gt; &gt; impl ToCssWithGuard for SupportsRule { &gt; fn to_css(&amp;self, guard: &amp;SharedRwLockReadGuard, dest: &amp;mut CssStringWriter) -&gt; fmt::Result { &gt; dest.write_str("@supports ")?; &gt; self.condition.to_css(&amp;mut CssWriter::new(dest))?; &gt; self.rules.read_with(guard).to_css_block(guard, dest) &gt;@@ -107,24 +107,24 @@ impl SupportsCondition { &gt; &gt; let in_parens = SupportsCondition::parse_in_parens(input)?; &gt; &gt; let location = input.current_source_location(); &gt; let (keyword, wrapper) = match input.next() { &gt; Err(_) =&gt; { &gt; // End of input &gt; return Ok(in_parens); &gt;- }, &gt;+ } &gt; Ok(&amp;Token::Ident(ref ident)) =&gt; { &gt; match_ignore_ascii_case! { &amp;ident, &gt; "and" =&gt; ("and", SupportsCondition::And as fn(_) -&gt; _), &gt; "or" =&gt; ("or", SupportsCondition::Or as fn(_) -&gt; _), &gt; _ =&gt; return Err(location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))) &gt; } &gt;- }, &gt;+ } &gt; Ok(t) =&gt; return Err(location.new_unexpected_token_error(t.clone())), &gt; }; &gt; &gt; let mut conditions = Vec::with_capacity(2); &gt; conditions.push(in_parens); &gt; loop { &gt; conditions.push(SupportsCondition::parse_in_parens(input)?); &gt; if input &gt;@@ -151,36 +151,34 @@ impl SupportsCondition { &gt; // FIXME: remove clone() when lifetimes are non-lexical &gt; match input.next()?.clone() { &gt; Token::ParenthesisBlock =&gt; { &gt; let nested = input &gt; .try(|input| input.parse_nested_block(|i| parse_condition_or_declaration(i))); &gt; if nested.is_ok() { &gt; return nested; &gt; } &gt;- }, &gt;+ } &gt; Token::Function(ident) =&gt; { &gt; // Although this is an internal syntax, it is not necessary to check &gt; // parsing context as far as we accept any unexpected token as future &gt; // syntax, and evaluate it to false when not in chrome / ua sheet. &gt; // See https://drafts.csswg.org/css-conditional-3/#general_enclosed &gt; if ident.eq_ignore_ascii_case("-moz-bool-pref") { &gt; if let Ok(name) = input.try(|i| { &gt; i.parse_nested_block(|i| { &gt; i.expect_string() &gt; .map(|s| s.to_string()) &gt; .map_err(CssParseError::&lt;()&gt;::from) &gt;- }).and_then(|s| { &gt;- CString::new(s).map_err(|_| location.new_custom_error(())) &gt;- }) &gt;+ }).and_then(|s| CString::new(s).map_err(|_| location.new_custom_error(()))) &gt; }) { &gt; return Ok(SupportsCondition::MozBoolPref(name)); &gt; } &gt; } &gt;- }, &gt;+ } &gt; t =&gt; return Err(location.new_unexpected_token_error(t)), &gt; } &gt; input.parse_nested_block(|i| consume_any_value(i))?; &gt; Ok(SupportsCondition::FutureSyntax( &gt; input.slice_from(pos).to_owned(), &gt; )) &gt; } &gt; &gt;@@ -229,56 +227,56 @@ impl ToCss for SupportsCondition { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; match *self { &gt; SupportsCondition::Not(ref cond) =&gt; { &gt; dest.write_str("not ")?; &gt; cond.to_css(dest) &gt;- }, &gt;+ } &gt; SupportsCondition::Parenthesized(ref cond) =&gt; { &gt; dest.write_str("(")?; &gt; cond.to_css(dest)?; &gt; dest.write_str(")") &gt;- }, &gt;+ } &gt; SupportsCondition::And(ref vec) =&gt; { &gt; let mut first = true; &gt; for cond in vec { &gt; if !first { &gt; dest.write_str(" and ")?; &gt; } &gt; first = false; &gt; cond.to_css(dest)?; &gt; } &gt; Ok(()) &gt;- }, &gt;+ } &gt; SupportsCondition::Or(ref vec) =&gt; { &gt; let mut first = true; &gt; for cond in vec { &gt; if !first { &gt; dest.write_str(" or ")?; &gt; } &gt; first = false; &gt; cond.to_css(dest)?; &gt; } &gt; Ok(()) &gt;- }, &gt;+ } &gt; SupportsCondition::Declaration(ref decl) =&gt; { &gt; dest.write_str("(")?; &gt; decl.to_css(dest)?; &gt; dest.write_str(")") &gt;- }, &gt;+ } &gt; SupportsCondition::MozBoolPref(ref name) =&gt; { &gt; dest.write_str("-moz-bool-pref(")?; &gt; let name = &gt; str::from_utf8(name.as_bytes()).expect("Should be parsed from valid UTF-8"); &gt; name.to_css(dest)?; &gt; dest.write_str(")") &gt;- }, &gt;+ } &gt; SupportsCondition::FutureSyntax(ref s) =&gt; dest.write_str(&amp;s), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Clone, Debug)] &gt; /// A possibly-invalid property declaration &gt; pub struct Declaration(pub String); &gt;@@ -310,29 +308,26 @@ impl Declaration { &gt; /// Determine if a declaration parses &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-conditional-3/#support-definition&gt; &gt; pub fn eval(&amp;self, context: &amp;ParserContext) -&gt; bool { &gt; debug_assert_eq!(context.rule_type(), CssRuleType::Style); &gt; &gt; let mut input = ParserInput::new(&amp;self.0); &gt; let mut input = Parser::new(&amp;mut input); &gt;- input.parse_entirely(|input| -&gt; Result&lt;(), CssParseError&lt;()&gt;&gt; { &gt;- let prop = input.expect_ident_cloned().unwrap(); &gt;- input.expect_colon().unwrap(); &gt;+ input &gt;+ .parse_entirely(|input| -&gt; Result&lt;(), CssParseError&lt;()&gt;&gt; { &gt;+ let prop = input.expect_ident_cloned().unwrap(); &gt;+ input.expect_colon().unwrap(); &gt; &gt;- let id = PropertyId::parse(&amp;prop, context) &gt;- .map_err(|_| input.new_custom_error(()))?; &gt;+ let id = &gt;+ PropertyId::parse(&amp;prop, context).map_err(|_| input.new_custom_error(()))?; &gt; &gt;- let mut declarations = SourcePropertyDeclaration::new(); &gt;- input.parse_until_before(Delimiter::Bang, |input| { &gt;- PropertyDeclaration::parse_into( &gt;- &amp;mut declarations, &gt;- id, &gt;- &amp;context, &gt;- input, &gt;- ).map_err(|_| input.new_custom_error(())) &gt;- })?; &gt;- let _ = input.try(parse_important); &gt;- Ok(()) &gt;- }).is_ok() &gt;+ let mut declarations = SourcePropertyDeclaration::new(); &gt;+ input.parse_until_before(Delimiter::Bang, |input| { &gt;+ PropertyDeclaration::parse_into(&amp;mut declarations, id, &amp;context, input) &gt;+ .map_err(|_| input.new_custom_error(())) &gt;+ })?; &gt;+ let _ = input.try(parse_important); &gt;+ Ok(()) &gt;+ }).is_ok() &gt; } &gt; } &gt;diff --git a/servo/components/style/stylesheets/viewport_rule.rs b/servo/components/style/stylesheets/viewport_rule.rs &gt;index 1fc6a988c7ca..30848743ba67 100644 &gt;--- a/servo/components/style/stylesheets/viewport_rule.rs &gt;+++ b/servo/components/style/stylesheets/viewport_rule.rs &gt;@@ -4,35 +4,35 @@ &gt; &gt; //! The [`@viewport`][at] at-rule and [`meta`][meta] element. &gt; //! &gt; //! [at]: https://drafts.csswg.org/css-device-adapt/#atviewport-rule &gt; //! [meta]: https://drafts.csswg.org/css-device-adapt/#viewport-meta &gt; &gt; use app_units::Au; &gt; use context::QuirksMode; &gt;-use cssparser::{parse_important, AtRuleParser, DeclarationListParser, DeclarationParser, Parser}; &gt; use cssparser::CowRcStr; &gt;+use cssparser::{parse_important, AtRuleParser, DeclarationListParser, DeclarationParser, Parser}; &gt; use error_reporting::ContextualParseError; &gt; use euclid::TypedSize2D; &gt; use font_metrics::get_metrics_provider_for_product; &gt; use media_queries::Device; &gt; use parser::ParserContext; &gt; use properties::StyleBuilder; &gt; use rule_cache::RuleCacheConditions; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use shared_lock::{SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard}; &gt; use std::borrow::Cow; &gt; use std::cell::RefCell; &gt; use std::fmt::{self, Write}; &gt; use std::iter::Enumerate; &gt; use std::str::Chars; &gt; use str::CssStringWriter; &gt;-use style_traits::{CssWriter, ParseError, PinchZoomFactor, StyleParseErrorKind, ToCss}; &gt; use style_traits::viewport::{Orientation, UserZoom, ViewportConstraints, Zoom}; &gt;+use style_traits::{CssWriter, ParseError, PinchZoomFactor, StyleParseErrorKind, ToCss}; &gt; use stylesheets::{Origin, StylesheetInDocument}; &gt; use values::computed::{Context, ToComputedValue}; &gt; use values::specified::{LengthOrPercentageOrAuto, NoCalcLength, ViewportPercentageLength}; &gt; &gt; /// Whether parsing and processing of `@viewport` rules is enabled. &gt; #[cfg(feature = "servo")] &gt; pub fn enabled() -&gt; bool { &gt; use servo_config::prefs::PREFS; &gt;@@ -366,25 +366,24 @@ impl ViewportRule { &gt; let mut cascade = Cascade::new(); &gt; let mut parser = DeclarationListParser::new(input, parser); &gt; while let Some(result) = parser.next() { &gt; match result { &gt; Ok(declarations) =&gt; { &gt; for declarations in declarations { &gt; cascade.add(Cow::Owned(declarations)) &gt; } &gt;- }, &gt;+ } &gt; Err((error, slice)) =&gt; { &gt; let location = error.location; &gt; let error = ContextualParseError::UnsupportedViewportDescriptorDeclaration( &gt;- slice, &gt;- error, &gt;+ slice, error, &gt; ); &gt; context.log_css_error(location, error); &gt;- }, &gt;+ } &gt; } &gt; } &gt; Ok(ViewportRule { &gt; declarations: cascade.finish(), &gt; }) &gt; } &gt; } &gt; &gt;@@ -433,36 +432,36 @@ impl ViewportRule { &gt; &gt; match name { &gt; n if n.eq_ignore_ascii_case("width") =&gt; { &gt; if let Some(value) = ViewportLength::from_meta(value) { &gt; push_descriptor!(MinWidth(ViewportLength::ExtendToZoom)); &gt; push_descriptor!(MaxWidth(value)); &gt; has_width = true; &gt; } &gt;- }, &gt;+ } &gt; n if n.eq_ignore_ascii_case("height") =&gt; { &gt; if let Some(value) = ViewportLength::from_meta(value) { &gt; push_descriptor!(MinHeight(ViewportLength::ExtendToZoom)); &gt; push_descriptor!(MaxHeight(value)); &gt; has_height = true; &gt; } &gt;- }, &gt;+ } &gt; n if n.eq_ignore_ascii_case("initial-scale") =&gt; { &gt; if let Some(value) = Zoom::from_meta(value) { &gt; push_descriptor!(Zoom(value)); &gt; has_zoom = true; &gt; } &gt;- }, &gt;+ } &gt; n if n.eq_ignore_ascii_case("minimum-scale") =&gt; push!(MinZoom(Zoom::from_meta)), &gt; n if n.eq_ignore_ascii_case("maximum-scale") =&gt; push!(MaxZoom(Zoom::from_meta)), &gt; n if n.eq_ignore_ascii_case("user-scalable") =&gt; { &gt; push!(UserZoom(UserZoom::from_meta)) &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; } &gt; } &gt; &gt; // DEVICE-ADAPT § 9.4 - The 'width' and 'height' properties &gt; // http://dev.w3.org/csswg/css-device-adapt/#width-and-height-properties &gt; if !has_width &amp;&amp; has_zoom { &gt; if has_height { &gt;@@ -605,20 +604,20 @@ impl Cascade { &gt; let descriptor = declaration.descriptor.discriminant_value(); &gt; &gt; match self.declarations[descriptor] { &gt; Some((ref mut order_of_appearance, ref mut entry_declaration)) =&gt; { &gt; if declaration.higher_or_equal_precendence(entry_declaration) { &gt; *entry_declaration = declaration.into_owned(); &gt; *order_of_appearance = self.count_so_far; &gt; } &gt;- }, &gt;+ } &gt; ref mut entry @ None =&gt; { &gt; *entry = Some((self.count_so_far, declaration.into_owned())); &gt;- }, &gt;+ } &gt; } &gt; self.count_so_far += 1; &gt; } &gt; &gt; pub fn finish(mut self) -&gt; Vec&lt;ViewportDescriptorDeclaration&gt; { &gt; // sort the descriptors by order of appearance &gt; self.declarations &gt; .sort_by_key(|entry| entry.as_ref().map(|&amp;(index, _)| index)); &gt;@@ -750,34 +749,34 @@ impl MaybeNew for ViewportConstraints { &gt; &gt; macro_rules! to_pixel_length { &gt; ($value:ident, $dimension:ident, $extend_to:ident =&gt; $auto_extend_to:expr) =&gt; { &gt; if let Some($value) = $value { &gt; match *$value { &gt; ViewportLength::Specified(ref length) =&gt; match *length { &gt; LengthOrPercentageOrAuto::Length(ref value) =&gt; { &gt; Some(Au::from(value.to_computed_value(&amp;context))) &gt;- }, &gt;+ } &gt; LengthOrPercentageOrAuto::Percentage(value) =&gt; { &gt; Some(initial_viewport.$dimension.scale_by(value.0)) &gt;- }, &gt;+ } &gt; LengthOrPercentageOrAuto::Auto =&gt; None, &gt;- LengthOrPercentageOrAuto::Calc(ref calc) =&gt; calc.to_computed_value( &gt;- &amp;context, &gt;- ).to_used_value(Some(initial_viewport.$dimension)), &gt;+ LengthOrPercentageOrAuto::Calc(ref calc) =&gt; calc &gt;+ .to_computed_value(&amp;context) &gt;+ .to_used_value(Some(initial_viewport.$dimension)), &gt; }, &gt; ViewportLength::ExtendToZoom =&gt; { &gt; // $extend_to will be 'None' if 'extend-to-zoom' is 'auto' &gt; match ($extend_to, $auto_extend_to) { &gt; (None, None) =&gt; None, &gt; (a, None) =&gt; a, &gt; (None, b) =&gt; b, &gt; (a, b) =&gt; cmp::max(a, b), &gt; } &gt;- }, &gt;+ } &gt; } &gt; } else { &gt; None &gt; } &gt; }; &gt; } &gt; &gt; // DEVICE-ADAPT § 9.3 states that max-descriptors need to be resolved &gt;@@ -818,26 +817,26 @@ impl MaybeNew for ViewportConstraints { &gt; width &gt; }; &gt; &gt; let width = width.unwrap_or_else(|| match initial_viewport.height { &gt; Au(0) =&gt; initial_viewport.width, &gt; initial_height =&gt; { &gt; let ratio = initial_viewport.width.to_f32_px() / initial_height.to_f32_px(); &gt; Au::from_f32_px(height.unwrap().to_f32_px() * ratio) &gt;- }, &gt;+ } &gt; }); &gt; &gt; // DEVICE-ADAPT § 6.2.6 Resolve height value &gt; let height = height.unwrap_or_else(|| match initial_viewport.width { &gt; Au(0) =&gt; initial_viewport.height, &gt; initial_width =&gt; { &gt; let ratio = initial_viewport.height.to_f32_px() / initial_width.to_f32_px(); &gt; Au::from_f32_px(width.to_f32_px() * ratio) &gt;- }, &gt;+ } &gt; }); &gt; &gt; Some(ViewportConstraints { &gt; size: TypedSize2D::new(width.to_f32_px(), height.to_f32_px()), &gt; &gt; // TODO: compute a zoom factor for 'auto' as suggested by DEVICE-ADAPT § 10. &gt; initial_zoom: PinchZoomFactor::new(initial_zoom.unwrap_or(1.)), &gt; min_zoom: min_zoom.map(PinchZoomFactor::new), &gt;diff --git a/servo/components/style/stylist.rs b/servo/components/style/stylist.rs &gt;index dbddca725e12..7f8690500e67 100644 &gt;--- a/servo/components/style/stylist.rs &gt;+++ b/servo/components/style/stylist.rs &gt;@@ -1,61 +1,61 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Selector matching. &gt; &gt;-use {Atom, LocalName, Namespace, WeakAtom}; &gt; use applicable_declarations::{ApplicableDeclarationBlock, ApplicableDeclarationList}; &gt; use context::{CascadeInputs, QuirksMode}; &gt; use dom::{TElement, TShadowRoot}; &gt; use element_state::{DocumentState, ElementState}; &gt; use font_metrics::FontMetricsProvider; &gt; #[cfg(feature = "gecko")] &gt; use gecko_bindings::structs::{ServoStyleSetSizes, StyleRuleInclusion}; &gt; use hashglobe::FailedAllocationError; &gt; use invalidation::element::invalidation_map::InvalidationMap; &gt; use invalidation::media_queries::{EffectiveMediaQueryResults, ToMediaListKey}; &gt; #[cfg(feature = "gecko")] &gt;-use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; &gt;-#[cfg(feature = "gecko")] &gt; use malloc_size_of::MallocUnconditionalShallowSizeOf; &gt;+#[cfg(feature = "gecko")] &gt;+use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps}; &gt; use media_queries::Device; &gt; use properties::{self, CascadeMode, ComputedValues}; &gt; use properties::{AnimationRules, PropertyDeclarationBlock}; &gt; use rule_cache::{RuleCache, RuleCacheConditions}; &gt; use rule_tree::{CascadeLevel, RuleTree, ShadowCascadeOrder, StrongRuleNode, StyleSource}; &gt; use selector_map::{PrecomputedHashMap, SelectorMap, SelectorMapEntry}; &gt; use selector_parser::{PerPseudoElementMap, PseudoElement, SelectorImpl, SnapshotMap}; &gt;-use selectors::NthIndexCache; &gt; use selectors::attr::{CaseSensitivity, NamespaceConstraint}; &gt; use selectors::bloom::{BloomFilter, NonCountingBloomFilter}; &gt;-use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext, MatchingMode}; &gt; use selectors::matching::VisitedHandlingMode; &gt;+use selectors::matching::{matches_selector, ElementSelectorFlags, MatchingContext, MatchingMode}; &gt; use selectors::parser::{AncestorHashes, Combinator, Component, Selector}; &gt; use selectors::parser::{SelectorIter, Visit}; &gt; use selectors::visitor::SelectorVisitor; &gt;+use selectors::NthIndexCache; &gt; use servo_arc::{Arc, ArcBorrow}; &gt; use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; &gt; use smallbitvec::SmallBitVec; &gt; use smallvec::SmallVec; &gt; use std::ops; &gt; use std::sync::Mutex; &gt; use style_traits::viewport::ViewportConstraints; &gt; use stylesheet_set::{DataValidity, DocumentStylesheetSet, SheetRebuildKind}; &gt; use stylesheet_set::{DocumentStylesheetFlusher, SheetCollectionFlusher}; &gt;-#[cfg(feature = "gecko")] &gt;-use stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule, PageRule}; &gt;-use stylesheets::{CssRule, Origin, OriginSet, PerOrigin, PerOriginIter}; &gt;-use stylesheets::StyleRule; &gt;-use stylesheets::StylesheetInDocument; &gt; use stylesheets::keyframes_rule::KeyframesAnimation; &gt; use stylesheets::viewport_rule::{self, MaybeNew, ViewportRule}; &gt;+use stylesheets::StyleRule; &gt;+use stylesheets::StylesheetInDocument; &gt;+#[cfg(feature = "gecko")] &gt;+use stylesheets::{CounterStyleRule, FontFaceRule, FontFeatureValuesRule, PageRule}; &gt;+use stylesheets::{CssRule, Origin, OriginSet, PerOrigin, PerOriginIter}; &gt; use thread_state::{self, ThreadState}; &gt;+use {Atom, LocalName, Namespace, WeakAtom}; &gt; &gt; /// The type of the stylesheets that the stylist contains. &gt; #[cfg(feature = "servo")] &gt; pub type StylistSheet = ::stylesheets::DocumentStyleSheet; &gt; &gt; /// The type of the stylesheets that the stylist contains. &gt; #[cfg(feature = "gecko")] &gt; pub type StylistSheet = ::gecko::data::GeckoStyleSheet; &gt;@@ -179,18 +179,20 @@ impl UserAgentCascadeData { &gt; sizes.mPrecomputedPseudos += self.precomputed_pseudo_element_decls.size_of(ops); &gt; } &gt; } &gt; &gt; /// All the computed information for a stylesheet. &gt; #[derive(Default)] &gt; #[cfg_attr(feature = "servo", derive(MallocSizeOf))] &gt; struct DocumentCascadeData { &gt;- #[cfg_attr(feature = "servo", &gt;- ignore_malloc_size_of = "Arc, owned by UserAgentCascadeDataCache")] &gt;+ #[cfg_attr( &gt;+ feature = "servo", &gt;+ ignore_malloc_size_of = "Arc, owned by UserAgentCascadeDataCache" &gt;+ )] &gt; user_agent: Arc&lt;UserAgentCascadeData&gt;, &gt; user: CascadeData, &gt; author: CascadeData, &gt; per_origin: PerOrigin&lt;()&gt;, &gt; } &gt; &gt; /// An iterator over the cascade data of a given document. &gt; pub struct DocumentCascadeDataIter&lt;'a&gt; { &gt;@@ -345,17 +347,20 @@ pub struct Stylist { &gt; &gt; /// Viewport constraints based on the current device. &gt; viewport_constraints: Option&lt;ViewportConstraints&gt;, &gt; &gt; /// The list of stylesheets. &gt; stylesheets: StylistStylesheetSet, &gt; &gt; /// If true, the quirks-mode stylesheet is applied. &gt;- #[cfg_attr(feature = "servo", ignore_malloc_size_of = "defined in selectors")] &gt;+ #[cfg_attr( &gt;+ feature = "servo", &gt;+ ignore_malloc_size_of = "defined in selectors" &gt;+ )] &gt; quirks_mode: QuirksMode, &gt; &gt; /// Selector maps for all of the style sheets in the stylist, after &gt; /// evalutaing media rules against the current device, split out per &gt; /// cascade level. &gt; cascade_data: DocumentCascadeData, &gt; &gt; /// Whether author styles are enabled. &gt;@@ -676,27 +681,28 @@ impl Stylist { &gt; /// argument. This is useful for providing extra @page rules. &gt; pub fn rule_node_for_precomputed_pseudo( &gt; &amp;self, &gt; guards: &amp;StylesheetGuards, &gt; pseudo: &amp;PseudoElement, &gt; extra_declarations: Option&lt;Vec&lt;ApplicableDeclarationBlock&gt;&gt;, &gt; ) -&gt; StrongRuleNode { &gt; let mut decl; &gt;- let declarations = match self.cascade_data &gt;+ let declarations = match self &gt;+ .cascade_data &gt; .user_agent &gt; .precomputed_pseudo_element_decls &gt; .get(pseudo) &gt; { &gt; Some(declarations) =&gt; match extra_declarations { &gt; Some(mut extra_decls) =&gt; { &gt; decl = declarations.clone(); &gt; decl.append(&amp;mut extra_decls); &gt; Some(&amp;decl) &gt;- }, &gt;+ } &gt; None =&gt; Some(declarations), &gt; }, &gt; None =&gt; extra_declarations.as_ref(), &gt; }; &gt; &gt; match declarations { &gt; Some(decls) =&gt; self.rule_tree.insert_ordered_rules_with_important( &gt; decls.into_iter().map(|a| a.clone().for_rule_tree()), &gt;@@ -1131,17 +1137,18 @@ impl Stylist { &gt; &gt; let rule_hash_target = element.rule_hash_target(); &gt; &gt; let matches_user_rules = rule_hash_target.matches_user_and_author_rules(); &gt; let matches_author_rules = &gt; matches_user_rules &amp;&amp; self.author_styles_enabled == AuthorStylesEnabled::Yes; &gt; &gt; // Normal user-agent rules. &gt;- if let Some(map) = self.cascade_data &gt;+ if let Some(map) = self &gt;+ .cascade_data &gt; .user_agent &gt; .cascade_data &gt; .normal_rules(pseudo_element) &gt; { &gt; map.get_all_matching_rules( &gt; element, &gt; rule_hash_target, &gt; applicable_declarations, &gt;@@ -1282,18 +1289,17 @@ impl Stylist { &gt; // See: https://github.com/w3c/svgwg/issues/504 &gt; // &gt; // Note that we always resolve URLs against the document, so we &gt; // can't get into a nested shadow situation here. &gt; // &gt; // See: https://github.com/w3c/svgwg/issues/505 &gt; // &gt; let host_is_svg_use = &gt;- host.is_svg_element() &amp;&amp; &gt;- host.local_name() == &amp;*local_name!("use"); &gt;+ host.is_svg_element() &amp;&amp; host.local_name() == &amp;*local_name!("use"); &gt; &gt; match_document_author_rules = host_is_svg_use; &gt; } &gt; } &gt; &gt; // FIXME(emilio): This doesn't account for the author_styles_enabled &gt; // stuff... &gt; let cut_xbl_binding_inheritance = &gt;@@ -1387,39 +1393,35 @@ impl Stylist { &gt; pub fn may_have_rules_for_id&lt;E&gt;(&amp;self, id: &amp;WeakAtom, element: E) -&gt; bool &gt; where &gt; E: TElement, &gt; { &gt; // If id needs to be compared case-insensitively, the logic below &gt; // wouldn't work. Just conservatively assume it may have such rules. &gt; match self.quirks_mode().classes_and_ids_case_sensitivity() { &gt; CaseSensitivity::AsciiCaseInsensitive =&gt; return true, &gt;- CaseSensitivity::CaseSensitive =&gt; {}, &gt;+ CaseSensitivity::CaseSensitive =&gt; {} &gt; } &gt; &gt; let hash = id.get_hash(); &gt; self.any_applicable_rule_data(element, |data| data.mapped_ids.might_contain_hash(hash)) &gt; } &gt; &gt; /// Returns the registered `@keyframes` animation for the specified name. &gt; #[inline] &gt;- pub fn get_animation&lt;'a, E&gt;( &gt;- &amp;'a self, &gt;- name: &amp;Atom, &gt;- element: E, &gt;- ) -&gt; Option&lt;&amp;'a KeyframesAnimation&gt; &gt;+ pub fn get_animation&lt;'a, E&gt;(&amp;'a self, name: &amp;Atom, element: E) -&gt; Option&lt;&amp;'a KeyframesAnimation&gt; &gt; where &gt; E: TElement + 'a, &gt; { &gt; macro_rules! try_find_in { &gt; ($data:expr) =&gt; { &gt; if let Some(animation) = $data.animations.get(name) { &gt; return Some(animation); &gt; } &gt;- } &gt;+ }; &gt; } &gt; &gt; // NOTE(emilio): We implement basically what Blink does for this case, &gt; // which is [1] as of this writing. &gt; // &gt; // See [2] for the spec discussion about what to do about this. WebKit's &gt; // behavior makes a bit more sense off-hand, but it's way more complex &gt; // to implement, and it makes value computation having to thread around &gt;@@ -1533,37 +1535,41 @@ impl Stylist { &gt; ) -&gt; Arc&lt;ComputedValues&gt; &gt; where &gt; E: TElement, &gt; { &gt; use font_metrics::get_metrics_provider_for_product; &gt; &gt; let block = declarations.read_with(guards.author); &gt; let iter_declarations = || { &gt;- block.declaration_importance_iter().map(|(declaration, importance)| { &gt;- debug_assert!(!importance.important()); &gt;- (declaration, CascadeLevel::StyleAttributeNormal) &gt;- }) &gt;+ block &gt;+ .declaration_importance_iter() &gt;+ .map(|(declaration, importance)| { &gt;+ debug_assert!(!importance.important()); &gt;+ (declaration, CascadeLevel::StyleAttributeNormal) &gt;+ }) &gt; }; &gt; &gt; let metrics = get_metrics_provider_for_product(); &gt; &gt; // We don't bother inserting these declarations in the rule tree, since &gt; // it'd be quite useless and slow. &gt; properties::apply_declarations::&lt;E, _, _&gt;( &gt; &amp;self.device, &gt; /* pseudo = */ None, &gt; self.rule_tree.root(), &gt; guards, &gt; iter_declarations, &gt; Some(parent_style), &gt; Some(parent_style), &gt; Some(parent_style), &gt; &amp;metrics, &gt;- CascadeMode::Unvisited { visited_rules: None }, &gt;+ CascadeMode::Unvisited { &gt;+ visited_rules: None, &gt;+ }, &gt; self.quirks_mode, &gt; /* rule_cache = */ None, &gt; &amp;mut Default::default(), &gt; /* element = */ None, &gt; ) &gt; } &gt; &gt; /// Accessor for a shared reference to the device. &gt;@@ -1689,18 +1695,20 @@ impl MallocSizeOf for ExtraStyleData { &gt; n &gt; } &gt; } &gt; &gt; /// SelectorMapEntry implementation for use in our revalidation selector map. &gt; #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] &gt; #[derive(Clone, Debug)] &gt; struct RevalidationSelectorAndHashes { &gt;- #[cfg_attr(feature = "gecko", &gt;- ignore_malloc_size_of = "CssRules have primary refs, we measure there")] &gt;+ #[cfg_attr( &gt;+ feature = "gecko", &gt;+ ignore_malloc_size_of = "CssRules have primary refs, we measure there" &gt;+ )] &gt; selector: Selector&lt;SelectorImpl&gt;, &gt; selector_offset: usize, &gt; hashes: AncestorHashes, &gt; } &gt; &gt; impl RevalidationSelectorAndHashes { &gt; fn new(selector: Selector&lt;SelectorImpl&gt;, hashes: AncestorHashes) -&gt; Self { &gt; let selector_offset = { &gt;@@ -1766,31 +1774,31 @@ fn component_needs_revalidation( &gt; match *c { &gt; Component::ID(_) =&gt; { &gt; // TODO(emilio): This could also check that the ID is not already in &gt; // the rule hash. In that case, we could avoid making this a &gt; // revalidation selector too. &gt; // &gt; // See https://bugzilla.mozilla.org/show_bug.cgi?id=1369611 &gt; passed_rightmost_selector &gt;- }, &gt;- Component::AttributeInNoNamespaceExists { .. } | &gt;- Component::AttributeInNoNamespace { .. } | &gt;- Component::AttributeOther(_) | &gt;- Component::Empty | &gt;- Component::FirstChild | &gt;- Component::LastChild | &gt;- Component::OnlyChild | &gt;- Component::NthChild(..) | &gt;- Component::NthLastChild(..) | &gt;- Component::NthOfType(..) | &gt;- Component::NthLastOfType(..) | &gt;- Component::FirstOfType | &gt;- Component::LastOfType | &gt;- Component::OnlyOfType =&gt; true, &gt;+ } &gt;+ Component::AttributeInNoNamespaceExists { .. } &gt;+ | Component::AttributeInNoNamespace { .. } &gt;+ | Component::AttributeOther(_) &gt;+ | Component::Empty &gt;+ | Component::FirstChild &gt;+ | Component::LastChild &gt;+ | Component::OnlyChild &gt;+ | Component::NthChild(..) &gt;+ | Component::NthLastChild(..) &gt;+ | Component::NthOfType(..) &gt;+ | Component::NthLastOfType(..) &gt;+ | Component::FirstOfType &gt;+ | Component::LastOfType &gt;+ | Component::OnlyOfType =&gt; true, &gt; Component::NonTSPseudoClass(ref p) =&gt; p.needs_cache_revalidation(), &gt; _ =&gt; false, &gt; } &gt; } &gt; &gt; impl&lt;'a&gt; SelectorVisitor for StylistSelectorVisitor&lt;'a&gt; { &gt; type Impl = SelectorImpl; &gt; &gt;@@ -1800,18 +1808,19 @@ impl&lt;'a&gt; SelectorVisitor for StylistSelectorVisitor&lt;'a&gt; { &gt; &gt; // NOTE(emilio): This works properly right now because we can't store &gt; // complex selectors in nested selectors, otherwise we may need to &gt; // rethink this. &gt; // &gt; // Also, note that this call happens before we visit any of the simple &gt; // selectors in the next ComplexSelector, so we can use this to skip &gt; // looking at them. &gt;- self.passed_rightmost_selector = self.passed_rightmost_selector || &gt;- !matches!(combinator, None | Some(Combinator::PseudoElement)); &gt;+ self.passed_rightmost_selector = &gt;+ self.passed_rightmost_selector &gt;+ || !matches!(combinator, None | Some(Combinator::PseudoElement)); &gt; &gt; true &gt; } &gt; &gt; fn visit_attribute_selector( &gt; &amp;mut self, &gt; _ns: &amp;NamespaceConstraint&lt;&amp;Namespace&gt;, &gt; name: &amp;LocalName, &gt;@@ -1823,40 +1832,41 @@ impl&lt;'a&gt; SelectorVisitor for StylistSelectorVisitor&lt;'a&gt; { &gt; self.attribute_dependencies.insert_hash(name.get_hash()); &gt; self.attribute_dependencies &gt; .insert_hash(lower_name.get_hash()); &gt; } &gt; true &gt; } &gt; &gt; fn visit_simple_selector(&amp;mut self, s: &amp;Component&lt;SelectorImpl&gt;) -&gt; bool { &gt;- self.needs_revalidation = self.needs_revalidation || &gt;- component_needs_revalidation(s, self.passed_rightmost_selector); &gt;+ self.needs_revalidation = &gt;+ self.needs_revalidation &gt;+ || component_needs_revalidation(s, self.passed_rightmost_selector); &gt; &gt; match *s { &gt; Component::NonTSPseudoClass(ref p) =&gt; { &gt; self.state_dependencies.insert(p.state_flag()); &gt; self.document_state_dependencies &gt; .insert(p.document_state_flag()); &gt;- }, &gt;+ } &gt; Component::ID(ref id) if !self.passed_rightmost_selector =&gt; { &gt; // We want to stop storing mapped ids as soon as we've moved off &gt; // the rightmost ComplexSelector that is not a pseudo-element. &gt; // &gt; // That can be detected by a visit_complex_selector call with a &gt; // combinator other than None and PseudoElement. &gt; // &gt; // Importantly, this call happens before we visit any of the &gt; // simple selectors in that ComplexSelector. &gt; // &gt; // NOTE(emilio): See the comment regarding on when this may &gt; // break in visit_complex_selector. &gt; self.mapped_ids.insert_hash(id.get_hash()); &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; &gt; true &gt; } &gt; } &gt; &gt; /// A set of rules for element and pseudo-elements. &gt; #[derive(Debug, Default, MallocSizeOf)] &gt;@@ -1880,17 +1890,18 @@ impl ElementAndPseudoRules { &gt; rule: Rule, &gt; pseudo_element: Option&lt;&amp;PseudoElement&gt;, &gt; quirks_mode: QuirksMode, &gt; ) -&gt; Result&lt;(), FailedAllocationError&gt; { &gt; debug_assert!(pseudo_element.map_or(true, |pseudo| !pseudo.is_precomputed())); &gt; &gt; let map = match pseudo_element { &gt; None =&gt; &amp;mut self.element_map, &gt;- Some(pseudo) =&gt; self.pseudos_map &gt;+ Some(pseudo) =&gt; self &gt;+ .pseudos_map &gt; .get_or_insert_with(pseudo, || Box::new(SelectorMap::new())), &gt; }; &gt; &gt; map.insert(rule, quirks_mode) &gt; } &gt; &gt; fn clear(&amp;mut self) { &gt; self.element_map.clear(); &gt;@@ -2041,17 +2052,17 @@ impl CascadeData { &gt; { &gt; if !collection.dirty() { &gt; return Ok(()); &gt; } &gt; &gt; let validity = collection.data_validity(); &gt; &gt; match validity { &gt;- DataValidity::Valid =&gt; {}, &gt;+ DataValidity::Valid =&gt; {} &gt; DataValidity::CascadeInvalid =&gt; self.clear_cascade_data(), &gt; DataValidity::FullyInvalid =&gt; self.clear(), &gt; } &gt; &gt; for (stylesheet, rebuild_kind) in collection { &gt; self.add_stylesheet( &gt; device, &gt; quirks_mode, &gt;@@ -2127,23 +2138,23 @@ impl CascadeData { &gt; results.saw_effective(stylesheet); &gt; &gt; for rule in stylesheet.effective_rules(device, guard) { &gt; match *rule { &gt; CssRule::Import(ref lock) =&gt; { &gt; let import_rule = lock.read_with(guard); &gt; debug!(" + {:?}", import_rule.stylesheet.media(guard)); &gt; results.saw_effective(import_rule); &gt;- }, &gt;+ } &gt; CssRule::Media(ref lock) =&gt; { &gt; let media_rule = lock.read_with(guard); &gt; debug!(" + {:?}", media_rule.media_queries.read_with(guard)); &gt; results.saw_effective(media_rule); &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; } &gt; } &gt; &gt; // Returns Err(..) to signify OOM &gt; fn add_stylesheet&lt;S&gt;( &gt; &amp;mut self, &gt; device: &amp;Device, &gt;@@ -2241,71 +2252,71 @@ impl CascadeData { &gt; .get_or_insert_with(|| Box::new(Default::default())) &gt; } else { &gt; &amp;mut self.normal_rules &gt; }; &gt; &gt; rules.insert(rule, pseudo_element, quirks_mode)?; &gt; } &gt; self.rules_source_order += 1; &gt;- }, &gt;+ } &gt; CssRule::Import(ref lock) =&gt; { &gt; if rebuild_kind.should_rebuild_invalidation() { &gt; let import_rule = lock.read_with(guard); &gt; self.effective_media_query_results &gt; .saw_effective(import_rule); &gt; } &gt; &gt; // NOTE: effective_rules visits the inner stylesheet if &gt; // appropriate. &gt;- }, &gt;+ } &gt; CssRule::Media(ref lock) =&gt; { &gt; if rebuild_kind.should_rebuild_invalidation() { &gt; let media_rule = lock.read_with(guard); &gt; self.effective_media_query_results.saw_effective(media_rule); &gt; } &gt;- }, &gt;+ } &gt; CssRule::Keyframes(ref keyframes_rule) =&gt; { &gt; let keyframes_rule = keyframes_rule.read_with(guard); &gt; debug!("Found valid keyframes rule: {:?}", *keyframes_rule); &gt; &gt; // Don't let a prefixed keyframes animation override a non-prefixed one. &gt;- let needs_insertion = keyframes_rule.vendor_prefix.is_none() || &gt;- self.animations &gt;- .get(keyframes_rule.name.as_atom()) &gt;- .map_or(true, |rule| rule.vendor_prefix.is_some()); &gt;+ let needs_insertion = keyframes_rule.vendor_prefix.is_none() || self &gt;+ .animations &gt;+ .get(keyframes_rule.name.as_atom()) &gt;+ .map_or(true, |rule| rule.vendor_prefix.is_some()); &gt; if needs_insertion { &gt; let animation = KeyframesAnimation::from_keyframes( &gt; &amp;keyframes_rule.keyframes, &gt; keyframes_rule.vendor_prefix.clone(), &gt; guard, &gt; ); &gt; debug!("Found valid keyframe animation: {:?}", animation); &gt; self.animations &gt; .try_insert(keyframes_rule.name.as_atom().clone(), animation)?; &gt; } &gt;- }, &gt;+ } &gt; #[cfg(feature = "gecko")] &gt; CssRule::FontFace(ref rule) =&gt; { &gt; self.extra_data.add_font_face(rule); &gt;- }, &gt;+ } &gt; #[cfg(feature = "gecko")] &gt; CssRule::FontFeatureValues(ref rule) =&gt; { &gt; self.extra_data.add_font_feature_values(rule); &gt;- }, &gt;+ } &gt; #[cfg(feature = "gecko")] &gt; CssRule::CounterStyle(ref rule) =&gt; { &gt; self.extra_data.add_counter_style(guard, rule); &gt;- }, &gt;+ } &gt; #[cfg(feature = "gecko")] &gt; CssRule::Page(ref rule) =&gt; { &gt; self.extra_data.add_page(rule); &gt;- }, &gt;+ } &gt; // We don't care about any other rule. &gt;- _ =&gt; {}, &gt;+ _ =&gt; {} &gt; } &gt; } &gt; &gt; Ok(()) &gt; } &gt; &gt; /// Returns whether all the media-feature affected values matched before and &gt; /// match now in the given stylesheet. &gt;@@ -2338,71 +2349,70 @@ impl CascadeData { &gt; if !effective_now { &gt; return true; &gt; } &gt; &gt; let mut iter = stylesheet.iter_rules::&lt;PotentiallyEffectiveMediaRules&gt;(device, guard); &gt; &gt; while let Some(rule) = iter.next() { &gt; match *rule { &gt;- CssRule::Style(..) | &gt;- CssRule::Namespace(..) | &gt;- CssRule::FontFace(..) | &gt;- CssRule::CounterStyle(..) | &gt;- CssRule::Supports(..) | &gt;- CssRule::Keyframes(..) | &gt;- CssRule::Page(..) | &gt;- CssRule::Viewport(..) | &gt;- CssRule::Document(..) | &gt;- CssRule::FontFeatureValues(..) =&gt; { &gt;+ CssRule::Style(..) &gt;+ | CssRule::Namespace(..) &gt;+ | CssRule::FontFace(..) &gt;+ | CssRule::CounterStyle(..) &gt;+ | CssRule::Supports(..) &gt;+ | CssRule::Keyframes(..) &gt;+ | CssRule::Page(..) &gt;+ | CssRule::Viewport(..) &gt;+ | CssRule::Document(..) &gt;+ | CssRule::FontFeatureValues(..) =&gt; { &gt; // Not affected by device changes. &gt; continue; &gt;- }, &gt;+ } &gt; CssRule::Import(ref lock) =&gt; { &gt; let import_rule = lock.read_with(guard); &gt; let effective_now = import_rule &gt; .stylesheet &gt; .is_effective_for_device(&amp;device, guard); &gt;- let effective_then = self.effective_media_query_results &gt;+ let effective_then = self &gt;+ .effective_media_query_results &gt; .was_effective(import_rule); &gt; if effective_now != effective_then { &gt; debug!( &gt; " &gt; @import rule {:?} changed {} -&gt; {}", &gt; import_rule.stylesheet.media(guard), &gt; effective_then, &gt; effective_now &gt; ); &gt; return false; &gt; } &gt; &gt; if !effective_now { &gt; iter.skip_children(); &gt; } &gt;- }, &gt;+ } &gt; CssRule::Media(ref lock) =&gt; { &gt; let media_rule = lock.read_with(guard); &gt; let mq = media_rule.media_queries.read_with(guard); &gt; let effective_now = mq.evaluate(device, quirks_mode); &gt; let effective_then = &gt; self.effective_media_query_results.was_effective(media_rule); &gt; &gt; if effective_now != effective_then { &gt; debug!( &gt; " &gt; @media rule {:?} changed {} -&gt; {}", &gt;- mq, &gt;- effective_then, &gt;- effective_now &gt;+ mq, effective_then, effective_now &gt; ); &gt; return false; &gt; } &gt; &gt; if !effective_now { &gt; iter.skip_children(); &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; true &gt; } &gt; &gt; /// Clears the cascade data, but not the invalidation data. &gt; fn clear_cascade_data(&amp;mut self) { &gt;@@ -2465,18 +2475,20 @@ pub struct Rule { &gt; pub hashes: AncestorHashes, &gt; &gt; /// The source order this style rule appears in. Note that we only use &gt; /// three bytes to store this value in ApplicableDeclarationsBlock, so &gt; /// we could repurpose that storage here if we needed to. &gt; pub source_order: u32, &gt; &gt; /// The actual style rule. &gt;- #[cfg_attr(feature = "gecko", &gt;- ignore_malloc_size_of = "Secondary ref. Primary ref is in StyleRule under Stylesheet.")] &gt;+ #[cfg_attr( &gt;+ feature = "gecko", &gt;+ ignore_malloc_size_of = "Secondary ref. Primary ref is in StyleRule under Stylesheet." &gt;+ )] &gt; #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] &gt; pub style_rule: Arc&lt;Locked&lt;StyleRule&gt;&gt;, &gt; } &gt; &gt; impl SelectorMapEntry for Rule { &gt; fn selector(&amp;self) -&gt; SelectorIter&lt;SelectorImpl&gt; { &gt; self.selector.iter() &gt; } &gt;@@ -2491,17 +2503,23 @@ impl Rule { &gt; /// Turns this rule into an `ApplicableDeclarationBlock` for the given &gt; /// cascade level. &gt; pub fn to_applicable_declaration_block( &gt; &amp;self, &gt; level: CascadeLevel, &gt; shadow_cascade_order: ShadowCascadeOrder, &gt; ) -&gt; ApplicableDeclarationBlock { &gt; let source = StyleSource::from_rule(self.style_rule.clone()); &gt;- ApplicableDeclarationBlock::new(source, self.source_order, level, self.specificity(), shadow_cascade_order) &gt;+ ApplicableDeclarationBlock::new( &gt;+ source, &gt;+ self.source_order, &gt;+ level, &gt;+ self.specificity(), &gt;+ shadow_cascade_order, &gt;+ ) &gt; } &gt; &gt; /// Creates a new Rule. &gt; pub fn new( &gt; selector: Selector&lt;SelectorImpl&gt;, &gt; hashes: AncestorHashes, &gt; style_rule: Arc&lt;Locked&lt;StyleRule&gt;&gt;, &gt; source_order: u32, &gt;diff --git a/servo/components/style/timer.rs b/servo/components/style/timer.rs &gt;index 54e6fcdfd90f..e9d9e71a13a4 100644 &gt;--- a/servo/components/style/timer.rs &gt;+++ b/servo/components/style/timer.rs &gt;@@ -52,12 +52,12 @@ impl Timer { &gt; } &gt; &gt; /// Increments the current clock. Panics if the clock is not on test mode. &gt; pub fn increment(&amp;mut self, by: f64) { &gt; match self.mode { &gt; TimerMode::Test(ref mut val) =&gt; *val += by, &gt; TimerMode::Current =&gt; { &gt; panic!("Timer::increment called for a non-test mode timer. This is a bug.") &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/style/traversal.rs b/servo/components/style/traversal.rs &gt;index 0bffd39819c4..200c31d82405 100644 &gt;--- a/servo/components/style/traversal.rs &gt;+++ b/servo/components/style/traversal.rs &gt;@@ -202,22 +202,22 @@ pub trait DomTraversal&lt;E: TElement&gt;: Sync { &gt; "element_needs_traversal({:?}, {:?}, {:?})", &gt; el, traversal_flags, data &gt; ); &gt; &gt; // In case of animation-only traversal we need to traverse the element &gt; // if the element has animation only dirty descendants bit, &gt; // animation-only restyle hint or recascade. &gt; if traversal_flags.for_animation_only() { &gt;- return data.map_or(false, |d| d.has_styles()) &amp;&amp; &gt;- (el.has_animation_only_dirty_descendants() || &gt;- data.as_ref() &gt;- .unwrap() &gt;- .hint &gt;- .has_animation_hint_or_recascade()); &gt;+ return data.map_or(false, |d| d.has_styles()) &gt;+ &amp;&amp; (el.has_animation_only_dirty_descendants() || data &gt;+ .as_ref() &gt;+ .unwrap() &gt;+ .hint &gt;+ .has_animation_hint_or_recascade()); &gt; } &gt; &gt; // Non-incremental layout visits every node. &gt; if is_servo_nonincremental_layout() { &gt; return true; &gt; } &gt; &gt; // Unwrap the data. &gt;@@ -274,18 +274,19 @@ pub trait DomTraversal&lt;E: TElement&gt;: Sync { &gt; &gt; // Gecko-only XBL handling. &gt; // &gt; // When we apply the XBL binding during frame construction, we restyle &gt; // the whole subtree again if the binding is valid, so assuming it's &gt; // likely to load valid bindings, we avoid wasted work here, which may &gt; // be a very big perf hit when elements with bindings are nested &gt; // heavily. &gt;- if cfg!(feature = "gecko") &amp;&amp; is_initial_style &amp;&amp; &gt;- parent_data.styles.primary().has_moz_binding() &gt;+ if cfg!(feature = "gecko") &gt;+ &amp;&amp; is_initial_style &gt;+ &amp;&amp; parent_data.styles.primary().has_moz_binding() &gt; { &gt; debug!("Parent {:?} has XBL binding, deferring traversal", parent); &gt; return true; &gt; } &gt; &gt; return false; &gt; } &gt; &gt;@@ -304,19 +305,19 @@ pub fn resolve_style&lt;E&gt;( &gt; pseudo: Option&lt;&amp;PseudoElement&gt;, &gt; ) -&gt; ElementStyles &gt; where &gt; E: TElement, &gt; { &gt; use style_resolver::StyleResolverForElement; &gt; &gt; debug_assert!( &gt;- rule_inclusion == RuleInclusion::DefaultOnly || &gt;- pseudo.map_or(false, |p| p.is_before_or_after()) || &gt;- element.borrow_data().map_or(true, |d| !d.has_styles()), &gt;+ rule_inclusion == RuleInclusion::DefaultOnly &gt;+ || pseudo.map_or(false, |p| p.is_before_or_after()) &gt;+ || element.borrow_data().map_or(true, |d| !d.has_styles()), &gt; "Why are we here?" &gt; ); &gt; let mut ancestors_requiring_style_resolution = SmallVec::&lt;[E; 16]&gt;::new(); &gt; &gt; // Clear the bloom filter, just in case the caller is reusing TLS. &gt; context.thread_local.bloom_filter.clear(); &gt; &gt; let mut style = None; &gt;@@ -379,18 +380,17 @@ where &gt; StyleResolverForElement::new( &gt; element, &gt; context, &gt; rule_inclusion, &gt; PseudoElementResolution::Force, &gt; ).resolve_style( &gt; style.as_ref().map(|s| &amp;**s), &gt; layout_parent_style.as_ref().map(|s| &amp;**s), &gt;- ) &gt;- .into() &gt;+ ).into() &gt; } &gt; &gt; /// Calculates the style for a single node. &gt; #[inline] &gt; #[allow(unsafe_code)] &gt; pub fn recalc_style_at&lt;E, D, F&gt;( &gt; traversal: &amp;D, &gt; traversal_data: &amp;PerLevelTraversalData, &gt;@@ -406,18 +406,19 @@ pub fn recalc_style_at&lt;E, D, F&gt;( &gt; use std::cmp; &gt; use traversal_flags::TraversalFlags; &gt; &gt; let flags = context.shared.traversal_flags; &gt; let is_initial_style = !data.has_styles(); &gt; &gt; context.thread_local.statistics.elements_traversed += 1; &gt; debug_assert!( &gt;- flags.intersects(TraversalFlags::AnimationOnly) || !element.has_snapshot() || &gt;- element.handled_snapshot(), &gt;+ flags.intersects(TraversalFlags::AnimationOnly) &gt;+ || !element.has_snapshot() &gt;+ || element.handled_snapshot(), &gt; "Should've handled snapshots here already" &gt; ); &gt; &gt; let compute_self = !element.has_current_styles_for_traversal(data, flags); &gt; &gt; debug!( &gt; "recalc_style_at: {:?} (compute_self={:?}, \ &gt; dirty_descendants={:?}, data={:?})", &gt;@@ -502,23 +503,24 @@ pub fn recalc_style_at&lt;E, D, F&gt;( &gt; // * We have the dirty descendants bit. &gt; // * We're propagating a restyle hint. &gt; // * We can't skip the cascade. &gt; // * This is a servo non-incremental traversal. &gt; // &gt; // Additionally, there are a few scenarios where we avoid traversing the &gt; // subtree even if descendant styles are out of date. These cases are &gt; // enumerated in should_cull_subtree(). &gt;- let mut traverse_children = has_dirty_descendants_for_this_restyle || &gt;- !propagated_hint.is_empty() || &gt;- !child_cascade_requirement.can_skip_cascade() || &gt;- is_servo_nonincremental_layout(); &gt;+ let mut traverse_children = has_dirty_descendants_for_this_restyle &gt;+ || !propagated_hint.is_empty() &gt;+ || !child_cascade_requirement.can_skip_cascade() &gt;+ || is_servo_nonincremental_layout(); &gt; &gt;- traverse_children = traverse_children &amp;&amp; &gt;- !traversal.should_cull_subtree(context, element, &amp;data, is_initial_style); &gt;+ traverse_children = &gt;+ traverse_children &gt;+ &amp;&amp; !traversal.should_cull_subtree(context, element, &amp;data, is_initial_style); &gt; &gt; // Examine our children, and enqueue the appropriate ones for traversal. &gt; if traverse_children { &gt; note_children::&lt;E, D, F&gt;( &gt; context, &gt; element, &gt; data, &gt; propagated_hint, &gt;@@ -530,18 +532,19 @@ pub fn recalc_style_at&lt;E, D, F&gt;( &gt; &gt; // FIXME(bholley): Make these assertions pass for servo. &gt; if cfg!(feature = "gecko") &amp;&amp; cfg!(debug_assertions) &amp;&amp; data.styles.is_display_none() { &gt; debug_assert!(!element.has_dirty_descendants()); &gt; debug_assert!(!element.has_animation_only_dirty_descendants()); &gt; } &gt; &gt; debug_assert!( &gt;- flags.for_animation_only() || !flags.contains(TraversalFlags::ClearDirtyBits) || &gt;- !element.has_animation_only_dirty_descendants(), &gt;+ flags.for_animation_only() &gt;+ || !flags.contains(TraversalFlags::ClearDirtyBits) &gt;+ || !element.has_animation_only_dirty_descendants(), &gt; "Should have cleared animation bits already" &gt; ); &gt; clear_state_after_traversing(element, data, flags); &gt; } &gt; &gt; fn clear_state_after_traversing&lt;E&gt;(element: E, data: &amp;mut ElementData, flags: TraversalFlags) &gt; where &gt; E: TElement, &gt;@@ -617,17 +620,17 @@ where &gt; let mut target = StyleSharingTarget::new(element); &gt; &gt; // Now that our bloom filter is set up, try the style sharing &gt; // cache. &gt; match target.share_style_if_possible(context) { &gt; Some(shared_styles) =&gt; { &gt; context.thread_local.statistics.styles_shared += 1; &gt; shared_styles &gt;- }, &gt;+ } &gt; None =&gt; { &gt; context.thread_local.statistics.elements_matched += 1; &gt; // Perform the matching and cascading. &gt; let new_styles = { &gt; let mut resolver = StyleResolverForElement::new( &gt; element, &gt; context, &gt; RuleInclusion::All, &gt;@@ -640,33 +643,33 @@ where &gt; context.thread_local.sharing_cache.insert_if_possible( &gt; &amp;element, &gt; &amp;new_styles.primary, &gt; Some(&amp;mut target), &gt; traversal_data.current_dom_depth, &gt; ); &gt; &gt; new_styles &gt;- }, &gt;+ } &gt; } &gt;- }, &gt;+ } &gt; CascadeWithReplacements(flags) =&gt; { &gt; // Skipping full matching, load cascade inputs from previous values. &gt; let mut cascade_inputs = ElementCascadeInputs::new_from_element_data(data); &gt; important_rules_changed = element.replace_rules(flags, context, &amp;mut cascade_inputs); &gt; &gt; let mut resolver = StyleResolverForElement::new( &gt; element, &gt; context, &gt; RuleInclusion::All, &gt; PseudoElementResolution::IfApplicable, &gt; ); &gt; &gt; resolver.cascade_styles_with_default_parents(cascade_inputs) &gt;- }, &gt;+ } &gt; CascadeOnly =&gt; { &gt; // Skipping full matching, load cascade inputs from previous values. &gt; let cascade_inputs = ElementCascadeInputs::new_from_element_data(data); &gt; &gt; let new_styles = { &gt; let mut resolver = StyleResolverForElement::new( &gt; element, &gt; context, &gt;@@ -697,41 +700,41 @@ where &gt; &amp;element, &gt; &amp;new_styles.primary, &gt; None, &gt; traversal_data.current_dom_depth, &gt; ); &gt; } &gt; &gt; new_styles &gt;- }, &gt;+ } &gt; }; &gt; &gt; element.finish_restyle(context, data, new_styles, important_rules_changed) &gt; } &gt; &gt; #[cfg(feature = "servo")] &gt; fn notify_paint_worklet&lt;E&gt;(context: &amp;StyleContext&lt;E&gt;, data: &amp;ElementData) &gt; where &gt; E: TElement, &gt; { &gt; use style_traits::ToCss; &gt;- use values::Either; &gt; use values::generics::image::Image; &gt;+ use values::Either; &gt; &gt; // We speculatively evaluate any paint worklets during styling. &gt; // This allows us to run paint worklets in parallel with style and layout. &gt; // Note that this is wasted effort if the size of the node has &gt; // changed, but in may cases it won't have. &gt; if let Some(ref values) = data.styles.primary { &gt; for image in &amp;values.get_background().background_image.0 { &gt; let (name, arguments) = match *image { &gt; Either::Second(Image::PaintWorklet(ref worklet)) =&gt; { &gt; (&amp;worklet.name, &amp;worklet.arguments) &gt;- }, &gt;+ } &gt; _ =&gt; continue, &gt; }; &gt; let painter = match context.shared.registered_speculative_painters.get(name) { &gt; Some(painter) =&gt; painter, &gt; None =&gt; continue, &gt; }; &gt; let properties = painter &gt; .properties() &gt;@@ -773,56 +776,56 @@ fn note_children&lt;E, D, F&gt;( &gt; trace!("note_children: {:?}", element); &gt; let flags = context.shared.traversal_flags; &gt; &gt; // Loop over all the traversal children. &gt; for child_node in element.traversal_children() { &gt; let child = match child_node.as_element() { &gt; Some(el) =&gt; el, &gt; None =&gt; { &gt;- if is_servo_nonincremental_layout() || &gt;- D::text_node_needs_traversal(child_node, data) &gt;+ if is_servo_nonincremental_layout() &gt;+ || D::text_node_needs_traversal(child_node, data) &gt; { &gt; note_child(child_node); &gt; } &gt; continue; &gt;- }, &gt;+ } &gt; }; &gt; &gt; let mut child_data = child.mutate_data(); &gt; let mut child_data = child_data.as_mut().map(|d| &amp;mut **d); &gt; trace!( &gt; " &gt; {:?} -&gt; {:?} + {:?}, pseudo: {:?}", &gt; child, &gt; child_data.as_ref().map(|d| d.hint), &gt; propagated_hint, &gt; child.implemented_pseudo_element() &gt; ); &gt; &gt; if let Some(ref mut child_data) = child_data { &gt; let mut child_hint = propagated_hint; &gt; match cascade_requirement { &gt;- ChildCascadeRequirement::CanSkipCascade =&gt; {}, &gt;+ ChildCascadeRequirement::CanSkipCascade =&gt; {} &gt; ChildCascadeRequirement::MustCascadeDescendants =&gt; { &gt; child_hint |= RestyleHint::RECASCADE_SELF | RestyleHint::RECASCADE_DESCENDANTS; &gt;- }, &gt;+ } &gt; ChildCascadeRequirement::MustCascadeChildrenIfInheritResetStyle =&gt; { &gt; use properties::computed_value_flags::ComputedValueFlags; &gt; if child_data &gt; .styles &gt; .primary() &gt; .flags &gt; .contains(ComputedValueFlags::INHERITS_RESET_STYLE) &gt; { &gt; child_hint |= RestyleHint::RECASCADE_SELF; &gt; } &gt;- }, &gt;+ } &gt; ChildCascadeRequirement::MustCascadeChildren =&gt; { &gt; child_hint |= RestyleHint::RECASCADE_SELF; &gt;- }, &gt;+ } &gt; } &gt; &gt; child_data.hint.insert(child_hint); &gt; &gt; // Handle element snapshots and invalidation of descendants and siblings &gt; // as needed. &gt; // &gt; // NB: This will be a no-op if there's no snapshot. &gt;diff --git a/servo/components/style/values/animated/color.rs b/servo/components/style/values/animated/color.rs &gt;index 4356c5a3d9bf..2a6a8827f8d7 100644 &gt;--- a/servo/components/style/values/animated/color.rs &gt;+++ b/servo/components/style/values/animated/color.rs &gt;@@ -55,18 +55,19 @@ impl Animate for RGBA { &gt; // Ideally we should return color value that only alpha component is &gt; // 0, but this is what current gecko does. &gt; return Ok(RGBA::transparent()); &gt; } &gt; &gt; alpha = alpha.min(1.); &gt; let red = &gt; (self.red * self.alpha).animate(&amp;(other.red * other.alpha), procedure)? * 1. / alpha; &gt;- let green = (self.green * self.alpha).animate(&amp;(other.green * other.alpha), procedure)? * &gt;- 1. / alpha; &gt;+ let green = (self.green * self.alpha).animate(&amp;(other.green * other.alpha), procedure)? &gt;+ * 1. &gt;+ / alpha; &gt; let blue = &gt; (self.blue * self.alpha).animate(&amp;(other.blue * other.alpha), procedure)? * 1. / alpha; &gt; &gt; Ok(RGBA::new(red, green, blue, alpha)) &gt; } &gt; } &gt; &gt; impl ComputeSquaredDistance for RGBA { &gt;diff --git a/servo/components/style/values/animated/effects.rs b/servo/components/style/values/animated/effects.rs &gt;index a201ec0549e3..dca36779ebc7 100644 &gt;--- a/servo/components/style/values/animated/effects.rs &gt;+++ b/servo/components/style/values/animated/effects.rs &gt;@@ -1,25 +1,25 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Animated types for CSS values related to effects. &gt; &gt;-#[cfg(not(feature = "gecko"))] &gt;-use values::Impossible; &gt; use values::animated::color::Color; &gt;-use values::computed::{Angle, Number}; &gt; use values::computed::length::Length; &gt; #[cfg(feature = "gecko")] &gt; use values::computed::url::ComputedUrl; &gt;+use values::computed::{Angle, Number}; &gt; use values::distance::{ComputeSquaredDistance, SquaredDistance}; &gt; use values::generics::effects::BoxShadow as GenericBoxShadow; &gt; use values::generics::effects::Filter as GenericFilter; &gt; use values::generics::effects::SimpleShadow as GenericSimpleShadow; &gt;+#[cfg(not(feature = "gecko"))] &gt;+use values::Impossible; &gt; &gt; /// An animated value for a single `box-shadow`. &gt; pub type BoxShadow = GenericBoxShadow&lt;Color, Length, Length, Length&gt;; &gt; &gt; /// An animated value for a single `filter`. &gt; #[cfg(feature = "gecko")] &gt; pub type Filter = GenericFilter&lt;Angle, Number, Length, SimpleShadow, ComputedUrl&gt;; &gt; &gt;@@ -31,12 +31,12 @@ pub type Filter = GenericFilter&lt;Angle, Number, Length, Impossible, Impossible&gt;; &gt; pub type SimpleShadow = GenericSimpleShadow&lt;Color, Length, Length&gt;; &gt; &gt; impl ComputeSquaredDistance for BoxShadow { &gt; #[inline] &gt; fn compute_squared_distance(&amp;self, other: &amp;Self) -&gt; Result&lt;SquaredDistance, ()&gt; { &gt; if self.inset != other.inset { &gt; return Err(()); &gt; } &gt;- Ok(self.base.compute_squared_distance(&amp;other.base)? + &gt;- self.spread.compute_squared_distance(&amp;other.spread)?) &gt;+ Ok(self.base.compute_squared_distance(&amp;other.base)? &gt;+ + self.spread.compute_squared_distance(&amp;other.spread)?) &gt; } &gt; } &gt;diff --git a/servo/components/style/values/animated/mod.rs b/servo/components/style/values/animated/mod.rs &gt;index 53d3719b0213..0d23e062767d 100644 &gt;--- a/servo/components/style/values/animated/mod.rs &gt;+++ b/servo/components/style/values/animated/mod.rs &gt;@@ -6,22 +6,22 @@ &gt; //! &gt; //! Some values, notably colors, cannot be interpolated directly with their &gt; //! computed values and need yet another intermediate representation. This &gt; //! module's raison d'être is to ultimately contain all these types. &gt; &gt; use app_units::Au; &gt; use euclid::{Point2D, Size2D}; &gt; use smallvec::SmallVec; &gt;+use values::computed::length::CalcLengthOrPercentage; &gt;+use values::computed::url::ComputedUrl; &gt; use values::computed::Angle as ComputedAngle; &gt; use values::computed::BorderCornerRadius as ComputedBorderCornerRadius; &gt; use values::computed::MaxLength as ComputedMaxLength; &gt; use values::computed::MozLength as ComputedMozLength; &gt;-use values::computed::length::CalcLengthOrPercentage; &gt;-use values::computed::url::ComputedUrl; &gt; &gt; pub mod color; &gt; pub mod effects; &gt; &gt; /// Animate from one value to another. &gt; /// &gt; /// This trait is derivable with `#[derive(Animate)]`. The derived &gt; /// implementation uses a `match` expression with identical patterns for both &gt;@@ -292,24 +292,24 @@ impl ToAnimatedValue for ComputedMaxLength { &gt; #[inline] &gt; fn from_animated_value(animated: Self::AnimatedValue) -&gt; Self { &gt; use values::computed::{Length, LengthOrPercentageOrNone, Percentage}; &gt; match animated { &gt; ComputedMaxLength::LengthOrPercentageOrNone(lopn) =&gt; { &gt; let result = match lopn { &gt; LengthOrPercentageOrNone::Length(px) =&gt; { &gt; LengthOrPercentageOrNone::Length(Length::new(px.px().max(0.))) &gt;- }, &gt;+ } &gt; LengthOrPercentageOrNone::Percentage(percentage) =&gt; { &gt; LengthOrPercentageOrNone::Percentage(Percentage(percentage.0.max(0.))) &gt;- }, &gt;+ } &gt; _ =&gt; lopn, &gt; }; &gt; ComputedMaxLength::LengthOrPercentageOrNone(result) &gt;- }, &gt;+ } &gt; _ =&gt; animated, &gt; } &gt; } &gt; } &gt; &gt; impl ToAnimatedValue for ComputedMozLength { &gt; type AnimatedValue = Self; &gt; &gt;@@ -321,24 +321,24 @@ impl ToAnimatedValue for ComputedMozLength { &gt; #[inline] &gt; fn from_animated_value(animated: Self::AnimatedValue) -&gt; Self { &gt; use values::computed::{Length, LengthOrPercentageOrAuto, Percentage}; &gt; match animated { &gt; ComputedMozLength::LengthOrPercentageOrAuto(lopa) =&gt; { &gt; let result = match lopa { &gt; LengthOrPercentageOrAuto::Length(px) =&gt; { &gt; LengthOrPercentageOrAuto::Length(Length::new(px.px().max(0.))) &gt;- }, &gt;+ } &gt; LengthOrPercentageOrAuto::Percentage(percentage) =&gt; { &gt; LengthOrPercentageOrAuto::Percentage(Percentage(percentage.0.max(0.))) &gt;- }, &gt;+ } &gt; _ =&gt; lopa, &gt; }; &gt; ComputedMozLength::LengthOrPercentageOrAuto(result) &gt;- }, &gt;+ } &gt; _ =&gt; animated, &gt; } &gt; } &gt; } &gt; &gt; impl ToAnimatedZero for Au { &gt; #[inline] &gt; fn to_animated_zero(&amp;self) -&gt; Result&lt;Self, ()&gt; { &gt;diff --git a/servo/components/style/values/computed/angle.rs b/servo/components/style/values/computed/angle.rs &gt;index 67ea5d1231bd..f304e329f21e 100644 &gt;--- a/servo/components/style/values/computed/angle.rs &gt;+++ b/servo/components/style/values/computed/angle.rs &gt;@@ -1,26 +1,28 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed angles. &gt; &gt; use num_traits::Zero; &gt;-use std::{f32, f64}; &gt; use std::f64::consts::PI; &gt; use std::ops::Add; &gt;-use values::CSSFloat; &gt;+use std::{f32, f64}; &gt; use values::animated::{Animate, Procedure}; &gt; use values::distance::{ComputeSquaredDistance, SquaredDistance}; &gt;+use values::CSSFloat; &gt; &gt; /// A computed angle. &gt; #[animate(fallback = "Self::animate_fallback")] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToAnimatedZero, ToCss)] &gt;+#[derive( &gt;+ Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToAnimatedZero, ToCss, &gt;+)] &gt; pub enum Angle { &gt; /// An angle with degree unit. &gt; #[css(dimension)] &gt; Deg(CSSFloat), &gt; /// An angle with gradian unit. &gt; #[css(dimension)] &gt; Grad(CSSFloat), &gt; /// An angle with radian unit. &gt;@@ -68,17 +70,19 @@ impl Angle { &gt; pub fn degrees(&amp;self) -&gt; f32 { &gt; use std::f32::consts::PI; &gt; self.radians() * 360. / (2. * PI) &gt; } &gt; &gt; /// &lt;https://drafts.csswg.org/css-transitions/#animtype-number&gt; &gt; #[inline] &gt; fn animate_fallback(&amp;self, other: &amp;Self, procedure: Procedure) -&gt; Result&lt;Self, ()&gt; { &gt;- Ok(Angle::from_radians(self.radians().animate(&amp;other.radians(), procedure)?)) &gt;+ Ok(Angle::from_radians( &gt;+ self.radians().animate(&amp;other.radians(), procedure)?, &gt;+ )) &gt; } &gt; } &gt; &gt; impl AsRef&lt;Angle&gt; for Angle { &gt; #[inline] &gt; fn as_ref(&amp;self) -&gt; &amp;Self { &gt; self &gt; } &gt;diff --git a/servo/components/style/values/computed/background.rs b/servo/components/style/values/computed/background.rs &gt;index e94bece983e5..bd701b735943 100644 &gt;--- a/servo/components/style/values/computed/background.rs &gt;+++ b/servo/components/style/values/computed/background.rs &gt;@@ -1,18 +1,18 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed types for CSS values related to backgrounds. &gt; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ToCss}; &gt;-use values::computed::{Context, ToComputedValue}; &gt; use values::computed::length::NonNegativeLengthOrPercentageOrAuto; &gt;+use values::computed::{Context, ToComputedValue}; &gt; use values::generics::background::BackgroundSize as GenericBackgroundSize; &gt; use values::specified::background::BackgroundRepeat as SpecifiedBackgroundRepeat; &gt; use values::specified::background::BackgroundRepeatKeyword; &gt; &gt; /// A computed value for the `background-size` property. &gt; pub type BackgroundSize = GenericBackgroundSize&lt;NonNegativeLengthOrPercentageOrAuto&gt;; &gt; &gt; impl BackgroundSize { &gt;@@ -44,28 +44,28 @@ impl BackgroundRepeat { &gt; impl ToCss for BackgroundRepeat { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; match (self.0, self.1) { &gt; (BackgroundRepeatKeyword::Repeat, BackgroundRepeatKeyword::NoRepeat) =&gt; { &gt; dest.write_str("repeat-x") &gt;- }, &gt;+ } &gt; (BackgroundRepeatKeyword::NoRepeat, BackgroundRepeatKeyword::Repeat) =&gt; { &gt; dest.write_str("repeat-y") &gt;- }, &gt;+ } &gt; (horizontal, vertical) =&gt; { &gt; horizontal.to_css(dest)?; &gt; if horizontal != vertical { &gt; dest.write_str(" ")?; &gt; vertical.to_css(dest)?; &gt; } &gt; Ok(()) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl ToComputedValue for SpecifiedBackgroundRepeat { &gt; type ComputedValue = BackgroundRepeat; &gt; &gt; #[inline] &gt;@@ -76,29 +76,29 @@ impl ToComputedValue for SpecifiedBackgroundRepeat { &gt; BackgroundRepeatKeyword::NoRepeat, &gt; ), &gt; SpecifiedBackgroundRepeat::RepeatY =&gt; BackgroundRepeat( &gt; BackgroundRepeatKeyword::NoRepeat, &gt; BackgroundRepeatKeyword::Repeat, &gt; ), &gt; SpecifiedBackgroundRepeat::Keywords(horizontal, vertical) =&gt; { &gt; BackgroundRepeat(horizontal, vertical.unwrap_or(horizontal)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; // FIXME(emilio): Why can't this just be: &gt; // SpecifiedBackgroundRepeat::Keywords(computed.0, computed.1) &gt; match (computed.0, computed.1) { &gt; (BackgroundRepeatKeyword::Repeat, BackgroundRepeatKeyword::NoRepeat) =&gt; { &gt; SpecifiedBackgroundRepeat::RepeatX &gt;- }, &gt;+ } &gt; (BackgroundRepeatKeyword::NoRepeat, BackgroundRepeatKeyword::Repeat) =&gt; { &gt; SpecifiedBackgroundRepeat::RepeatY &gt;- }, &gt;+ } &gt; (horizontal, vertical) =&gt; { &gt; SpecifiedBackgroundRepeat::Keywords(horizontal, Some(vertical)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/style/values/computed/basic_shape.rs b/servo/components/style/values/computed/basic_shape.rs &gt;index c140439af4ef..770e37f523fb 100644 &gt;--- a/servo/components/style/values/computed/basic_shape.rs &gt;+++ b/servo/components/style/values/computed/basic_shape.rs &gt;@@ -4,18 +4,18 @@ &gt; &gt; //! CSS handling for the computed value of &gt; //! [`basic-shape`][basic-shape]s &gt; //! &gt; //! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape &gt; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ToCss}; &gt;-use values::computed::{Image, LengthOrPercentage}; &gt; use values::computed::url::ComputedUrl; &gt;+use values::computed::{Image, LengthOrPercentage}; &gt; use values::generics::basic_shape as generic; &gt; &gt; /// A computed clipping shape. &gt; pub type ClippingShape = generic::ClippingShape&lt;BasicShape, ComputedUrl&gt;; &gt; &gt; /// A computed float area shape. &gt; pub type FloatAreaShape = generic::FloatAreaShape&lt;BasicShape, Image&gt;; &gt; &gt;diff --git a/servo/components/style/values/computed/border.rs b/servo/components/style/values/computed/border.rs &gt;index cf97a96ad736..a305d03803f1 100644 &gt;--- a/servo/components/style/values/computed/border.rs &gt;+++ b/servo/components/style/values/computed/border.rs &gt;@@ -1,18 +1,18 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed types for CSS values related to borders. &gt; &gt; use app_units::Au; &gt; use values::animated::ToAnimatedZero; &gt;-use values::computed::{Number, NumberOrPercentage}; &gt; use values::computed::length::{LengthOrPercentage, NonNegativeLength}; &gt;+use values::computed::{Number, NumberOrPercentage}; &gt; use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; &gt; use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth; &gt; use values::generics::border::BorderImageSlice as GenericBorderImageSlice; &gt; use values::generics::border::BorderRadius as GenericBorderRadius; &gt; use values::generics::border::BorderSpacing as GenericBorderSpacing; &gt; use values::generics::rect::Rect; &gt; use values::generics::size::Size; &gt; &gt;diff --git a/servo/components/style/values/computed/box.rs b/servo/components/style/values/computed/box.rs &gt;index 15e447ea4156..a1ca87aeac86 100644 &gt;--- a/servo/components/style/values/computed/box.rs &gt;+++ b/servo/components/style/values/computed/box.rs &gt;@@ -1,24 +1,26 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed types for box properties. &gt; &gt;-use values::computed::{Context, Number, ToComputedValue}; &gt; use values::computed::length::{LengthOrPercentage, NonNegativeLength}; &gt;+use values::computed::{Context, Number, ToComputedValue}; &gt; use values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount; &gt; use values::generics::box_::Perspective as GenericPerspective; &gt; use values::generics::box_::VerticalAlign as GenericVerticalAlign; &gt; use values::specified::box_ as specified; &gt; &gt; pub use values::specified::box_::{AnimationName, Appearance, Contain, Display, OverflowClipBox}; &gt; pub use values::specified::box_::{Clear as SpecifiedClear, Float as SpecifiedFloat}; &gt;-pub use values::specified::box_::{OverscrollBehavior, ScrollSnapType, TouchAction, TransitionProperty, WillChange}; &gt;+pub use values::specified::box_::{ &gt;+ OverscrollBehavior, ScrollSnapType, TouchAction, TransitionProperty, WillChange, &gt;+}; &gt; &gt; /// A computed value for the `vertical-align` property. &gt; pub type VerticalAlign = GenericVerticalAlign&lt;LengthOrPercentage&gt;; &gt; &gt; /// A computed value for the `animation-iteration-count` property. &gt; pub type AnimationIterationCount = GenericAnimationIterationCount&lt;Number&gt;; &gt; &gt; impl AnimationIterationCount { &gt;@@ -29,109 +31,119 @@ impl AnimationIterationCount { &gt; } &gt; } &gt; &gt; /// A computed value for the `perspective` property. &gt; pub type Perspective = GenericPerspective&lt;NonNegativeLength&gt;; &gt; &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, &gt;+)] &gt; /// A computed value for the `float` property. &gt; pub enum Float { &gt; Left, &gt; Right, &gt;- None &gt;+ None, &gt; } &gt; &gt; impl ToComputedValue for SpecifiedFloat { &gt; type ComputedValue = Float; &gt; &gt; #[inline] &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Self::ComputedValue { &gt; let ltr = context.style().writing_mode.is_bidi_ltr(); &gt; // https://drafts.csswg.org/css-logical-props/#float-clear &gt; match *self { &gt; SpecifiedFloat::InlineStart =&gt; { &gt;- context.rule_cache_conditions.borrow_mut() &gt;+ context &gt;+ .rule_cache_conditions &gt;+ .borrow_mut() &gt; .set_writing_mode_dependency(context.builder.writing_mode); &gt; if ltr { &gt; Float::Left &gt; } else { &gt; Float::Right &gt; } &gt;- }, &gt;+ } &gt; SpecifiedFloat::InlineEnd =&gt; { &gt;- context.rule_cache_conditions.borrow_mut() &gt;+ context &gt;+ .rule_cache_conditions &gt;+ .borrow_mut() &gt; .set_writing_mode_dependency(context.builder.writing_mode); &gt; if ltr { &gt; Float::Right &gt; } else { &gt; Float::Left &gt; } &gt;- }, &gt;+ } &gt; SpecifiedFloat::Left =&gt; Float::Left, &gt; SpecifiedFloat::Right =&gt; Float::Right, &gt;- SpecifiedFloat::None =&gt; Float::None &gt;+ SpecifiedFloat::None =&gt; Float::None, &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; SpecifiedFloat { &gt; match *computed { &gt; Float::Left =&gt; SpecifiedFloat::Left, &gt; Float::Right =&gt; SpecifiedFloat::Right, &gt;- Float::None =&gt; SpecifiedFloat::None &gt;+ Float::None =&gt; SpecifiedFloat::None, &gt; } &gt; } &gt; } &gt; &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, &gt;-SpecifiedValueInfo, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, &gt;+)] &gt; /// A computed value for the `clear` property. &gt; pub enum Clear { &gt; None, &gt; Left, &gt; Right, &gt;- Both &gt;+ Both, &gt; } &gt; &gt; impl ToComputedValue for SpecifiedClear { &gt; type ComputedValue = Clear; &gt; &gt; #[inline] &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Self::ComputedValue { &gt; let ltr = context.style().writing_mode.is_bidi_ltr(); &gt; // https://drafts.csswg.org/css-logical-props/#float-clear &gt; match *self { &gt; SpecifiedClear::InlineStart =&gt; { &gt;- context.rule_cache_conditions.borrow_mut() &gt;+ context &gt;+ .rule_cache_conditions &gt;+ .borrow_mut() &gt; .set_writing_mode_dependency(context.builder.writing_mode); &gt; if ltr { &gt; Clear::Left &gt; } else { &gt; Clear::Right &gt; } &gt;- }, &gt;+ } &gt; SpecifiedClear::InlineEnd =&gt; { &gt;- context.rule_cache_conditions.borrow_mut() &gt;+ context &gt;+ .rule_cache_conditions &gt;+ .borrow_mut() &gt; .set_writing_mode_dependency(context.builder.writing_mode); &gt; if ltr { &gt; Clear::Right &gt; } else { &gt; Clear::Left &gt; } &gt;- }, &gt;+ } &gt; SpecifiedClear::None =&gt; Clear::None, &gt; SpecifiedClear::Left =&gt; Clear::Left, &gt; SpecifiedClear::Right =&gt; Clear::Right, &gt;- SpecifiedClear::Both =&gt; Clear::Both &gt;+ SpecifiedClear::Both =&gt; Clear::Both, &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; SpecifiedClear { &gt; match *computed { &gt; Clear::None =&gt; SpecifiedClear::None, &gt; Clear::Left =&gt; SpecifiedClear::Left, &gt;@@ -155,26 +167,30 @@ pub enum Resize { &gt; impl ToComputedValue for specified::Resize { &gt; type ComputedValue = Resize; &gt; &gt; #[inline] &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Resize { &gt; let is_vertical = context.style().writing_mode.is_vertical(); &gt; match self { &gt; specified::Resize::Inline =&gt; { &gt;- context.rule_cache_conditions.borrow_mut() &gt;+ context &gt;+ .rule_cache_conditions &gt;+ .borrow_mut() &gt; .set_writing_mode_dependency(context.builder.writing_mode); &gt; if is_vertical { &gt; Resize::Vertical &gt; } else { &gt; Resize::Horizontal &gt; } &gt; } &gt; specified::Resize::Block =&gt; { &gt;- context.rule_cache_conditions.borrow_mut() &gt;+ context &gt;+ .rule_cache_conditions &gt;+ .borrow_mut() &gt; .set_writing_mode_dependency(context.builder.writing_mode); &gt; if is_vertical { &gt; Resize::Horizontal &gt; } else { &gt; Resize::Vertical &gt; } &gt; } &gt; specified::Resize::None =&gt; Resize::None, &gt;diff --git a/servo/components/style/values/computed/color.rs b/servo/components/style/values/computed/color.rs &gt;index 5effffe59661..6d0713ac1d4a 100644 &gt;--- a/servo/components/style/values/computed/color.rs &gt;+++ b/servo/components/style/values/computed/color.rs &gt;@@ -2,18 +2,18 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed color values. &gt; &gt; use cssparser::{Color as CSSParserColor, RGBA}; &gt; use std::fmt; &gt; use style_traits::{CssWriter, ToCss}; &gt;-use values::animated::ToAnimatedValue; &gt; use values::animated::color::RGBA as AnimatedRGBA; &gt;+use values::animated::ToAnimatedValue; &gt; use values::generics::color::Color as GenericColor; &gt; &gt; /// Computed value type for the specified RGBAColor. &gt; pub type RGBAColor = RGBA; &gt; &gt; /// The computed value of the `color` property. &gt; pub type ColorPropertyValue = RGBA; &gt; &gt;diff --git a/servo/components/style/values/computed/counters.rs b/servo/components/style/values/computed/counters.rs &gt;index fd8d7763f1cf..211ca6753e7f 100644 &gt;--- a/servo/components/style/values/computed/counters.rs &gt;+++ b/servo/components/style/values/computed/counters.rs &gt;@@ -15,9 +15,8 @@ pub type CounterIncrement = GenericCounterIncrement&lt;i32&gt;; &gt; /// A computed value for the `counter-increment` property. &gt; pub type CounterReset = GenericCounterReset&lt;i32&gt;; &gt; &gt; /// A computed value for the `content` property. &gt; pub type Content = generics::Content&lt;ComputedImageUrl&gt;; &gt; &gt; /// A computed content item. &gt; pub type ContentItem = generics::ContentItem&lt;ComputedImageUrl&gt;; &gt;- &gt;diff --git a/servo/components/style/values/computed/effects.rs b/servo/components/style/values/computed/effects.rs &gt;index 07ac6441b6c5..9a511c4fd89a 100644 &gt;--- a/servo/components/style/values/computed/effects.rs &gt;+++ b/servo/components/style/values/computed/effects.rs &gt;@@ -1,30 +1,32 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed types for CSS values related to effects. &gt; &gt;-#[cfg(not(feature = "gecko"))] &gt;-use values::Impossible; &gt;-use values::computed::{Angle, NonNegativeNumber}; &gt; use values::computed::color::Color; &gt; use values::computed::length::{Length, NonNegativeLength}; &gt; #[cfg(feature = "gecko")] &gt; use values::computed::url::ComputedUrl; &gt;+use values::computed::{Angle, NonNegativeNumber}; &gt; use values::generics::effects::BoxShadow as GenericBoxShadow; &gt; use values::generics::effects::Filter as GenericFilter; &gt; use values::generics::effects::SimpleShadow as GenericSimpleShadow; &gt;+#[cfg(not(feature = "gecko"))] &gt;+use values::Impossible; &gt; &gt; /// A computed value for a single shadow of the `box-shadow` property. &gt; pub type BoxShadow = GenericBoxShadow&lt;Color, Length, NonNegativeLength, Length&gt;; &gt; &gt; /// A computed value for a single `filter`. &gt; #[cfg(feature = "gecko")] &gt;-pub type Filter = GenericFilter&lt;Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow, ComputedUrl&gt;; &gt;+pub type Filter = &gt;+ GenericFilter&lt;Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow, ComputedUrl&gt;; &gt; &gt; /// A computed value for a single `filter`. &gt; #[cfg(not(feature = "gecko"))] &gt;-pub type Filter = GenericFilter&lt;Angle, NonNegativeNumber, NonNegativeLength, Impossible, Impossible&gt;; &gt;+pub type Filter = &gt;+ GenericFilter&lt;Angle, NonNegativeNumber, NonNegativeLength, Impossible, Impossible&gt;; &gt; &gt; /// A computed value for the `drop-shadow()` filter. &gt; pub type SimpleShadow = GenericSimpleShadow&lt;Color, Length, NonNegativeLength&gt;; &gt;diff --git a/servo/components/style/values/computed/font.rs b/servo/components/style/values/computed/font.rs &gt;index 8db4bd7e9171..7ac31c52c183 100644 &gt;--- a/servo/components/style/values/computed/font.rs &gt;+++ b/servo/components/style/values/computed/font.rs &gt;@@ -1,47 +1,46 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed values for font properties &gt; &gt;-use Atom; &gt; use app_units::Au; &gt; use byteorder::{BigEndian, ByteOrder}; &gt; use cssparser::{serialize_identifier, CssStringWriter, Parser}; &gt; #[cfg(feature = "gecko")] &gt;-use gecko_bindings::{bindings, structs}; &gt;-#[cfg(feature = "gecko")] &gt; use gecko_bindings::sugar::refptr::RefPtr; &gt; #[cfg(feature = "gecko")] &gt;+use gecko_bindings::{bindings, structs}; &gt;+#[cfg(feature = "gecko")] &gt; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; &gt; use std::fmt::{self, Write}; &gt; use std::hash::{Hash, Hasher}; &gt; #[cfg(feature = "servo")] &gt; use std::slice; &gt; use style_traits::{CssWriter, ParseError, ToCss}; &gt;-use values::CSSFloat; &gt; use values::animated::{ToAnimatedValue, ToAnimatedZero}; &gt; use values::computed::{Angle, Context, Integer, NonNegativeLength, NonNegativePercentage}; &gt; use values::computed::{Number, Percentage, ToComputedValue}; &gt; use values::generics::font::{self as generics, FeatureTagValue, FontSettings, VariationValue}; &gt;-use values::specified::font::{self as specified, MIN_FONT_WEIGHT, MAX_FONT_WEIGHT}; &gt;+use values::specified::font::{self as specified, MAX_FONT_WEIGHT, MIN_FONT_WEIGHT}; &gt; use values::specified::length::{FontBaseSize, NoCalcLength}; &gt;+use values::CSSFloat; &gt;+use Atom; &gt; &gt; pub use values::computed::Length as MozScriptMinSize; &gt; pub use values::specified::font::{FontSynthesis, MozScriptSizeMultiplier, XLang, XTextZoom}; &gt; &gt; /// A value for the font-weight property per: &gt; /// &gt; /// https://drafts.csswg.org/css-fonts-4/#propdef-font-weight &gt; /// &gt; /// This is effectively just a `Number`. &gt;-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, &gt;- ToCss)] &gt;+#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt; pub struct FontWeight(pub Number); &gt; &gt; impl Hash for FontWeight { &gt; fn hash&lt;H: Hasher&gt;(&amp;self, hasher: &amp;mut H) { &gt; hasher.write_u64((self.0 * 10000.).trunc() as u64); &gt; } &gt; } &gt;@@ -55,18 +54,27 @@ impl ToAnimatedValue for FontWeight { &gt; } &gt; &gt; #[inline] &gt; fn from_animated_value(animated: Self::AnimatedValue) -&gt; Self { &gt; FontWeight(animated.max(MIN_FONT_WEIGHT).min(MAX_FONT_WEIGHT)) &gt; } &gt; } &gt; &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, &gt;- ToAnimatedZero, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ ToAnimatedZero, &gt;+ ToCss, &gt;+)] &gt; /// The computed value of font-size &gt; pub struct FontSize { &gt; /// The size. &gt; pub size: NonNegativeLength, &gt; /// If derived from a keyword, the keyword and additional transformations applied to it &gt; #[css(skip)] &gt; pub keyword_info: Option&lt;KeywordInfo&gt;, &gt; } &gt;@@ -212,19 +220,19 @@ impl ToAnimatedValue for FontSize { &gt; #[cfg_attr(feature = "servo", derive(MallocSizeOf))] &gt; /// Specifies a prioritized list of font family names or generic family names. &gt; pub struct FontFamily(pub FontFamilyList); &gt; &gt; impl FontFamily { &gt; #[inline] &gt; /// Get default font family as `serif` which is a generic font-family &gt; pub fn serif() -&gt; Self { &gt;- FontFamily(FontFamilyList::new(Box::new([ &gt;- SingleFontFamily::Generic(atom!("serif")), &gt;- ]))) &gt;+ FontFamily(FontFamilyList::new(Box::new([SingleFontFamily::Generic( &gt;+ atom!("serif"), &gt;+ )]))) &gt; } &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt; impl MallocSizeOf for FontFamily { &gt; fn size_of(&amp;self, _ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; // SharedFontList objects are generally shared from the pointer &gt; // stored in the specified value. So only count this if the &gt;@@ -263,17 +271,17 @@ impl ToCss for FamilyName { &gt; where &gt; W: fmt::Write, &gt; { &gt; match self.syntax { &gt; FamilyNameSyntax::Quoted =&gt; { &gt; dest.write_char('"')?; &gt; write!(CssStringWriter::new(dest), "{}", self.name)?; &gt; dest.write_char('"') &gt;- }, &gt;+ } &gt; FamilyNameSyntax::Identifiers =&gt; { &gt; let mut first = true; &gt; for ident in self.name.to_string().split(' ') { &gt; if first { &gt; first = false; &gt; } else { &gt; dest.write_char(' ')?; &gt; } &gt;@@ -281,17 +289,17 @@ impl ToCss for FamilyName { &gt; !ident.is_empty(), &gt; "Family name with leading, \ &gt; trailing, or consecutive white spaces should \ &gt; have been marked quoted by the parser" &gt; ); &gt; serialize_identifier(ident, dest)?; &gt; } &gt; Ok(()) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt; /// Font family names must either be given quoted as strings, &gt; /// or unquoted as a sequence of one or more identifiers. &gt;@@ -331,22 +339,22 @@ impl SingleFontFamily { &gt; pub fn name(&amp;self) -&gt; &amp;str { &gt; self.atom() &gt; } &gt; &gt; #[cfg(not(feature = "gecko"))] // Gecko can't borrow atoms as UTF-8. &gt; /// Get the corresponding font-family with Atom &gt; pub fn from_atom(input: Atom) -&gt; SingleFontFamily { &gt; match input { &gt;- atom!("serif") | &gt;- atom!("sans-serif") | &gt;- atom!("cursive") | &gt;- atom!("fantasy") | &gt;- atom!("monospace") =&gt; return SingleFontFamily::Generic(input), &gt;- _ =&gt; {}, &gt;+ atom!("serif") &gt;+ | atom!("sans-serif") &gt;+ | atom!("cursive") &gt;+ | atom!("fantasy") &gt;+ | atom!("monospace") =&gt; return SingleFontFamily::Generic(input), &gt;+ _ =&gt; {} &gt; } &gt; match_ignore_ascii_case! { &amp;input, &gt; "serif" =&gt; return SingleFontFamily::Generic(atom!("serif")), &gt; "sans-serif" =&gt; return SingleFontFamily::Generic(atom!("sans-serif")), &gt; "cursive" =&gt; return SingleFontFamily::Generic(atom!("cursive")), &gt; "fantasy" =&gt; return SingleFontFamily::Generic(atom!("fantasy")), &gt; "monospace" =&gt; return SingleFontFamily::Generic(atom!("monospace")), &gt; _ =&gt; {} &gt;@@ -468,26 +476,24 @@ impl SingleFontFamily { &gt; use gecko_bindings::structs::FontFamilyType; &gt; &gt; match family.mType { &gt; FontFamilyType::eFamily_sans_serif =&gt; SingleFontFamily::Generic(atom!("sans-serif")), &gt; FontFamilyType::eFamily_serif =&gt; SingleFontFamily::Generic(atom!("serif")), &gt; FontFamilyType::eFamily_monospace =&gt; SingleFontFamily::Generic(atom!("monospace")), &gt; FontFamilyType::eFamily_cursive =&gt; SingleFontFamily::Generic(atom!("cursive")), &gt; FontFamilyType::eFamily_fantasy =&gt; SingleFontFamily::Generic(atom!("fantasy")), &gt;- FontFamilyType::eFamily_moz_fixed =&gt; { &gt;- SingleFontFamily::Generic(atom!("-moz-fixed")) &gt;- }, &gt;+ FontFamilyType::eFamily_moz_fixed =&gt; SingleFontFamily::Generic(atom!("-moz-fixed")), &gt; FontFamilyType::eFamily_named =&gt; { &gt; let name = Atom::from(&amp;*family.mName); &gt; SingleFontFamily::FamilyName(FamilyName { &gt; name, &gt; syntax: FamilyNameSyntax::Identifiers, &gt; }) &gt;- }, &gt;+ } &gt; FontFamilyType::eFamily_named_quoted =&gt; SingleFontFamily::FamilyName(FamilyName { &gt; name: (&amp;*family.mName).into(), &gt; syntax: FamilyNameSyntax::Quoted, &gt; }), &gt; _ =&gt; panic!("Found unexpected font FontFamilyType"), &gt; } &gt; } &gt; } &gt;@@ -506,17 +512,17 @@ impl ToCss for SingleFontFamily { &gt; { &gt; // We should treat -moz-fixed as monospace &gt; if name == &amp;atom!("-moz-fixed") { &gt; return dest.write_str("monospace"); &gt; } &gt; } &gt; &gt; write!(dest, "{}", name) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; #[cfg(feature = "servo")] &gt; #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq)] &gt; /// A list of SingleFontFamily &gt; pub struct FontFamilyList(Box&lt;[SingleFontFamily]&gt;); &gt;@@ -581,23 +587,23 @@ impl FontFamilyList { &gt; let quoted = matches!(f.syntax, FamilyNameSyntax::Quoted); &gt; unsafe { &gt; bindings::Gecko_nsTArray_FontFamilyName_AppendNamed( &gt; names, &gt; f.name.as_ptr(), &gt; quoted, &gt; ); &gt; } &gt;- }, &gt;+ } &gt; SingleFontFamily::Generic(ref name) =&gt; { &gt; let (family_type, _generic) = SingleFontFamily::generic(name); &gt; unsafe { &gt; bindings::Gecko_nsTArray_FontFamilyName_AppendGeneric(names, family_type); &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; FontFamilyList(unsafe { RefPtr::from_addrefed(fontlist) }) &gt; } &gt; &gt; #[cfg(feature = "servo")] &gt; /// Return iterator of SingleFontFamily &gt;@@ -784,17 +790,17 @@ impl ToComputedValue for specified::MozScriptMinSize { &gt; fn to_computed_value(&amp;self, cx: &amp;Context) -&gt; MozScriptMinSize { &gt; // this value is used in the computation of font-size, so &gt; // we use the parent size &gt; let base_size = FontBaseSize::InheritedStyle; &gt; match self.0 { &gt; NoCalcLength::FontRelative(value) =&gt; value.to_computed_value(cx, base_size), &gt; NoCalcLength::ServoCharacterWidth(value) =&gt; { &gt; value.to_computed_value(base_size.resolve(cx)) &gt;- }, &gt;+ } &gt; ref l =&gt; l.to_computed_value(cx), &gt; } &gt; } &gt; &gt; fn from_computed_value(other: &amp;MozScriptMinSize) -&gt; Self { &gt; specified::MozScriptMinSize(ToComputedValue::from_computed_value(other)) &gt; } &gt; } &gt;@@ -814,21 +820,21 @@ impl ToComputedValue for specified::MozScriptLevel { &gt; specified::MozScriptLevel::Auto =&gt; { &gt; let parent = cx.builder.get_parent_font().clone__moz_script_level() as i32; &gt; let display = cx.builder.get_parent_font().clone__moz_math_display(); &gt; if display == DisplayValue::Inline { &gt; parent + 1 &gt; } else { &gt; parent &gt; } &gt;- }, &gt;+ } &gt; specified::MozScriptLevel::Relative(rel) =&gt; { &gt; let parent = cx.builder.get_parent_font().clone__moz_script_level(); &gt; parent as i32 + rel &gt;- }, &gt;+ } &gt; specified::MozScriptLevel::MozAbsolute(abs) =&gt; abs, &gt; }; &gt; cmp::min(int, i8::MAX as i32) as i8 &gt; } &gt; &gt; fn from_computed_value(other: &amp;i8) -&gt; Self { &gt; specified::MozScriptLevel::MozAbsolute(*other as i32) &gt; } &gt;@@ -846,19 +852,20 @@ impl ToAnimatedValue for FontStyleAngle { &gt; #[inline] &gt; fn to_animated_value(self) -&gt; Self::AnimatedValue { &gt; self.0 &gt; } &gt; &gt; #[inline] &gt; fn from_animated_value(animated: Self::AnimatedValue) -&gt; Self { &gt; FontStyleAngle(Angle::Deg( &gt;- animated.degrees() &gt;+ animated &gt;+ .degrees() &gt; .min(specified::FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES) &gt;- .max(specified::FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES) &gt;+ .max(specified::FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES), &gt; )) &gt; } &gt; } &gt; &gt; impl Hash for FontStyleAngle { &gt; fn hash&lt;H: Hasher&gt;(&amp;self, hasher: &amp;mut H) { &gt; hasher.write_u64((self.0.degrees() * 10000.).trunc() as u64); &gt; } &gt;@@ -877,20 +884,21 @@ impl FontStyle { &gt; generics::FontStyle::Normal &gt; } &gt; &gt; /// The default angle for font-style: oblique. This is 20deg per spec: &gt; /// &gt; /// https://drafts.csswg.org/css-fonts-4/#valdef-font-style-oblique-angle &gt; #[inline] &gt; pub fn default_angle() -&gt; FontStyleAngle { &gt;- FontStyleAngle(Angle::Deg(specified::DEFAULT_FONT_STYLE_OBLIQUE_ANGLE_DEGREES)) &gt;+ FontStyleAngle(Angle::Deg( &gt;+ specified::DEFAULT_FONT_STYLE_OBLIQUE_ANGLE_DEGREES, &gt;+ )) &gt; } &gt; &gt;- &gt; /// Get the font style from Gecko's nsFont struct. &gt; #[cfg(feature = "gecko")] &gt; pub fn from_gecko(style: structs::FontSlantStyle) -&gt; Self { &gt; let mut angle = 0.; &gt; let mut italic = false; &gt; let mut normal = false; &gt; unsafe { &gt; bindings::Gecko_FontSlantStyle_Get(style, &amp;mut normal, &amp;mut italic, &amp;mut angle); &gt;diff --git a/servo/components/style/values/computed/image.rs b/servo/components/style/values/computed/image.rs &gt;index 91e55c399101..0f80b1f32f97 100644 &gt;--- a/servo/components/style/values/computed/image.rs &gt;+++ b/servo/components/style/values/computed/image.rs &gt;@@ -5,26 +5,26 @@ &gt; //! CSS handling for the computed value of &gt; //! [`image`][image]s &gt; //! &gt; //! [image]: https://drafts.csswg.org/css-images/#image-values &gt; &gt; use std::f32::consts::PI; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ToCss}; &gt;-use values::{Either, None_}; &gt;-use values::computed::{Angle, Color, Context}; &gt;-use values::computed::{Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue}; &gt;-#[cfg(feature = "gecko")] &gt;-use values::computed::Percentage; &gt; use values::computed::position::Position; &gt; use values::computed::url::ComputedImageUrl; &gt;+#[cfg(feature = "gecko")] &gt;+use values::computed::Percentage; &gt;+use values::computed::{Angle, Color, Context}; &gt;+use values::computed::{Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue}; &gt; use values::generics::image::{self as generic, CompatMode}; &gt; use values::specified::image::LineDirection as SpecifiedLineDirection; &gt; use values::specified::position::{X, Y}; &gt;+use values::{Either, None_}; &gt; &gt; /// A computed image layer. &gt; pub type ImageLayer = Either&lt;None_, Image&gt;; &gt; &gt; /// Computed values for an image according to CSS-IMAGES. &gt; /// &lt;https://drafts.csswg.org/css-images/#image-values&gt; &gt; pub type Image = generic::Image&lt;Gradient, MozImageRect, ComputedImageUrl&gt;; &gt; &gt;@@ -77,97 +77,97 @@ impl generic::LineDirection for LineDirection { &gt; Some(Position { &gt; horizontal: LengthOrPercentage::Percentage(Percentage(x)), &gt; vertical: LengthOrPercentage::Percentage(Percentage(y)), &gt; }), &gt; None, &gt; ) =&gt; { &gt; // `50% 0%` is the default value for line direction. &gt; x == 0.5 &amp;&amp; y == 0.0 &gt;- }, &gt;+ } &gt; _ =&gt; false, &gt; } &gt; } &gt; &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;, compat_mode: CompatMode) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; match *self { &gt; LineDirection::Angle(ref angle) =&gt; angle.to_css(dest), &gt; LineDirection::Horizontal(x) =&gt; { &gt; if compat_mode == CompatMode::Modern { &gt; dest.write_str("to ")?; &gt; } &gt; x.to_css(dest) &gt;- }, &gt;+ } &gt; LineDirection::Vertical(y) =&gt; { &gt; if compat_mode == CompatMode::Modern { &gt; dest.write_str("to ")?; &gt; } &gt; y.to_css(dest) &gt;- }, &gt;+ } &gt; LineDirection::Corner(x, y) =&gt; { &gt; if compat_mode == CompatMode::Modern { &gt; dest.write_str("to ")?; &gt; } &gt; x.to_css(dest)?; &gt; dest.write_str(" ")?; &gt; y.to_css(dest) &gt;- }, &gt;+ } &gt; #[cfg(feature = "gecko")] &gt; LineDirection::MozPosition(position, angle) =&gt; { &gt; let mut need_space = false; &gt; if let Some(position) = position { &gt; position.to_css(dest)?; &gt; need_space = true; &gt; } &gt; if let Some(angle) = angle { &gt; if need_space { &gt; dest.write_str(" ")?; &gt; } &gt; angle.to_css(dest)?; &gt; } &gt; Ok(()) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl ToComputedValue for SpecifiedLineDirection { &gt; type ComputedValue = LineDirection; &gt; &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Self::ComputedValue { &gt; match *self { &gt; SpecifiedLineDirection::Angle(ref angle) =&gt; { &gt; LineDirection::Angle(angle.to_computed_value(context)) &gt;- }, &gt;+ } &gt; SpecifiedLineDirection::Horizontal(x) =&gt; LineDirection::Horizontal(x), &gt; SpecifiedLineDirection::Vertical(y) =&gt; LineDirection::Vertical(y), &gt; SpecifiedLineDirection::Corner(x, y) =&gt; LineDirection::Corner(x, y), &gt; #[cfg(feature = "gecko")] &gt; SpecifiedLineDirection::MozPosition(ref position, ref angle) =&gt; { &gt; LineDirection::MozPosition( &gt; position.to_computed_value(context), &gt; angle.to_computed_value(context), &gt; ) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; match *computed { &gt; LineDirection::Angle(ref angle) =&gt; { &gt; SpecifiedLineDirection::Angle(ToComputedValue::from_computed_value(angle)) &gt;- }, &gt;+ } &gt; LineDirection::Horizontal(x) =&gt; SpecifiedLineDirection::Horizontal(x), &gt; LineDirection::Vertical(y) =&gt; SpecifiedLineDirection::Vertical(y), &gt; LineDirection::Corner(x, y) =&gt; SpecifiedLineDirection::Corner(x, y), &gt; #[cfg(feature = "gecko")] &gt; LineDirection::MozPosition(ref position, ref angle) =&gt; { &gt; SpecifiedLineDirection::MozPosition( &gt; ToComputedValue::from_computed_value(position), &gt; ToComputedValue::from_computed_value(angle), &gt; ) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/style/values/computed/length.rs b/servo/components/style/values/computed/length.rs &gt;index 0ff99a08a3fb..e4ffa084b7ad 100644 &gt;--- a/servo/components/style/values/computed/length.rs &gt;+++ b/servo/components/style/values/computed/length.rs &gt;@@ -1,50 +1,50 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! `&lt;length&gt;` computed values, and related ones. &gt; &gt;+use super::{Context, Number, Percentage, ToComputedValue}; &gt; use app_units::Au; &gt; use logical_geometry::WritingMode; &gt; use ordered_float::NotNan; &gt; use properties::LonghandId; &gt; use std::fmt::{self, Write}; &gt; use std::ops::{Add, Neg}; &gt;-use style_traits::{CssWriter, ToCss}; &gt; use style_traits::values::specified::AllowedNumericType; &gt;-use super::{Context, Number, Percentage, ToComputedValue}; &gt;-use values::{specified, Auto, CSSFloat, Either, Normal}; &gt;+use style_traits::{CssWriter, ToCss}; &gt; use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; &gt; use values::distance::{ComputeSquaredDistance, SquaredDistance}; &gt; use values::generics::NonNegative; &gt;-use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength}; &gt; use values::specified::length::ViewportPercentageLength; &gt;+use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength}; &gt;+use values::{specified, Auto, CSSFloat, Either, Normal}; &gt; &gt; pub use super::image::Image; &gt; pub use values::specified::url::UrlOrNone; &gt; pub use values::specified::{Angle, BorderStyle, Time}; &gt; &gt; impl ToComputedValue for specified::NoCalcLength { &gt; type ComputedValue = CSSPixelLength; &gt; &gt; #[inline] &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Self::ComputedValue { &gt; match *self { &gt; specified::NoCalcLength::Absolute(length) =&gt; length.to_computed_value(context), &gt; specified::NoCalcLength::FontRelative(length) =&gt; { &gt; length.to_computed_value(context, FontBaseSize::CurrentStyle) &gt;- }, &gt;+ } &gt; specified::NoCalcLength::ViewportPercentage(length) =&gt; { &gt; length.to_computed_value(context.viewport_size_for_viewport_unit_resolution()) &gt;- }, &gt;+ } &gt; specified::NoCalcLength::ServoCharacterWidth(length) =&gt; { &gt; length.to_computed_value(context.style().get_font().clone_font_size().size()) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; specified::NoCalcLength::Absolute(AbsoluteLength::Px(computed.px())) &gt; } &gt; } &gt;@@ -75,19 +75,21 @@ pub struct CalcLengthOrPercentage { &gt; pub percentage: Option&lt;Percentage&gt;, &gt; } &gt; &gt; impl ComputeSquaredDistance for CalcLengthOrPercentage { &gt; #[inline] &gt; fn compute_squared_distance(&amp;self, other: &amp;Self) -&gt; Result&lt;SquaredDistance, ()&gt; { &gt; // FIXME(nox): This looks incorrect to me, to add a distance between lengths &gt; // with a distance between percentages. &gt;- Ok(self.unclamped_length() &gt;- .compute_squared_distance(&amp;other.unclamped_length())? + &gt;- self.percentage() &gt;+ Ok(self &gt;+ .unclamped_length() &gt;+ .compute_squared_distance(&amp;other.unclamped_length())? &gt;+ + self &gt;+ .percentage() &gt; .compute_squared_distance(&amp;other.percentage())?) &gt; } &gt; } &gt; &gt; impl CalcLengthOrPercentage { &gt; /// Returns a new `CalcLengthOrPercentage`. &gt; #[inline] &gt; pub fn new(length: Length, percentage: Option&lt;Percentage&gt;) -&gt; Self { &gt;@@ -144,54 +146,54 @@ impl CalcLengthOrPercentage { &gt; /// If there are special rules for computing percentages in a value (e.g. &gt; /// the height property), they apply whenever a calc() expression contains &gt; /// percentages. &gt; pub fn to_pixel_length(&amp;self, container_len: Option&lt;Au&gt;) -&gt; Option&lt;Length&gt; { &gt; match (container_len, self.percentage) { &gt; (Some(len), Some(percent)) =&gt; { &gt; let pixel = self.length.px() + len.scale_by(percent.0).to_f32_px(); &gt; Some(Length::new(self.clamping_mode.clamp(pixel))) &gt;- }, &gt;+ } &gt; (_, None) =&gt; Some(self.length()), &gt; _ =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; impl From&lt;LengthOrPercentage&gt; for CalcLengthOrPercentage { &gt; fn from(len: LengthOrPercentage) -&gt; CalcLengthOrPercentage { &gt; match len { &gt; LengthOrPercentage::Percentage(this) =&gt; { &gt; CalcLengthOrPercentage::new(Length::new(0.), Some(this)) &gt;- }, &gt;+ } &gt; LengthOrPercentage::Length(this) =&gt; CalcLengthOrPercentage::new(this, None), &gt; LengthOrPercentage::Calc(this) =&gt; this, &gt; } &gt; } &gt; } &gt; &gt; impl From&lt;LengthOrPercentageOrAuto&gt; for Option&lt;CalcLengthOrPercentage&gt; { &gt; fn from(len: LengthOrPercentageOrAuto) -&gt; Option&lt;CalcLengthOrPercentage&gt; { &gt; match len { &gt; LengthOrPercentageOrAuto::Percentage(this) =&gt; { &gt; Some(CalcLengthOrPercentage::new(Length::new(0.), Some(this))) &gt;- }, &gt;+ } &gt; LengthOrPercentageOrAuto::Length(this) =&gt; Some(CalcLengthOrPercentage::new(this, None)), &gt; LengthOrPercentageOrAuto::Calc(this) =&gt; Some(this), &gt; LengthOrPercentageOrAuto::Auto =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; impl From&lt;LengthOrPercentageOrNone&gt; for Option&lt;CalcLengthOrPercentage&gt; { &gt; fn from(len: LengthOrPercentageOrNone) -&gt; Option&lt;CalcLengthOrPercentage&gt; { &gt; match len { &gt; LengthOrPercentageOrNone::Percentage(this) =&gt; { &gt; Some(CalcLengthOrPercentage::new(Length::new(0.), Some(this))) &gt;- }, &gt;+ } &gt; LengthOrPercentageOrNone::Length(this) =&gt; Some(CalcLengthOrPercentage::new(this, None)), &gt; LengthOrPercentageOrNone::Calc(this) =&gt; Some(this), &gt; LengthOrPercentageOrNone::None =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; impl ToCss for CalcLengthOrPercentage { &gt;@@ -280,29 +282,35 @@ impl specified::CalcLengthOrPercentage { &gt; |abs| context.maybe_zoom_text(abs.into()).0, &gt; base_size, &gt; ) &gt; } &gt; &gt; /// Compute the value into pixel length as CSSFloat without context, &gt; /// so it returns Err(()) if there is any non-absolute unit. &gt; pub fn to_computed_pixel_length_without_context(&amp;self) -&gt; Result&lt;CSSFloat, ()&gt; { &gt;- if self.vw.is_some() || self.vh.is_some() || self.vmin.is_some() || self.vmax.is_some() || &gt;- self.em.is_some() || self.ex.is_some() || self.ch.is_some() || &gt;- self.rem.is_some() || self.percentage.is_some() &gt;+ if self.vw.is_some() &gt;+ || self.vh.is_some() &gt;+ || self.vmin.is_some() &gt;+ || self.vmax.is_some() &gt;+ || self.em.is_some() &gt;+ || self.ex.is_some() &gt;+ || self.ch.is_some() &gt;+ || self.rem.is_some() &gt;+ || self.percentage.is_some() &gt; { &gt; return Err(()); &gt; } &gt; &gt; match self.absolute { &gt; Some(abs) =&gt; Ok(abs.to_px()), &gt; None =&gt; { &gt; debug_assert!(false, "Someone forgot to handle an unit here: {:?}", self); &gt; Err(()) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl ToComputedValue for specified::CalcLengthOrPercentage { &gt; type ComputedValue = CalcLengthOrPercentage; &gt; &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; CalcLengthOrPercentage { &gt;@@ -319,18 +327,27 @@ impl ToComputedValue for specified::CalcLengthOrPercentage { &gt; ..Default::default() &gt; } &gt; } &gt; } &gt; &gt; #[allow(missing_docs)] &gt; #[animate(fallback = "Self::animate_fallback")] &gt; #[css(derive_debug)] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, &gt;- ToAnimatedValue, ToAnimatedZero, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToCss, &gt;+)] &gt; #[distance(fallback = "Self::compute_squared_distance_fallback")] &gt; pub enum LengthOrPercentage { &gt; Length(Length), &gt; Percentage(Percentage), &gt; Calc(CalcLengthOrPercentage), &gt; } &gt; &gt; impl LengthOrPercentage { &gt;@@ -410,60 +427,60 @@ impl LengthOrPercentage { &gt; &gt; /// Returns the used value as CSSPixelLength. &gt; pub fn to_pixel_length(&amp;self, containing_length: Au) -&gt; Length { &gt; match *self { &gt; LengthOrPercentage::Length(length) =&gt; length, &gt; LengthOrPercentage::Percentage(p) =&gt; containing_length.scale_by(p.0).into(), &gt; LengthOrPercentage::Calc(ref calc) =&gt; { &gt; calc.to_pixel_length(Some(containing_length)).unwrap() &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Returns the clamped non-negative values. &gt; #[inline] &gt; pub fn clamp_to_non_negative(self) -&gt; Self { &gt; match self { &gt; LengthOrPercentage::Length(length) =&gt; { &gt; LengthOrPercentage::Length(length.clamp_to_non_negative()) &gt;- }, &gt;+ } &gt; LengthOrPercentage::Percentage(percentage) =&gt; { &gt; LengthOrPercentage::Percentage(percentage.clamp_to_non_negative()) &gt;- }, &gt;+ } &gt; _ =&gt; self, &gt; } &gt; } &gt; } &gt; &gt; impl ToComputedValue for specified::LengthOrPercentage { &gt; type ComputedValue = LengthOrPercentage; &gt; &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; LengthOrPercentage { &gt; match *self { &gt; specified::LengthOrPercentage::Length(ref value) =&gt; { &gt; LengthOrPercentage::Length(value.to_computed_value(context)) &gt;- }, &gt;+ } &gt; specified::LengthOrPercentage::Percentage(value) =&gt; { &gt; LengthOrPercentage::Percentage(value) &gt;- }, &gt;+ } &gt; specified::LengthOrPercentage::Calc(ref calc) =&gt; { &gt; LengthOrPercentage::Calc((**calc).to_computed_value(context)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; fn from_computed_value(computed: &amp;LengthOrPercentage) -&gt; Self { &gt; match *computed { &gt; LengthOrPercentage::Length(value) =&gt; { &gt; specified::LengthOrPercentage::Length(ToComputedValue::from_computed_value(&amp;value)) &gt;- }, &gt;+ } &gt; LengthOrPercentage::Percentage(value) =&gt; { &gt; specified::LengthOrPercentage::Percentage(value) &gt;- }, &gt;+ } &gt; LengthOrPercentage::Calc(ref calc) =&gt; specified::LengthOrPercentage::Calc(Box::new( &gt; ToComputedValue::from_computed_value(calc), &gt; )), &gt; } &gt; } &gt; } &gt; &gt; #[allow(missing_docs)] &gt;@@ -478,21 +495,19 @@ pub enum LengthOrPercentageOrAuto { &gt; Calc(CalcLengthOrPercentage), &gt; } &gt; &gt; impl LengthOrPercentageOrAuto { &gt; /// &lt;https://drafts.csswg.org/css-transitions/#animtype-lpcalc&gt; &gt; fn animate_fallback(&amp;self, other: &amp;Self, procedure: Procedure) -&gt; Result&lt;Self, ()&gt; { &gt; let this = &lt;Option&lt;CalcLengthOrPercentage&gt;&gt;::from(*self); &gt; let other = &lt;Option&lt;CalcLengthOrPercentage&gt;&gt;::from(*other); &gt;- Ok(LengthOrPercentageOrAuto::Calc(this.animate( &gt;- &amp;other, &gt;- procedure, &gt;- )? &gt;- .ok_or(())?)) &gt;+ Ok(LengthOrPercentageOrAuto::Calc( &gt;+ this.animate(&amp;other, procedure)?.ok_or(())?, &gt;+ )) &gt; } &gt; &gt; #[inline] &gt; fn compute_squared_distance_fallback(&amp;self, other: &amp;Self) -&gt; Result&lt;SquaredDistance, ()&gt; { &gt; &lt;Option&lt;CalcLengthOrPercentage&gt;&gt;::compute_squared_distance( &gt; &amp;(*self).into(), &gt; &amp;(*other).into(), &gt; ) &gt;@@ -551,37 +566,37 @@ impl LengthOrPercentageOrAuto { &gt; impl ToComputedValue for specified::LengthOrPercentageOrAuto { &gt; type ComputedValue = LengthOrPercentageOrAuto; &gt; &gt; #[inline] &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; LengthOrPercentageOrAuto { &gt; match *self { &gt; specified::LengthOrPercentageOrAuto::Length(ref value) =&gt; { &gt; LengthOrPercentageOrAuto::Length(value.to_computed_value(context)) &gt;- }, &gt;+ } &gt; specified::LengthOrPercentageOrAuto::Percentage(value) =&gt; { &gt; LengthOrPercentageOrAuto::Percentage(value) &gt;- }, &gt;+ } &gt; specified::LengthOrPercentageOrAuto::Auto =&gt; LengthOrPercentageOrAuto::Auto, &gt; specified::LengthOrPercentageOrAuto::Calc(ref calc) =&gt; { &gt; LengthOrPercentageOrAuto::Calc((**calc).to_computed_value(context)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;LengthOrPercentageOrAuto) -&gt; Self { &gt; match *computed { &gt; LengthOrPercentageOrAuto::Auto =&gt; specified::LengthOrPercentageOrAuto::Auto, &gt; LengthOrPercentageOrAuto::Length(value) =&gt; specified::LengthOrPercentageOrAuto::Length( &gt; ToComputedValue::from_computed_value(&amp;value), &gt; ), &gt; LengthOrPercentageOrAuto::Percentage(value) =&gt; { &gt; specified::LengthOrPercentageOrAuto::Percentage(value) &gt;- }, &gt;+ } &gt; LengthOrPercentageOrAuto::Calc(calc) =&gt; specified::LengthOrPercentageOrAuto::Calc( &gt; Box::new(ToComputedValue::from_computed_value(&amp;calc)), &gt; ), &gt; } &gt; } &gt; } &gt; &gt; #[allow(missing_docs)] &gt;@@ -597,21 +612,19 @@ pub enum LengthOrPercentageOrNone { &gt; None, &gt; } &gt; &gt; impl LengthOrPercentageOrNone { &gt; /// &lt;https://drafts.csswg.org/css-transitions/#animtype-lpcalc&gt; &gt; fn animate_fallback(&amp;self, other: &amp;Self, procedure: Procedure) -&gt; Result&lt;Self, ()&gt; { &gt; let this = &lt;Option&lt;CalcLengthOrPercentage&gt;&gt;::from(*self); &gt; let other = &lt;Option&lt;CalcLengthOrPercentage&gt;&gt;::from(*other); &gt;- Ok(LengthOrPercentageOrNone::Calc(this.animate( &gt;- &amp;other, &gt;- procedure, &gt;- )? &gt;- .ok_or(())?)) &gt;+ Ok(LengthOrPercentageOrNone::Calc( &gt;+ this.animate(&amp;other, procedure)?.ok_or(())?, &gt;+ )) &gt; } &gt; &gt; fn compute_squared_distance_fallback(&amp;self, other: &amp;Self) -&gt; Result&lt;SquaredDistance, ()&gt; { &gt; &lt;Option&lt;CalcLengthOrPercentage&gt;&gt;::compute_squared_distance( &gt; &amp;(*self).into(), &gt; &amp;(*other).into(), &gt; ) &gt; } &gt;@@ -620,51 +633,51 @@ impl LengthOrPercentageOrNone { &gt; impl LengthOrPercentageOrNone { &gt; /// Returns the used value. &gt; pub fn to_used_value(&amp;self, containing_length: Au) -&gt; Option&lt;Au&gt; { &gt; match *self { &gt; LengthOrPercentageOrNone::None =&gt; None, &gt; LengthOrPercentageOrNone::Length(length) =&gt; Some(Au::from(length)), &gt; LengthOrPercentageOrNone::Percentage(percent) =&gt; { &gt; Some(containing_length.scale_by(percent.0)) &gt;- }, &gt;+ } &gt; LengthOrPercentageOrNone::Calc(ref calc) =&gt; calc.to_used_value(Some(containing_length)), &gt; } &gt; } &gt; } &gt; &gt; impl ToComputedValue for specified::LengthOrPercentageOrNone { &gt; type ComputedValue = LengthOrPercentageOrNone; &gt; &gt; #[inline] &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; LengthOrPercentageOrNone { &gt; match *self { &gt; specified::LengthOrPercentageOrNone::Length(ref value) =&gt; { &gt; LengthOrPercentageOrNone::Length(value.to_computed_value(context)) &gt;- }, &gt;+ } &gt; specified::LengthOrPercentageOrNone::Percentage(value) =&gt; { &gt; LengthOrPercentageOrNone::Percentage(value) &gt;- }, &gt;+ } &gt; specified::LengthOrPercentageOrNone::Calc(ref calc) =&gt; { &gt; LengthOrPercentageOrNone::Calc((**calc).to_computed_value(context)) &gt;- }, &gt;+ } &gt; specified::LengthOrPercentageOrNone::None =&gt; LengthOrPercentageOrNone::None, &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;LengthOrPercentageOrNone) -&gt; Self { &gt; match *computed { &gt; LengthOrPercentageOrNone::None =&gt; specified::LengthOrPercentageOrNone::None, &gt; LengthOrPercentageOrNone::Length(value) =&gt; specified::LengthOrPercentageOrNone::Length( &gt; ToComputedValue::from_computed_value(&amp;value), &gt; ), &gt; LengthOrPercentageOrNone::Percentage(value) =&gt; { &gt; specified::LengthOrPercentageOrNone::Percentage(value) &gt;- }, &gt;+ } &gt; LengthOrPercentageOrNone::Calc(calc) =&gt; specified::LengthOrPercentageOrNone::Calc( &gt; Box::new(ToComputedValue::from_computed_value(&amp;calc)), &gt; ), &gt; } &gt; } &gt; } &gt; &gt; /// A wrapper of LengthOrPercentage, whose value must be &gt;= 0. &gt;@@ -722,18 +735,28 @@ impl NonNegativeLengthOrPercentage { &gt; #[inline] &gt; pub fn to_used_value(&amp;self, containing_length: Au) -&gt; Au { &gt; self.0.to_used_value(containing_length) &gt; } &gt; } &gt; &gt; /// The computed `&lt;length&gt;` value. &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, &gt;- PartialOrd, ToAnimatedValue, ToAnimatedZero)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ PartialOrd, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+)] &gt; pub struct CSSPixelLength(CSSFloat); &gt; &gt; impl CSSPixelLength { &gt; /// Return a new CSSPixelLength. &gt; #[inline] &gt; pub fn new(px: CSSFloat) -&gt; Self { &gt; CSSPixelLength(px) &gt; } &gt;@@ -911,18 +934,17 @@ pub type NonNegativeLengthOrNormal = Either&lt;NonNegativeLength, Normal&gt;; &gt; &gt; /// Either a computed NonNegativeLengthOrPercentage or the `normal` keyword. &gt; pub type NonNegativeLengthOrPercentageOrNormal = Either&lt;NonNegativeLengthOrPercentage, Normal&gt;; &gt; &gt; /// A type for possible values for min- and max- flavors of width, height, &gt; /// block-size, and inline-size. &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToCss)] &gt;+#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)] &gt; pub enum ExtremumLength { &gt; MozMaxContent, &gt; MozMinContent, &gt; MozFitContent, &gt; MozAvailable, &gt; } &gt; &gt; impl ExtremumLength { &gt;@@ -931,34 +953,34 @@ impl ExtremumLength { &gt; /// &gt; /// TODO: After these values are supported for both axes (and maybe &gt; /// unprefixed, see bug 1322780) all this complexity can go away, and &gt; /// everything can be derived (no need for uncacheable stuff). &gt; fn valid_for(&amp;self, wm: WritingMode, longhand: LonghandId) -&gt; bool { &gt; // We only make sense on the inline axis. &gt; match longhand { &gt; // FIXME(emilio): The flex-basis thing is not quite clear... &gt;- LonghandId::FlexBasis | &gt;- LonghandId::MinWidth | &gt;- LonghandId::MaxWidth | &gt;- LonghandId::Width =&gt; !wm.is_vertical(), &gt;+ LonghandId::FlexBasis &gt;+ | LonghandId::MinWidth &gt;+ | LonghandId::MaxWidth &gt;+ | LonghandId::Width =&gt; !wm.is_vertical(), &gt; &gt; LonghandId::MinHeight | LonghandId::MaxHeight | LonghandId::Height =&gt; wm.is_vertical(), &gt; &gt; LonghandId::MinInlineSize | LonghandId::MaxInlineSize | LonghandId::InlineSize =&gt; true, &gt; // The block-* properties are rejected at parse-time, so they're &gt; // unexpected here. &gt; _ =&gt; { &gt; debug_assert!( &gt; false, &gt; "Unexpected property using ExtremumLength: {:?}", &gt; longhand, &gt; ); &gt; false &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// A value suitable for a `min-width`, `min-height`, `width` or `height` &gt; /// property. &gt; /// &gt; /// See values/specified/length.rs for more details. &gt;@@ -986,42 +1008,42 @@ impl ToComputedValue for specified::MozLength { &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; MozLength { &gt; debug_assert!( &gt; context.for_non_inherited_property.is_some(), &gt; "Someone added a MozLength to an inherited property? Evil!" &gt; ); &gt; match *self { &gt; specified::MozLength::LengthOrPercentageOrAuto(ref lopoa) =&gt; { &gt; MozLength::LengthOrPercentageOrAuto(lopoa.to_computed_value(context)) &gt;- }, &gt;+ } &gt; specified::MozLength::ExtremumLength(ext) =&gt; { &gt; context &gt; .rule_cache_conditions &gt; .borrow_mut() &gt; .set_writing_mode_dependency(context.builder.writing_mode); &gt; if !ext.valid_for( &gt; context.builder.writing_mode, &gt; context.for_non_inherited_property.unwrap(), &gt; ) { &gt; MozLength::auto() &gt; } else { &gt; MozLength::ExtremumLength(ext) &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;MozLength) -&gt; Self { &gt; match *computed { &gt; MozLength::LengthOrPercentageOrAuto(ref lopoa) =&gt; { &gt; specified::MozLength::LengthOrPercentageOrAuto( &gt; specified::LengthOrPercentageOrAuto::from_computed_value(lopoa), &gt; ) &gt;- }, &gt;+ } &gt; MozLength::ExtremumLength(ext) =&gt; specified::MozLength::ExtremumLength(ext), &gt; } &gt; } &gt; } &gt; &gt; /// A value suitable for a `max-width` or `max-height` property. &gt; /// See values/specified/length.rs for more details. &gt; #[allow(missing_docs)] &gt;@@ -1048,38 +1070,38 @@ impl ToComputedValue for specified::MaxLength { &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; MaxLength { &gt; debug_assert!( &gt; context.for_non_inherited_property.is_some(), &gt; "Someone added a MaxLength to an inherited property? Evil!" &gt; ); &gt; match *self { &gt; specified::MaxLength::LengthOrPercentageOrNone(ref lopon) =&gt; { &gt; MaxLength::LengthOrPercentageOrNone(lopon.to_computed_value(context)) &gt;- }, &gt;+ } &gt; specified::MaxLength::ExtremumLength(ext) =&gt; { &gt; context &gt; .rule_cache_conditions &gt; .borrow_mut() &gt; .set_writing_mode_dependency(context.builder.writing_mode); &gt; if !ext.valid_for( &gt; context.builder.writing_mode, &gt; context.for_non_inherited_property.unwrap(), &gt; ) { &gt; MaxLength::none() &gt; } else { &gt; MaxLength::ExtremumLength(ext) &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;MaxLength) -&gt; Self { &gt; match *computed { &gt; MaxLength::LengthOrPercentageOrNone(ref lopon) =&gt; { &gt; specified::MaxLength::LengthOrPercentageOrNone( &gt; specified::LengthOrPercentageOrNone::from_computed_value(&amp;lopon), &gt; ) &gt;- }, &gt;+ } &gt; MaxLength::ExtremumLength(ref ext) =&gt; specified::MaxLength::ExtremumLength(ext.clone()), &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/style/values/computed/list.rs b/servo/components/style/values/computed/list.rs &gt;index 0924cfc96fae..d70b1e77e7be 100644 &gt;--- a/servo/components/style/values/computed/list.rs &gt;+++ b/servo/components/style/values/computed/list.rs &gt;@@ -1,17 +1,17 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! `list` computed values. &gt; &gt;-pub use values::specified::list::Quotes; &gt; #[cfg(feature = "gecko")] &gt; pub use values::specified::list::ListStyleType; &gt;+pub use values::specified::list::Quotes; &gt; &gt; impl Quotes { &gt; /// Initial value for `quotes`. &gt; /// &gt; /// FIXME(emilio): This should ideally not allocate. &gt; #[inline] &gt; pub fn get_initial_value() -&gt; Quotes { &gt; Quotes( &gt;diff --git a/servo/components/style/values/computed/mod.rs b/servo/components/style/values/computed/mod.rs &gt;index 9a6b5fd76b58..95e6e264be96 100644 &gt;--- a/servo/components/style/values/computed/mod.rs &gt;+++ b/servo/components/style/values/computed/mod.rs &gt;@@ -1,90 +1,100 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed values. &gt; &gt;-use Atom; &gt;-#[cfg(feature = "servo")] &gt;-use Prefix; &gt;+use super::animated::ToAnimatedValue; &gt;+use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; &gt;+use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth}; &gt;+use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize}; &gt;+use super::generics::{GreaterThanOrEqualToOne, NonNegative}; &gt;+use super::specified; &gt;+use super::{CSSFloat, CSSInteger}; &gt; use context::QuirksMode; &gt; use euclid::Size2D; &gt; use font_metrics::{get_metrics_provider_for_product, FontMetricsProvider}; &gt; use media_queries::Device; &gt; #[cfg(feature = "gecko")] &gt; use properties; &gt; use properties::{ComputedValues, LonghandId, StyleBuilder}; &gt; use rule_cache::RuleCacheConditions; &gt; use std::cell::RefCell; &gt; use std::cmp; &gt; use std::f32; &gt; use std::fmt::{self, Write}; &gt;-use style_traits::{CssWriter, ToCss}; &gt; use style_traits::cursor::CursorKind; &gt;-use super::{CSSFloat, CSSInteger}; &gt;-use super::animated::ToAnimatedValue; &gt;-use super::generics::{GreaterThanOrEqualToOne, NonNegative}; &gt;-use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth}; &gt;-use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize}; &gt;-use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; &gt;-use super::specified; &gt;+use style_traits::{CssWriter, ToCss}; &gt;+use Atom; &gt;+#[cfg(feature = "servo")] &gt;+use Prefix; &gt; &gt;-pub use app_units::Au; &gt; #[cfg(feature = "gecko")] &gt; pub use self::align::{AlignContent, AlignItems, JustifyContent, JustifyItems, SelfAlignment}; &gt; #[cfg(feature = "gecko")] &gt; pub use self::align::{AlignSelf, JustifySelf}; &gt; pub use self::angle::Angle; &gt; pub use self::background::{BackgroundRepeat, BackgroundSize}; &gt;-pub use self::border::{BorderImageRepeat, BorderImageSideWidth, BorderImageSlice, BorderImageWidth}; &gt; pub use self::border::{BorderCornerRadius, BorderRadius, BorderSpacing}; &gt;-pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis, FontVariantAlternates, FontWeight}; &gt;-pub use self::font::{FontFamily, FontLanguageOverride, FontStyle, FontVariantEastAsian, FontVariationSettings}; &gt;-pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric}; &gt;-pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; &gt;-pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display, TransitionProperty}; &gt;+pub use self::border::{ &gt;+ BorderImageRepeat, BorderImageSideWidth, BorderImageSlice, BorderImageWidth, &gt;+}; &gt;+pub use self::box_::{ &gt;+ AnimationIterationCount, AnimationName, Contain, Display, TransitionProperty, &gt;+}; &gt; pub use self::box_::{Appearance, Clear, Float}; &gt; pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize}; &gt; pub use self::box_::{ScrollSnapType, TouchAction, VerticalAlign, WillChange}; &gt; pub use self::color::{Color, ColorPropertyValue, RGBAColor}; &gt; pub use self::column::ColumnCount; &gt; pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset}; &gt; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; &gt; pub use self::flex::FlexBasis; &gt;-pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect}; &gt;+pub use self::font::{ &gt;+ FontFamily, FontLanguageOverride, FontStyle, FontVariantEastAsian, FontVariationSettings, &gt;+}; &gt;+pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric}; &gt;+pub use self::font::{ &gt;+ FontSize, FontSizeAdjust, FontStretch, FontSynthesis, FontVariantAlternates, FontWeight, &gt;+}; &gt;+pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; &gt; #[cfg(feature = "gecko")] &gt; pub use self::gecko::ScrollSnapPoint; &gt;-pub use self::rect::LengthOrNumberRect; &gt;-pub use self::resolution::Resolution; &gt;-pub use super::{Auto, Either, None_}; &gt;-pub use super::specified::{BorderStyle, TextDecorationLine}; &gt;+pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect}; &gt;+pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength}; &gt; pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage}; &gt; pub use self::length::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, MaxLength, MozLength}; &gt;-pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength}; &gt; pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercentageOrAuto}; &gt;-pub use self::list::Quotes; &gt; #[cfg(feature = "gecko")] &gt; pub use self::list::ListStyleType; &gt;+pub use self::list::Quotes; &gt; pub use self::outline::OutlineStyle; &gt;-pub use self::percentage::{Percentage, NonNegativePercentage}; &gt;+pub use self::percentage::{NonNegativePercentage, Percentage}; &gt; pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex}; &gt;+pub use self::rect::LengthOrNumberRect; &gt;+pub use self::resolution::Resolution; &gt;+pub use self::svg::MozContextProperties; &gt; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; &gt; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; &gt;-pub use self::svg::MozContextProperties; &gt; pub use self::table::XSpan; &gt; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize}; &gt;-pub use self::text::{TextAlign, TextEmphasisPosition, TextEmphasisStyle, TextOverflow, WordSpacing}; &gt;+pub use self::text::{ &gt;+ TextAlign, TextEmphasisPosition, TextEmphasisStyle, TextOverflow, WordSpacing, &gt;+}; &gt; pub use self::time::Time; &gt; pub use self::transform::{Rotate, Scale, TimingFunction, Transform, TransformOperation}; &gt; pub use self::transform::{TransformOrigin, TransformStyle, Translate}; &gt;-pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon}; &gt; #[cfg(feature = "gecko")] &gt; pub use self::ui::CursorImage; &gt;+pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon}; &gt;+pub use super::specified::{BorderStyle, TextDecorationLine}; &gt;+pub use super::{Auto, Either, None_}; &gt;+pub use app_units::Au; &gt; &gt; #[cfg(feature = "gecko")] &gt; pub mod align; &gt; pub mod angle; &gt; pub mod background; &gt; pub mod basic_shape; &gt; pub mod border; &gt; #[path = "box.rs"] &gt;@@ -521,33 +531,33 @@ pub enum NumberOrPercentage { &gt; impl ToComputedValue for specified::NumberOrPercentage { &gt; type ComputedValue = NumberOrPercentage; &gt; &gt; #[inline] &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; NumberOrPercentage { &gt; match *self { &gt; specified::NumberOrPercentage::Percentage(percentage) =&gt; { &gt; NumberOrPercentage::Percentage(percentage.to_computed_value(context)) &gt;- }, &gt;+ } &gt; specified::NumberOrPercentage::Number(number) =&gt; { &gt; NumberOrPercentage::Number(number.to_computed_value(context)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; #[inline] &gt; fn from_computed_value(computed: &amp;NumberOrPercentage) -&gt; Self { &gt; match *computed { &gt; NumberOrPercentage::Percentage(percentage) =&gt; { &gt; specified::NumberOrPercentage::Percentage(ToComputedValue::from_computed_value( &gt; &amp;percentage, &gt; )) &gt;- }, &gt;+ } &gt; NumberOrPercentage::Number(number) =&gt; { &gt; specified::NumberOrPercentage::Number(ToComputedValue::from_computed_value(&amp;number)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// A type used for opacity. &gt; pub type Opacity = CSSFloat; &gt; &gt; /// A `&lt;integer&gt;` value. &gt;diff --git a/servo/components/style/values/computed/percentage.rs b/servo/components/style/values/computed/percentage.rs &gt;index 718d74335b7f..6e6264c969af 100644 &gt;--- a/servo/components/style/values/computed/percentage.rs &gt;+++ b/servo/components/style/values/computed/percentage.rs &gt;@@ -1,25 +1,37 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed percentages. &gt; &gt; use std::fmt; &gt; use style_traits::{CssWriter, ToCss}; &gt;-use values::{serialize_percentage, CSSFloat}; &gt; use values::animated::ToAnimatedValue; &gt; use values::generics::NonNegative; &gt;+use values::{serialize_percentage, CSSFloat}; &gt; &gt; /// A computed percentage. &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Default, &gt;- MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo, &gt;- ToAnimatedValue, ToAnimatedZero, ToComputedValue)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ Default, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ PartialOrd, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+)] &gt; pub struct Percentage(pub CSSFloat); &gt; &gt; impl Percentage { &gt; /// 0% &gt; #[inline] &gt; pub fn zero() -&gt; Self { &gt; Percentage(0.) &gt; } &gt;diff --git a/servo/components/style/values/computed/resolution.rs b/servo/components/style/values/computed/resolution.rs &gt;index d90bdf4867df..9d743f9cbf3e 100644 &gt;--- a/servo/components/style/values/computed/resolution.rs &gt;+++ b/servo/components/style/values/computed/resolution.rs &gt;@@ -3,19 +3,19 @@ &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Resolution values: &gt; //! &gt; //! https://drafts.csswg.org/css-values/#resolution &gt; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ToCss}; &gt;-use values::CSSFloat; &gt; use values::computed::{Context, ToComputedValue}; &gt; use values::specified; &gt;+use values::CSSFloat; &gt; &gt; /// A computed `&lt;resolution&gt;`. &gt; pub struct Resolution(CSSFloat); &gt; &gt; impl Resolution { &gt; /// Returns this resolution value as dppx. &gt; #[inline] &gt; pub fn dppx(&amp;self) -&gt; CSSFloat { &gt;diff --git a/servo/components/style/values/computed/svg.rs b/servo/components/style/values/computed/svg.rs &gt;index ab9bbd18b4ef..375da2eeeaab 100644 &gt;--- a/servo/components/style/values/computed/svg.rs &gt;+++ b/servo/components/style/values/computed/svg.rs &gt;@@ -1,22 +1,22 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed types for SVG properties. &gt; &gt; use app_units::Au; &gt;-use values::RGBA; &gt;-use values::computed::{LengthOrPercentage, NonNegativeLength}; &gt;-use values::computed::{NonNegativeLengthOrPercentage, NonNegativeNumber, Number}; &gt;-use values::computed::Opacity; &gt; use values::computed::color::Color; &gt; use values::computed::url::ComputedUrl; &gt;+use values::computed::Opacity; &gt;+use values::computed::{LengthOrPercentage, NonNegativeLength}; &gt;+use values::computed::{NonNegativeLengthOrPercentage, NonNegativeNumber, Number}; &gt; use values::generics::svg as generic; &gt;+use values::RGBA; &gt; &gt; pub use values::specified::SVGPaintOrder; &gt; &gt; pub use values::specified::MozContextProperties; &gt; &gt; /// Computed SVG Paint value &gt; pub type SVGPaint = generic::SVGPaint&lt;Color, ComputedUrl&gt;; &gt; /// Computed SVG Paint Kind value &gt;@@ -63,20 +63,20 @@ impl From&lt;Au&gt; for SVGLength { &gt; pub type NonNegativeSvgLengthOrPercentageOrNumber = &gt; generic::SvgLengthOrPercentageOrNumber&lt;NonNegativeLengthOrPercentage, NonNegativeNumber&gt;; &gt; &gt; impl Into&lt;NonNegativeSvgLengthOrPercentageOrNumber&gt; for SvgLengthOrPercentageOrNumber { &gt; fn into(self) -&gt; NonNegativeSvgLengthOrPercentageOrNumber { &gt; match self { &gt; generic::SvgLengthOrPercentageOrNumber::LengthOrPercentage(lop) =&gt; { &gt; generic::SvgLengthOrPercentageOrNumber::LengthOrPercentage(lop.into()) &gt;- }, &gt;+ } &gt; generic::SvgLengthOrPercentageOrNumber::Number(num) =&gt; { &gt; generic::SvgLengthOrPercentageOrNumber::Number(num.into()) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// An non-negative wrapper of SVGLength. &gt; pub type SVGWidth = generic::SVGLength&lt;NonNegativeSvgLengthOrPercentageOrNumber&gt;; &gt; &gt; impl From&lt;NonNegativeLength&gt; for SVGWidth { &gt;diff --git a/servo/components/style/values/computed/text.rs b/servo/components/style/values/computed/text.rs &gt;index b41ecdb7e678..f8443ec607ac 100644 &gt;--- a/servo/components/style/values/computed/text.rs &gt;+++ b/servo/components/style/values/computed/text.rs &gt;@@ -3,24 +3,24 @@ &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed types for text properties. &gt; &gt; #[cfg(feature = "servo")] &gt; use properties::StyleBuilder; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ToCss}; &gt;-use values::{CSSFloat, CSSInteger}; &gt;-use values::computed::{NonNegativeLength, NonNegativeNumber}; &gt; use values::computed::length::{Length, LengthOrPercentage}; &gt;+use values::computed::{NonNegativeLength, NonNegativeNumber}; &gt; use values::generics::text::InitialLetter as GenericInitialLetter; &gt; use values::generics::text::LineHeight as GenericLineHeight; &gt; use values::generics::text::MozTabSize as GenericMozTabSize; &gt; use values::generics::text::Spacing; &gt; use values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword, TextOverflowSide}; &gt;+use values::{CSSFloat, CSSInteger}; &gt; &gt; pub use values::specified::TextAlignKeyword as TextAlign; &gt; pub use values::specified::TextEmphasisPosition; &gt; &gt; /// A computed value for the `initial-letter` property. &gt; pub type InitialLetter = GenericInitialLetter&lt;CSSFloat, CSSInteger&gt;; &gt; &gt; /// A computed value for the `letter-spacing` property. &gt;diff --git a/servo/components/style/values/computed/transform.rs b/servo/components/style/values/computed/transform.rs &gt;index bbf710c42956..8bdbdef6f676 100644 &gt;--- a/servo/components/style/values/computed/transform.rs &gt;+++ b/servo/components/style/values/computed/transform.rs &gt;@@ -1,17 +1,17 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed types for CSS values that are related to transformations. &gt; &gt;+use super::CSSFloat; &gt; use euclid::{Transform3D, Vector3D}; &gt; use num_traits::Zero; &gt;-use super::CSSFloat; &gt; use values::animated::ToAnimatedZero; &gt; use values::computed::{Angle, Integer, Length, LengthOrPercentage, Number, Percentage}; &gt; use values::generics::transform as generic; &gt; &gt; pub use values::generics::transform::TransformStyle; &gt; &gt; /// A single operation in a computed CSS `transform` &gt; pub type TransformOperation = &gt;@@ -118,53 +118,53 @@ impl From&lt;Transform3D&lt;CSSFloat&gt;&gt; for Matrix3D { &gt; &gt; impl TransformOperation { &gt; /// Convert to a Translate3D. &gt; /// &gt; /// Must be called on a Translate function &gt; pub fn to_translate_3d(&amp;self) -&gt; Self { &gt; match *self { &gt; generic::TransformOperation::Translate3D(..) =&gt; self.clone(), &gt;- generic::TransformOperation::TranslateX(ref x) | &gt;- generic::TransformOperation::Translate(ref x, None) =&gt; { &gt;+ generic::TransformOperation::TranslateX(ref x) &gt;+ | generic::TransformOperation::Translate(ref x, None) =&gt; { &gt; generic::TransformOperation::Translate3D( &gt; x.clone(), &gt; LengthOrPercentage::zero(), &gt; Length::zero(), &gt; ) &gt;- }, &gt;+ } &gt; generic::TransformOperation::Translate(ref x, Some(ref y)) =&gt; { &gt; generic::TransformOperation::Translate3D(x.clone(), y.clone(), Length::zero()) &gt;- }, &gt;+ } &gt; generic::TransformOperation::TranslateY(ref y) =&gt; { &gt; generic::TransformOperation::Translate3D( &gt; LengthOrPercentage::zero(), &gt; y.clone(), &gt; Length::zero(), &gt; ) &gt;- }, &gt;+ } &gt; generic::TransformOperation::TranslateZ(ref z) =&gt; { &gt; generic::TransformOperation::Translate3D( &gt; LengthOrPercentage::zero(), &gt; LengthOrPercentage::zero(), &gt; z.clone(), &gt; ) &gt;- }, &gt;+ } &gt; _ =&gt; unreachable!(), &gt; } &gt; } &gt; &gt; /// Convert to a Rotate3D. &gt; /// &gt; /// Must be called on a Rotate function. &gt; pub fn to_rotate_3d(&amp;self) -&gt; Self { &gt; match *self { &gt; generic::TransformOperation::Rotate3D(..) =&gt; self.clone(), &gt;- generic::TransformOperation::RotateZ(ref angle) | &gt;- generic::TransformOperation::Rotate(ref angle) =&gt; { &gt;+ generic::TransformOperation::RotateZ(ref angle) &gt;+ | generic::TransformOperation::Rotate(ref angle) =&gt; { &gt; generic::TransformOperation::Rotate3D(0., 0., 1., angle.clone()) &gt; } &gt; generic::TransformOperation::RotateX(ref angle) =&gt; { &gt; generic::TransformOperation::Rotate3D(1., 0., 0., angle.clone()) &gt; } &gt; generic::TransformOperation::RotateY(ref angle) =&gt; { &gt; generic::TransformOperation::Rotate3D(0., 1., 0., angle.clone()) &gt; } &gt;@@ -175,190 +175,192 @@ impl TransformOperation { &gt; /// Convert to a Scale3D. &gt; /// &gt; /// Must be called on a Scale function &gt; pub fn to_scale_3d(&amp;self) -&gt; Self { &gt; match *self { &gt; generic::TransformOperation::Scale3D(..) =&gt; self.clone(), &gt; generic::TransformOperation::Scale(s, None) =&gt; { &gt; generic::TransformOperation::Scale3D(s, s, 1.) &gt;- }, &gt;+ } &gt; generic::TransformOperation::Scale(x, Some(y)) =&gt; { &gt; generic::TransformOperation::Scale3D(x, y, 1.) &gt;- }, &gt;+ } &gt; generic::TransformOperation::ScaleX(x) =&gt; { &gt; generic::TransformOperation::Scale3D(x, 1., 1.) &gt;- }, &gt;+ } &gt; generic::TransformOperation::ScaleY(y) =&gt; { &gt; generic::TransformOperation::Scale3D(1., y, 1.) &gt;- }, &gt;+ } &gt; generic::TransformOperation::ScaleZ(z) =&gt; { &gt; generic::TransformOperation::Scale3D(1., 1., z) &gt;- }, &gt;+ } &gt; _ =&gt; unreachable!(), &gt; } &gt; } &gt; } &gt; &gt; /// Build an equivalent 'identity transform function list' based &gt; /// on an existing transform list. &gt; /// http://dev.w3.org/csswg/css-transforms/#none-transform-animation &gt; impl ToAnimatedZero for TransformOperation { &gt; fn to_animated_zero(&amp;self) -&gt; Result&lt;Self, ()&gt; { &gt; match *self { &gt; generic::TransformOperation::Matrix3D(..) =&gt; { &gt; Ok(generic::TransformOperation::Matrix3D(Matrix3D::identity())) &gt;- }, &gt;+ } &gt; generic::TransformOperation::Matrix(..) =&gt; { &gt; Ok(generic::TransformOperation::Matrix(Matrix::identity())) &gt;- }, &gt;+ } &gt; generic::TransformOperation::Skew(sx, sy) =&gt; Ok(generic::TransformOperation::Skew( &gt; sx.to_animated_zero()?, &gt; sy.to_animated_zero()?, &gt; )), &gt; generic::TransformOperation::SkewX(s) =&gt; { &gt; Ok(generic::TransformOperation::SkewX(s.to_animated_zero()?)) &gt;- }, &gt;+ } &gt; generic::TransformOperation::SkewY(s) =&gt; { &gt; Ok(generic::TransformOperation::SkewY(s.to_animated_zero()?)) &gt;- }, &gt;+ } &gt; generic::TransformOperation::Translate3D(ref tx, ref ty, ref tz) =&gt; { &gt; Ok(generic::TransformOperation::Translate3D( &gt; tx.to_animated_zero()?, &gt; ty.to_animated_zero()?, &gt; tz.to_animated_zero()?, &gt; )) &gt;- }, &gt;+ } &gt; generic::TransformOperation::Translate(ref tx, ref ty) =&gt; { &gt; Ok(generic::TransformOperation::Translate( &gt; tx.to_animated_zero()?, &gt; ty.to_animated_zero()?, &gt; )) &gt;- }, &gt;+ } &gt; generic::TransformOperation::TranslateX(ref t) =&gt; Ok( &gt; generic::TransformOperation::TranslateX(t.to_animated_zero()?), &gt; ), &gt; generic::TransformOperation::TranslateY(ref t) =&gt; Ok( &gt; generic::TransformOperation::TranslateY(t.to_animated_zero()?), &gt; ), &gt; generic::TransformOperation::TranslateZ(ref t) =&gt; Ok( &gt; generic::TransformOperation::TranslateZ(t.to_animated_zero()?), &gt; ), &gt; generic::TransformOperation::Scale3D(..) =&gt; { &gt; Ok(generic::TransformOperation::Scale3D(1.0, 1.0, 1.0)) &gt;- }, &gt;+ } &gt; generic::TransformOperation::Scale(_, _) =&gt; { &gt; Ok(generic::TransformOperation::Scale(1.0, Some(1.0))) &gt;- }, &gt;+ } &gt; generic::TransformOperation::ScaleX(..) =&gt; Ok(generic::TransformOperation::ScaleX(1.0)), &gt; generic::TransformOperation::ScaleY(..) =&gt; Ok(generic::TransformOperation::ScaleY(1.0)), &gt; generic::TransformOperation::ScaleZ(..) =&gt; Ok(generic::TransformOperation::ScaleZ(1.0)), &gt; generic::TransformOperation::Rotate3D(x, y, z, a) =&gt; { &gt; let (x, y, z, _) = generic::get_normalized_vector_and_angle(x, y, z, a); &gt; Ok(generic::TransformOperation::Rotate3D( &gt; x, &gt; y, &gt; z, &gt; Angle::zero(), &gt; )) &gt;- }, &gt;+ } &gt; generic::TransformOperation::RotateX(_) =&gt; { &gt; Ok(generic::TransformOperation::RotateX(Angle::zero())) &gt;- }, &gt;+ } &gt; generic::TransformOperation::RotateY(_) =&gt; { &gt; Ok(generic::TransformOperation::RotateY(Angle::zero())) &gt;- }, &gt;+ } &gt; generic::TransformOperation::RotateZ(_) =&gt; { &gt; Ok(generic::TransformOperation::RotateZ(Angle::zero())) &gt;- }, &gt;+ } &gt; generic::TransformOperation::Rotate(_) =&gt; { &gt; Ok(generic::TransformOperation::Rotate(Angle::zero())) &gt;- }, &gt;- generic::TransformOperation::Perspective(ref l) =&gt; { &gt;- Ok(generic::TransformOperation::Perspective(l.to_animated_zero()?)) &gt;- }, &gt;- generic::TransformOperation::AccumulateMatrix { .. } | &gt;- generic::TransformOperation::InterpolateMatrix { .. } =&gt; { &gt;+ } &gt;+ generic::TransformOperation::Perspective(ref l) =&gt; Ok( &gt;+ generic::TransformOperation::Perspective(l.to_animated_zero()?), &gt;+ ), &gt;+ generic::TransformOperation::AccumulateMatrix { .. } &gt;+ | generic::TransformOperation::InterpolateMatrix { .. } =&gt; { &gt; // AccumulateMatrix/InterpolateMatrix: We do interpolation on &gt; // AccumulateMatrix/InterpolateMatrix by reading it as a ComputedMatrix &gt; // (with layout information), and then do matrix interpolation. &gt; // &gt; // Therefore, we use an identity matrix to represent the identity transform list. &gt; // http://dev.w3.org/csswg/css-transforms/#identity-transform-function &gt; Ok(generic::TransformOperation::Matrix3D(Matrix3D::identity())) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl ToAnimatedZero for Transform { &gt; #[inline] &gt; fn to_animated_zero(&amp;self) -&gt; Result&lt;Self, ()&gt; { &gt;- Ok(generic::Transform(self.0 &gt;- .iter() &gt;- .map(|op| op.to_animated_zero()) &gt;- .collect::&lt;Result&lt;Vec&lt;_&gt;, _&gt;&gt;()?)) &gt;+ Ok(generic::Transform( &gt;+ self.0 &gt;+ .iter() &gt;+ .map(|op| op.to_animated_zero()) &gt;+ .collect::&lt;Result&lt;Vec&lt;_&gt;, _&gt;&gt;()?, &gt;+ )) &gt; } &gt; } &gt; &gt; /// A computed CSS `rotate` &gt; pub type Rotate = generic::Rotate&lt;Number, Angle&gt;; &gt; &gt; impl Rotate { &gt; /// Convert TransformOperation to Rotate. &gt; pub fn to_transform_operation(&amp;self) -&gt; Option&lt;TransformOperation&gt; { &gt; match *self { &gt; generic::Rotate::None =&gt; None, &gt; generic::Rotate::Rotate(angle) =&gt; Some(generic::TransformOperation::Rotate(angle)), &gt; generic::Rotate::Rotate3D(rx, ry, rz, angle) =&gt; { &gt; Some(generic::TransformOperation::Rotate3D(rx, ry, rz, angle)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Convert Rotate to TransformOperation. &gt; pub fn from_transform_operation(operation: &amp;TransformOperation) -&gt; Rotate { &gt; match *operation { &gt; generic::TransformOperation::Rotate(angle) =&gt; generic::Rotate::Rotate(angle), &gt; generic::TransformOperation::Rotate3D(rx, ry, rz, angle) =&gt; { &gt; generic::Rotate::Rotate3D(rx, ry, rz, angle) &gt;- }, &gt;+ } &gt; _ =&gt; unreachable!("Found unexpected value for rotate property"), &gt; } &gt; } &gt; } &gt; &gt; /// A computed CSS `translate` &gt; pub type Translate = generic::Translate&lt;LengthOrPercentage, Length&gt;; &gt; &gt; impl Translate { &gt; /// Convert TransformOperation to Translate. &gt; pub fn to_transform_operation(&amp;self) -&gt; Option&lt;TransformOperation&gt; { &gt; match *self { &gt; generic::Translate::None =&gt; None, &gt; generic::Translate::TranslateX(tx) =&gt; Some(generic::TransformOperation::TranslateX(tx)), &gt; generic::Translate::Translate(tx, ty) =&gt; { &gt; Some(generic::TransformOperation::Translate(tx, Some(ty))) &gt;- }, &gt;+ } &gt; generic::Translate::Translate3D(tx, ty, tz) =&gt; { &gt; Some(generic::TransformOperation::Translate3D(tx, ty, tz)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Convert Translate to TransformOperation. &gt; pub fn from_transform_operation(operation: &amp;TransformOperation) -&gt; Translate { &gt; match *operation { &gt; generic::TransformOperation::TranslateX(tx) =&gt; generic::Translate::TranslateX(tx), &gt; generic::TransformOperation::Translate(tx, Some(ty)) =&gt; { &gt; generic::Translate::Translate(tx, ty) &gt;- }, &gt;+ } &gt; generic::TransformOperation::Translate3D(tx, ty, tz) =&gt; { &gt; generic::Translate::Translate3D(tx, ty, tz) &gt;- }, &gt;+ } &gt; _ =&gt; unreachable!("Found unexpected value for translate"), &gt; } &gt; } &gt; } &gt; &gt; /// A computed CSS `scale` &gt; pub type Scale = generic::Scale&lt;Number&gt;; &gt; &gt;@@ -366,17 +368,17 @@ impl Scale { &gt; /// Convert TransformOperation to Scale. &gt; pub fn to_transform_operation(&amp;self) -&gt; Option&lt;TransformOperation&gt; { &gt; match *self { &gt; generic::Scale::None =&gt; None, &gt; generic::Scale::ScaleX(sx) =&gt; Some(generic::TransformOperation::ScaleX(sx)), &gt; generic::Scale::Scale(sx, sy) =&gt; Some(generic::TransformOperation::Scale(sx, Some(sy))), &gt; generic::Scale::Scale3D(sx, sy, sz) =&gt; { &gt; Some(generic::TransformOperation::Scale3D(sx, sy, sz)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; /// Convert Scale to TransformOperation. &gt; pub fn from_transform_operation(operation: &amp;TransformOperation) -&gt; Scale { &gt; match *operation { &gt; generic::TransformOperation::ScaleX(sx) =&gt; generic::Scale::ScaleX(sx), &gt; generic::TransformOperation::Scale(sx, Some(sy)) =&gt; generic::Scale::Scale(sx, sy), &gt;diff --git a/servo/components/style/values/computed/ui.rs b/servo/components/style/values/computed/ui.rs &gt;index 5307f79a38e1..1639069fdf46 100644 &gt;--- a/servo/components/style/values/computed/ui.rs &gt;+++ b/servo/components/style/values/computed/ui.rs &gt;@@ -1,19 +1,19 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Computed values for UI properties &gt; &gt;-use values::{Auto, Either}; &gt;-use values::computed::Number; &gt; use values::computed::color::Color; &gt; use values::computed::url::ComputedImageUrl; &gt;+use values::computed::Number; &gt; use values::generics::ui as generics; &gt;+use values::{Auto, Either}; &gt; &gt; pub use values::specified::ui::MozForceBrokenImageIcon; &gt; &gt; /// auto | &lt;color&gt; &gt; pub type ColorOrAuto = Either&lt;Color, Auto&gt;; &gt; &gt; /// A computed value for the `cursor` property. &gt; pub type Cursor = generics::Cursor&lt;CursorImage&gt;; &gt;diff --git a/servo/components/style/values/computed/url.rs b/servo/components/style/values/computed/url.rs &gt;index cf9577101822..aca5d301fd25 100644 &gt;--- a/servo/components/style/values/computed/url.rs &gt;+++ b/servo/components/style/values/computed/url.rs &gt;@@ -1,18 +1,18 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Common handling for the computed value CSS url() values. &gt; &gt; use values::generics::url::UrlOrNone as GenericUrlOrNone; &gt; &gt;-#[cfg(feature = "servo")] &gt;-pub use servo::url::{ComputedImageUrl, ComputedUrl}; &gt; #[cfg(feature = "gecko")] &gt; pub use gecko::url::{ComputedImageUrl, ComputedUrl}; &gt;+#[cfg(feature = "servo")] &gt;+pub use servo::url::{ComputedImageUrl, ComputedUrl}; &gt; &gt; /// Computed &lt;url&gt; | &lt;none&gt; &gt; pub type UrlOrNone = GenericUrlOrNone&lt;ComputedUrl&gt;; &gt; &gt; /// Computed image &lt;url&gt; | &lt;none&gt; &gt; pub type ImageUrlOrNone = GenericUrlOrNone&lt;ComputedImageUrl&gt;; &gt;diff --git a/servo/components/style/values/distance.rs b/servo/components/style/values/distance.rs &gt;index fbdd4ea00043..c2827c4ece9e 100644 &gt;--- a/servo/components/style/values/distance.rs &gt;+++ b/servo/components/style/values/distance.rs &gt;@@ -96,18 +96,18 @@ where &gt; } &gt; &gt; impl&lt;T&gt; ComputeSquaredDistance for Size2D&lt;T&gt; &gt; where &gt; T: ComputeSquaredDistance, &gt; { &gt; #[inline] &gt; fn compute_squared_distance(&amp;self, other: &amp;Self) -&gt; Result&lt;SquaredDistance, ()&gt; { &gt;- Ok(self.width.compute_squared_distance(&amp;other.width)? + &gt;- self.height.compute_squared_distance(&amp;other.height)?) &gt;+ Ok(self.width.compute_squared_distance(&amp;other.width)? &gt;+ + self.height.compute_squared_distance(&amp;other.height)?) &gt; } &gt; } &gt; &gt; impl SquaredDistance { &gt; /// Returns the square root of this squared distance. &gt; #[inline] &gt; pub fn sqrt(self) -&gt; f64 { &gt; self.value.sqrt() &gt;diff --git a/servo/components/style/values/generics/background.rs b/servo/components/style/values/generics/background.rs &gt;index b25b00514d02..a4f4c58d8cd3 100644 &gt;--- a/servo/components/style/values/generics/background.rs &gt;+++ b/servo/components/style/values/generics/background.rs &gt;@@ -1,18 +1,29 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for CSS values related to backgrounds. &gt; &gt; /// A generic value for the `background-size` property. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum BackgroundSize&lt;LengthOrPercentageOrAuto&gt; { &gt; /// `&lt;width&gt; &lt;height&gt;` &gt; Explicit { &gt; /// Explicit width. &gt; width: LengthOrPercentageOrAuto, &gt; /// Explicit height. &gt; height: LengthOrPercentageOrAuto, &gt; }, &gt;diff --git a/servo/components/style/values/generics/basic_shape.rs b/servo/components/style/values/generics/basic_shape.rs &gt;index 3bad738c1e61..dc2ac6562307 100644 &gt;--- a/servo/components/style/values/generics/basic_shape.rs &gt;+++ b/servo/components/style/values/generics/basic_shape.rs &gt;@@ -13,129 +13,196 @@ use values::generics::border::BorderRadius; &gt; use values::generics::position::Position; &gt; use values::generics::rect::Rect; &gt; &gt; /// A clipping shape, for `clip-path`. &gt; pub type ClippingShape&lt;BasicShape, Url&gt; = ShapeSource&lt;BasicShape, GeometryBox, Url&gt;; &gt; &gt; /// &lt;https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box&gt; &gt; #[allow(missing_docs)] &gt;-#[derive(Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; pub enum GeometryBox { &gt; FillBox, &gt; StrokeBox, &gt; ViewBox, &gt; ShapeBox(ShapeBox), &gt; } &gt; &gt; /// A float area shape, for `shape-outside`. &gt; pub type FloatAreaShape&lt;BasicShape, Image&gt; = ShapeSource&lt;BasicShape, ShapeBox, Image&gt;; &gt; &gt; /// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Animate, Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum ShapeBox { &gt; MarginBox, &gt; BorderBox, &gt; PaddingBox, &gt; ContentBox, &gt; } &gt; &gt; /// A shape source, for some reference box. &gt; #[allow(missing_docs)] &gt; #[animation(no_bound(ImageOrUrl))] &gt;-#[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; pub enum ShapeSource&lt;BasicShape, ReferenceBox, ImageOrUrl&gt; { &gt; #[animation(error)] &gt; ImageOrUrl(ImageOrUrl), &gt; Shape(BasicShape, Option&lt;ReferenceBox&gt;), &gt; #[animation(error)] &gt; Box(ReferenceBox), &gt; #[animation(error)] &gt; None, &gt; } &gt; &gt; #[allow(missing_docs)] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum BasicShape&lt;H, V, LengthOrPercentage&gt; { &gt; Inset(#[css(field_bound)] InsetRect&lt;LengthOrPercentage&gt;), &gt; Circle(#[css(field_bound)] Circle&lt;H, V, LengthOrPercentage&gt;), &gt; Ellipse(#[css(field_bound)] Ellipse&lt;H, V, LengthOrPercentage&gt;), &gt; Polygon(Polygon&lt;LengthOrPercentage&gt;), &gt; } &gt; &gt; /// &lt;https://drafts.csswg.org/css-shapes/#funcdef-inset&gt; &gt; #[allow(missing_docs)] &gt; #[css(function = "inset")] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+)] &gt; pub struct InsetRect&lt;LengthOrPercentage&gt; { &gt; pub rect: Rect&lt;LengthOrPercentage&gt;, &gt; pub round: Option&lt;BorderRadius&lt;LengthOrPercentage&gt;&gt;, &gt; } &gt; &gt; /// &lt;https://drafts.csswg.org/css-shapes/#funcdef-circle&gt; &gt; #[allow(missing_docs)] &gt; #[css(function)] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+)] &gt; pub struct Circle&lt;H, V, LengthOrPercentage&gt; { &gt; pub position: Position&lt;H, V&gt;, &gt; pub radius: ShapeRadius&lt;LengthOrPercentage&gt;, &gt; } &gt; &gt; /// &lt;https://drafts.csswg.org/css-shapes/#funcdef-ellipse&gt; &gt; #[allow(missing_docs)] &gt; #[css(function)] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+)] &gt; pub struct Ellipse&lt;H, V, LengthOrPercentage&gt; { &gt; pub position: Position&lt;H, V&gt;, &gt; pub semiaxis_x: ShapeRadius&lt;LengthOrPercentage&gt;, &gt; pub semiaxis_y: ShapeRadius&lt;LengthOrPercentage&gt;, &gt; } &gt; &gt; /// &lt;https://drafts.csswg.org/css-shapes/#typedef-shape-radius&gt; &gt; #[allow(missing_docs)] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum ShapeRadius&lt;LengthOrPercentage&gt; { &gt; Length(LengthOrPercentage), &gt; #[animation(error)] &gt; ClosestSide, &gt; #[animation(error)] &gt; FarthestSide, &gt; } &gt; &gt; /// A generic type for representing the `polygon()` function &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-shapes/#funcdef-polygon&gt; &gt; #[css(function)] &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct Polygon&lt;LengthOrPercentage&gt; { &gt; /// The filling rule for a polygon. &gt; pub fill: FillRule, &gt; /// A collection of (x, y) coordinates to draw the polygon. &gt; pub coordinates: Vec&lt;(LengthOrPercentage, LengthOrPercentage)&gt;, &gt; } &gt; &gt; // https://drafts.csswg.org/css-shapes/#typedef-fill-rule &gt; // NOTE: Basic shapes spec says that these are the only two values, however &gt; // https://www.w3.org/TR/SVG/painting.html#FillRuleProperty &gt; // says that it can also be `inherit` &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum FillRule { &gt; Nonzero, &gt; Evenodd, &gt; } &gt; &gt; // FIXME(nox): Implement ComputeSquaredDistance for T types and stop &gt; // using PartialEq here, this will let us derive this impl. &gt; impl&lt;B, T, U&gt; ComputeSquaredDistance for ShapeSource&lt;B, T, U&gt; &gt;@@ -143,20 +210,21 @@ where &gt; B: ComputeSquaredDistance, &gt; T: PartialEq, &gt; { &gt; fn compute_squared_distance(&amp;self, other: &amp;Self) -&gt; Result&lt;SquaredDistance, ()&gt; { &gt; match (self, other) { &gt; ( &gt; &amp;ShapeSource::Shape(ref this, ref this_box), &gt; &amp;ShapeSource::Shape(ref other, ref other_box), &gt;- ) if this_box == other_box =&gt; &gt;+ ) &gt;+ if this_box == other_box =&gt; &gt; { &gt; this.compute_squared_distance(other) &gt;- }, &gt;+ } &gt; _ =&gt; Err(()), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;B, T, U&gt; ToAnimatedZero for ShapeSource&lt;B, T, U&gt; { &gt; fn to_animated_zero(&amp;self) -&gt; Result&lt;Self, ()&gt; { &gt; Err(()) &gt;@@ -194,26 +262,26 @@ where &gt; { &gt; fn animate(&amp;self, other: &amp;Self, procedure: Procedure) -&gt; Result&lt;Self, ()&gt; { &gt; if self.fill != other.fill { &gt; return Err(()); &gt; } &gt; if self.coordinates.len() != other.coordinates.len() { &gt; return Err(()); &gt; } &gt;- let coordinates = self.coordinates &gt;+ let coordinates = self &gt;+ .coordinates &gt; .iter() &gt; .zip(other.coordinates.iter()) &gt; .map(|(this, other)| { &gt; Ok(( &gt; this.0.animate(&amp;other.0, procedure)?, &gt; this.1.animate(&amp;other.1, procedure)?, &gt; )) &gt;- }) &gt;- .collect::&lt;Result&lt;Vec&lt;_&gt;, _&gt;&gt;()?; &gt;+ }).collect::&lt;Result&lt;Vec&lt;_&gt;, _&gt;&gt;()?; &gt; Ok(Polygon { &gt; fill: self.fill, &gt; coordinates, &gt; }) &gt; } &gt; } &gt; &gt; impl&lt;L&gt; ComputeSquaredDistance for Polygon&lt;L&gt; &gt;@@ -229,18 +297,17 @@ where &gt; } &gt; self.coordinates &gt; .iter() &gt; .zip(other.coordinates.iter()) &gt; .map(|(this, other)| { &gt; let d1 = this.0.compute_squared_distance(&amp;other.0)?; &gt; let d2 = this.1.compute_squared_distance(&amp;other.1)?; &gt; Ok(d1 + d2) &gt;- }) &gt;- .sum() &gt;+ }).sum() &gt; } &gt; } &gt; &gt; impl&lt;L: ToCss&gt; ToCss for Polygon&lt;L&gt; { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt;diff --git a/servo/components/style/values/generics/border.rs b/servo/components/style/values/generics/border.rs &gt;index c25560ed0f15..5ed7fbdee98c 100644 &gt;--- a/servo/components/style/values/generics/border.rs &gt;+++ b/servo/components/style/values/generics/border.rs &gt;@@ -5,69 +5,101 @@ &gt; //! Generic types for CSS values related to borders. &gt; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ToCss}; &gt; use values::generics::rect::Rect; &gt; use values::generics::size::Size; &gt; &gt; /// A generic value for a single side of a `border-image-width` property. &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; pub enum BorderImageSideWidth&lt;LengthOrPercentage, Number&gt; { &gt; /// `&lt;length-or-percentage&gt;` &gt; Length(LengthOrPercentage), &gt; /// `&lt;number&gt;` &gt; Number(Number), &gt; /// `auto` &gt; Auto, &gt; } &gt; &gt; /// A generic value for the `border-image-slice` property. &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; pub struct BorderImageSlice&lt;NumberOrPercentage&gt; { &gt; /// The offsets. &gt; #[css(field_bound)] &gt; pub offsets: Rect&lt;NumberOrPercentage&gt;, &gt; /// Whether to fill the middle part. &gt; #[css(represents_keyword)] &gt; pub fill: bool, &gt; } &gt; &gt; /// A generic value for the `border-*-radius` longhand properties. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub struct BorderCornerRadius&lt;L&gt;(#[css(field_bound)] pub Size&lt;L&gt;); &gt; &gt; impl&lt;L&gt; BorderCornerRadius&lt;L&gt; { &gt; /// Trivially create a `BorderCornerRadius`. &gt; pub fn new(w: L, h: L) -&gt; Self { &gt; BorderCornerRadius(Size::new(w, h)) &gt; } &gt; } &gt; &gt; /// A generic value for the `border-spacing` property. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub struct BorderSpacing&lt;L&gt;(#[css(field_bound)] pub Size&lt;L&gt;); &gt; &gt; impl&lt;L&gt; BorderSpacing&lt;L&gt; { &gt; /// Trivially create a `BorderCornerRadius`. &gt; pub fn new(w: L, h: L) -&gt; Self { &gt; BorderSpacing(Size::new(w, h)) &gt; } &gt; } &gt; &gt; /// A generic value for `border-radius`, `outline-radius` and `inset()`. &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-backgrounds-3/#border-radius&gt; &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+)] &gt; pub struct BorderRadius&lt;LengthOrPercentage&gt; { &gt; /// The top left radius. &gt; pub top_left: BorderCornerRadius&lt;LengthOrPercentage&gt;, &gt; /// The top right radius. &gt; pub top_right: BorderCornerRadius&lt;LengthOrPercentage&gt;, &gt; /// The bottom right radius. &gt; pub bottom_right: BorderCornerRadius&lt;LengthOrPercentage&gt;, &gt; /// The bottom left radius. &gt;@@ -115,18 +147,20 @@ where &gt; widths: Rect&lt;&amp;L&gt;, &gt; heights: Rect&lt;&amp;L&gt;, &gt; dest: &amp;mut CssWriter&lt;W&gt;, &gt; ) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; widths.to_css(dest)?; &gt;- if widths.0 != heights.0 || widths.1 != heights.1 || widths.2 != heights.2 || &gt;- widths.3 != heights.3 &gt;+ if widths.0 != heights.0 &gt;+ || widths.1 != heights.1 &gt;+ || widths.2 != heights.2 &gt;+ || widths.3 != heights.3 &gt; { &gt; dest.write_str(" / ")?; &gt; heights.to_css(dest)?; &gt; } &gt; Ok(()) &gt; } &gt; } &gt; &gt;diff --git a/servo/components/style/values/generics/box.rs b/servo/components/style/values/generics/box.rs &gt;index ea79e98eefb8..0b5259742887 100644 &gt;--- a/servo/components/style/values/generics/box.rs &gt;+++ b/servo/components/style/values/generics/box.rs &gt;@@ -2,18 +2,28 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for box properties. &gt; &gt; use values::animated::ToAnimatedZero; &gt; &gt; /// A generic value for the `vertical-align` property. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum VerticalAlign&lt;LengthOrPercentage&gt; { &gt; /// `baseline` &gt; Baseline, &gt; /// `sub` &gt; Sub, &gt; /// `super` &gt; Super, &gt; /// `top` &gt;@@ -43,29 +53,39 @@ impl&lt;L&gt; VerticalAlign&lt;L&gt; { &gt; &gt; impl&lt;L&gt; ToAnimatedZero for VerticalAlign&lt;L&gt; { &gt; fn to_animated_zero(&amp;self) -&gt; Result&lt;Self, ()&gt; { &gt; Err(()) &gt; } &gt; } &gt; &gt; /// https://drafts.csswg.org/css-animations/#animation-iteration-count &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub enum AnimationIterationCount&lt;Number&gt; { &gt; /// A `&lt;number&gt;` value. &gt; Number(Number), &gt; /// The `infinite` keyword. &gt; Infinite, &gt; } &gt; &gt; /// A generic value for the `perspective` property. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum Perspective&lt;NonNegativeLength&gt; { &gt; /// A non-negative length. &gt; Length(NonNegativeLength), &gt; /// The keyword `none`. &gt; None, &gt; } &gt; &gt; impl&lt;L&gt; Perspective&lt;L&gt; { &gt;diff --git a/servo/components/style/values/generics/column.rs b/servo/components/style/values/generics/column.rs &gt;index 1d76f6cb552c..5f96650d3e8d 100644 &gt;--- a/servo/components/style/values/generics/column.rs &gt;+++ b/servo/components/style/values/generics/column.rs &gt;@@ -1,18 +1,29 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for the column properties. &gt; &gt; /// A generic type for `column-count` values. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum ColumnCount&lt;PositiveInteger&gt; { &gt; /// A positive integer. &gt; Integer(PositiveInteger), &gt; /// The keyword `auto`. &gt; #[animation(error)] &gt; Auto, &gt; } &gt; &gt;diff --git a/servo/components/style/values/generics/counters.rs b/servo/components/style/values/generics/counters.rs &gt;index 779d56d65ee9..a5990691336d 100644 &gt;--- a/servo/components/style/values/generics/counters.rs &gt;+++ b/servo/components/style/values/generics/counters.rs &gt;@@ -2,35 +2,35 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for counters-related CSS values. &gt; &gt; #[cfg(feature = "servo")] &gt; use computed_values::list_style_type::T as ListStyleType; &gt; use std::ops::Deref; &gt;-use values::CustomIdent; &gt; #[cfg(feature = "gecko")] &gt; use values::generics::CounterStyleOrNone; &gt; #[cfg(feature = "gecko")] &gt; use values::specified::Attr; &gt;+use values::CustomIdent; &gt; &gt; /// A name / value pair for counters. &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub struct CounterPair&lt;Integer&gt; { &gt; /// The name of the counter. &gt; pub name: CustomIdent, &gt; /// The value of the counter / increment / etc. &gt; pub value: Integer, &gt; } &gt; &gt; /// A generic value for the `counter-increment` property. &gt;-#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; pub struct CounterIncrement&lt;I&gt;(Counters&lt;I&gt;); &gt; &gt; impl&lt;I&gt; CounterIncrement&lt;I&gt; { &gt; /// Returns a new value for `counter-increment`. &gt; #[inline] &gt; pub fn new(counters: Vec&lt;CounterPair&lt;I&gt;&gt;) -&gt; Self { &gt; CounterIncrement(Counters(counters.into_boxed_slice())) &gt; } &gt;@@ -41,18 +41,19 @@ impl&lt;I&gt; Deref for CounterIncrement&lt;I&gt; { &gt; &gt; #[inline] &gt; fn deref(&amp;self) -&gt; &amp;Self::Target { &gt; &amp;(self.0).0 &gt; } &gt; } &gt; &gt; /// A generic value for the `counter-reset` property. &gt;-#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; pub struct CounterReset&lt;I&gt;(Counters&lt;I&gt;); &gt; &gt; impl&lt;I&gt; CounterReset&lt;I&gt; { &gt; /// Returns a new value for `counter-reset`. &gt; #[inline] &gt; pub fn new(counters: Vec&lt;CounterPair&lt;I&gt;&gt;) -&gt; Self { &gt; CounterReset(Counters(counters.into_boxed_slice())) &gt; } &gt;@@ -65,18 +66,17 @@ impl&lt;I&gt; Deref for CounterReset&lt;I&gt; { &gt; fn deref(&amp;self) -&gt; &amp;Self::Target { &gt; &amp;(self.0).0 &gt; } &gt; } &gt; &gt; /// A generic value for lists of counters. &gt; /// &gt; /// Keyword `none` is represented by an empty vector. &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub struct Counters&lt;I&gt;(#[css(iterable, if_empty = "none")] Box&lt;[CounterPair&lt;I&gt;]&gt;); &gt; &gt; impl&lt;I&gt; Default for Counters&lt;I&gt; { &gt; #[inline] &gt; fn default() -&gt; Self { &gt; Counters(vec![].into_boxed_slice()) &gt; } &gt; } &gt;@@ -97,18 +97,17 @@ fn is_decimal(counter_type: &amp;CounterStyleType) -&gt; bool { &gt; #[inline] &gt; fn is_decimal(counter_type: &amp;CounterStyleType) -&gt; bool { &gt; *counter_type == CounterStyleOrNone::decimal() &gt; } &gt; &gt; /// The specified value for the `content` property. &gt; /// &gt; /// https://drafts.csswg.org/css-content/#propdef-content &gt;-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub enum Content&lt;ImageUrl&gt; { &gt; /// `normal` reserved keyword. &gt; Normal, &gt; /// `none` reserved keyword. &gt; None, &gt; /// `-moz-alt-content`. &gt; #[cfg(feature = "gecko")] &gt; MozAltContent, &gt;@@ -120,18 +119,17 @@ impl&lt;ImageUrl&gt; Content&lt;ImageUrl&gt; { &gt; /// Set `content` property to `normal`. &gt; #[inline] &gt; pub fn normal() -&gt; Self { &gt; Content::Normal &gt; } &gt; } &gt; &gt; /// Items for the `content` property. &gt;-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub enum ContentItem&lt;ImageUrl&gt; { &gt; /// Literal string content. &gt; String(Box&lt;str&gt;), &gt; /// `counter(name, style)`. &gt; #[css(comma, function)] &gt; Counter(CustomIdent, #[css(skip_if = "is_decimal")] CounterStyleType), &gt; /// `counters(name, separator, style)`. &gt; #[css(comma, function)] &gt;diff --git a/servo/components/style/values/generics/effects.rs b/servo/components/style/values/generics/effects.rs &gt;index f05dfe82d66f..7c7e3f4bef32 100644 &gt;--- a/servo/components/style/values/generics/effects.rs &gt;+++ b/servo/components/style/values/generics/effects.rs &gt;@@ -1,33 +1,51 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for CSS values related to effects. &gt; &gt; /// A generic value for a single `box-shadow`. &gt;-#[derive(Animate, Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToAnimatedValue, ToAnimatedZero, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToCss, &gt;+)] &gt; pub struct BoxShadow&lt;Color, SizeLength, BlurShapeLength, ShapeLength&gt; { &gt; /// The base shadow. &gt; pub base: SimpleShadow&lt;Color, SizeLength, BlurShapeLength&gt;, &gt; /// The spread radius. &gt; pub spread: ShapeLength, &gt; /// Whether this is an inset box shadow. &gt; #[animation(constant)] &gt; #[css(represents_keyword)] &gt; pub inset: bool, &gt; } &gt; &gt; /// A generic value for a single `filter`. &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt; #[animation(no_bound(Url))] &gt;-#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum Filter&lt;Angle, Factor, Length, DropShadow, Url&gt; { &gt; /// `blur(&lt;length&gt;)` &gt; #[css(function)] &gt; Blur(Length), &gt; /// `brightness(&lt;factor&gt;)` &gt; #[css(function)] &gt; Brightness(Factor), &gt; /// `contrast(&lt;factor&gt;)` &gt;@@ -58,18 +76,28 @@ pub enum Filter&lt;Angle, Factor, Length, DropShadow, Url&gt; { &gt; #[animation(error)] &gt; Url(Url), &gt; } &gt; &gt; /// A generic value for the `drop-shadow()` filter and the `text-shadow` property. &gt; /// &gt; /// Contrary to the canonical order from the spec, the color is serialised &gt; /// first, like in Gecko and Webkit. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToCss, &gt;+)] &gt; pub struct SimpleShadow&lt;Color, SizeLength, ShapeLength&gt; { &gt; /// Color. &gt; pub color: Color, &gt; /// Horizontal radius. &gt; pub horizontal: SizeLength, &gt; /// Vertical radius. &gt; pub vertical: SizeLength, &gt; /// Blur radius. &gt;diff --git a/servo/components/style/values/generics/flex.rs b/servo/components/style/values/generics/flex.rs &gt;index 1ab53233c446..9cbece2e1bc2 100644 &gt;--- a/servo/components/style/values/generics/flex.rs &gt;+++ b/servo/components/style/values/generics/flex.rs &gt;@@ -1,17 +1,27 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for CSS values related to flexbox. &gt; &gt; /// A generic value for the `flex-basis` property. &gt; #[cfg_attr(feature = "servo", derive(MallocSizeOf))] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue, &gt;- ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum FlexBasis&lt;Width&gt; { &gt; /// `content` &gt; Content, &gt; /// `&lt;width&gt;` &gt; Width(Width), &gt; } &gt;diff --git a/servo/components/style/values/generics/font.rs b/servo/components/style/values/generics/font.rs &gt;index 02df291065f3..03a76c5a32d2 100644 &gt;--- a/servo/components/style/values/generics/font.rs &gt;+++ b/servo/components/style/values/generics/font.rs &gt;@@ -11,18 +11,17 @@ use num_traits::One; &gt; use parser::{Parse, ParserContext}; &gt; use std::fmt::{self, Write}; &gt; use std::io::Cursor; &gt; use style_traits::{CssWriter, KeywordsCollectFn, ParseError}; &gt; use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; &gt; use values::distance::{ComputeSquaredDistance, SquaredDistance}; &gt; &gt; /// https://drafts.csswg.org/css-fonts-4/#feature-tag-value &gt;-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct FeatureTagValue&lt;Integer&gt; { &gt; /// A four-character tag, packed into a u32 (one byte per character). &gt; pub tag: FontTag, &gt; /// The actual value. &gt; pub value: Integer, &gt; } &gt; &gt; impl&lt;Integer&gt; ToCss for FeatureTagValue&lt;Integer&gt; &gt;@@ -42,18 +41,19 @@ where &gt; &gt; Ok(()) &gt; } &gt; } &gt; &gt; /// Variation setting for a single feature, see: &gt; /// &gt; /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def &gt;-#[derive(Animate, Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; pub struct VariationValue&lt;Number&gt; { &gt; /// A four-character tag, packed into a u32 (one byte per character). &gt; #[animation(constant)] &gt; pub tag: FontTag, &gt; /// The actual value. &gt; pub value: Number, &gt; } &gt; &gt;@@ -67,18 +67,17 @@ where &gt; return Err(()); &gt; } &gt; self.value.compute_squared_distance(&amp;other.value) &gt; } &gt; } &gt; &gt; /// A value both for font-variation-settings and font-feature-settings. &gt; #[css(comma)] &gt;-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub struct FontSettings&lt;T&gt;(#[css(if_empty = "normal", iterable)] pub Box&lt;[T]&gt;); &gt; &gt; impl&lt;T&gt; FontSettings&lt;T&gt; { &gt; /// Default value of font settings as `normal`. &gt; #[inline] &gt; pub fn normal() -&gt; Self { &gt; FontSettings(vec![].into_boxed_slice()) &gt; } &gt;@@ -104,18 +103,17 @@ impl&lt;T: Parse&gt; Parse for FontSettings&lt;T&gt; { &gt; } &gt; &gt; /// A font four-character tag, represented as a u32 for convenience. &gt; /// &gt; /// See: &gt; /// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def &gt; /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings &gt; /// &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct FontTag(pub u32); &gt; &gt; impl ToCss for FontTag { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; use byteorder::{BigEndian, ByteOrder}; &gt;@@ -140,18 +138,28 @@ impl Parse for FontTag { &gt; return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt; &gt; let mut raw = Cursor::new(tag.as_bytes()); &gt; Ok(FontTag(raw.read_u32::&lt;BigEndian&gt;().unwrap())) &gt; } &gt; } &gt; &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, &gt;- ToAnimatedValue, ToAnimatedZero, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToCss, &gt;+)] &gt; /// Additional information for keyword-derived font sizes. &gt; pub struct KeywordInfo&lt;Length&gt; { &gt; /// The keyword used &gt; pub kw: KeywordSize, &gt; /// A factor to be multiplied by the computed size of the keyword &gt; #[css(skip)] &gt; pub factor: f32, &gt; /// An additional Au offset to add to the kw*factor in the case of calcs &gt;@@ -184,19 +192,30 @@ where &gt; &gt; impl&lt;L&gt; SpecifiedValueInfo for KeywordInfo&lt;L&gt; { &gt; fn collect_completion_keywords(f: KeywordsCollectFn) { &gt; &lt;KeywordSize as SpecifiedValueInfo&gt;::collect_completion_keywords(f); &gt; } &gt; } &gt; &gt; /// CSS font keywords &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- Parse, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, &gt;- ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToCss, &gt;+)] &gt; #[allow(missing_docs)] &gt; pub enum KeywordSize { &gt; #[css(keyword = "xx-small")] &gt; XXSmall, &gt; XSmall, &gt; Small, &gt; Medium, &gt; Large, &gt;@@ -223,18 +242,29 @@ impl Default for KeywordSize { &gt; } &gt; } &gt; &gt; /// A generic value for the `font-style` property. &gt; /// &gt; /// https://drafts.csswg.org/css-fonts-4/#font-style-prop &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Hash, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ Hash, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+)] &gt; pub enum FontStyle&lt;Angle&gt; { &gt; #[animation(error)] &gt; Normal, &gt; #[animation(error)] &gt; Italic, &gt; #[value_info(starts_with_keyword)] &gt; Oblique(Angle), &gt; } &gt;diff --git a/servo/components/style/values/generics/gecko.rs b/servo/components/style/values/generics/gecko.rs &gt;index 72a8b71d073e..d56158750b6b 100644 &gt;--- a/servo/components/style/values/generics/gecko.rs &gt;+++ b/servo/components/style/values/generics/gecko.rs &gt;@@ -2,18 +2,17 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for legacy Gecko-only properties that should probably be &gt; //! unshipped at some point in the future. &gt; &gt; /// A generic value for scroll snap points. &gt; #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] &gt;-#[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToComputedValue, &gt;- ToCss)] &gt;+#[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub enum ScrollSnapPoint&lt;LengthOrPercentage&gt; { &gt; /// `none` &gt; None, &gt; /// `repeat(&lt;length-or-percentage&gt;)` &gt; #[css(function)] &gt; Repeat(LengthOrPercentage), &gt; } &gt; &gt;diff --git a/servo/components/style/values/generics/grid.rs b/servo/components/style/values/generics/grid.rs &gt;index b9ec85ace226..6e7c3ead2e11 100644 &gt;--- a/servo/components/style/values/generics/grid.rs &gt;+++ b/servo/components/style/values/generics/grid.rs &gt;@@ -2,29 +2,28 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for the handling of &gt; //! [grids](https://drafts.csswg.org/css-grid/). &gt; &gt; use cssparser::Parser; &gt; use parser::{Parse, ParserContext}; &gt;-use std::{mem, usize}; &gt; use std::fmt::{self, Write}; &gt;+use std::{mem, usize}; &gt; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt;-use values::{CSSFloat, CustomIdent}; &gt; use values::computed::{Context, ToComputedValue}; &gt; use values::specified; &gt; use values::specified::grid::parse_line_names; &gt;+use values::{CSSFloat, CustomIdent}; &gt; &gt; /// A `&lt;grid-line&gt;` type. &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line&gt; &gt;-#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct GridLine&lt;Integer&gt; { &gt; /// Flag to check whether it's a `span` keyword. &gt; pub is_span: bool, &gt; /// A custom identifier for named lines. &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-grid/#grid-placement-slot&gt; &gt; pub ident: Option&lt;CustomIdent&gt;, &gt; /// Denotes the nth grid line from grid item's placement. &gt;@@ -144,30 +143,39 @@ impl Parse for GridLine&lt;specified::Integer&gt; { &gt; } &gt; &gt; Ok(grid_line) &gt; } &gt; } &gt; &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum TrackKeyword { &gt; Auto, &gt; MaxContent, &gt; MinContent, &gt; } &gt; &gt; /// A track breadth for explicit grid track sizing. It's generic solely to &gt; /// avoid re-implementing it for the computed type. &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-grid/#typedef-track-breadth&gt; &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub enum TrackBreadth&lt;L&gt; { &gt; /// The generic type is almost always a non-negative `&lt;length-percentage&gt;` &gt; Breadth(L), &gt; /// A flex fraction specified in `fr` units. &gt; #[css(dimension)] &gt; Fr(CSSFloat), &gt; /// One of the track-sizing keywords (`auto`, `min-content`, `max-content`) &gt; Keyword(TrackKeyword), &gt;@@ -222,17 +230,17 @@ impl&lt;L&gt; TrackSize&lt;L&gt; { &gt; if breadth_1.is_fixed() { &gt; return true; // the second value is always a &lt;track-breadth&gt; &gt; } &gt; &gt; match *breadth_1 { &gt; TrackBreadth::Fr(_) =&gt; false, // should be &lt;inflexible-breadth&gt; at this point &gt; _ =&gt; breadth_2.is_fixed(), &gt; } &gt;- }, &gt;+ } &gt; TrackSize::FitContent(_) =&gt; false, &gt; } &gt; } &gt; } &gt; &gt; impl&lt;L&gt; Default for TrackSize&lt;L&gt; { &gt; fn default() -&gt; Self { &gt; TrackSize::Breadth(TrackBreadth::Keyword(TrackKeyword::Auto)) &gt;@@ -262,22 +270,22 @@ impl&lt;L: ToCss&gt; ToCss for TrackSize&lt;L&gt; { &gt; } &gt; } &gt; &gt; dest.write_str("minmax(")?; &gt; min.to_css(dest)?; &gt; dest.write_str(", ")?; &gt; max.to_css(dest)?; &gt; dest.write_str(")") &gt;- }, &gt;+ } &gt; TrackSize::FitContent(ref lop) =&gt; { &gt; dest.write_str("fit-content(")?; &gt; lop.to_css(dest)?; &gt; dest.write_str(")") &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl&lt;L: ToComputedValue&gt; ToComputedValue for TrackSize&lt;L&gt; { &gt; type ComputedValue = TrackSize&lt;L::ComputedValue&gt;; &gt; &gt; #[inline] &gt;@@ -288,38 +296,38 @@ impl&lt;L: ToComputedValue&gt; ToComputedValue for TrackSize&lt;L&gt; { &gt; // https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-flex &gt; // FIXME(nox): This sounds false, the spec just says that &lt;flex&gt; &gt; // implies `minmax(auto, &lt;flex&gt;)`, not that it should be changed &gt; // into `minmax` at computed value time. &gt; TrackSize::Minmax( &gt; TrackBreadth::Keyword(TrackKeyword::Auto), &gt; TrackBreadth::Fr(f.to_computed_value(context)), &gt; ) &gt;- }, &gt;+ } &gt; TrackSize::Breadth(ref b) =&gt; TrackSize::Breadth(b.to_computed_value(context)), &gt; TrackSize::Minmax(ref b1, ref b2) =&gt; { &gt; TrackSize::Minmax(b1.to_computed_value(context), b2.to_computed_value(context)) &gt;- }, &gt;+ } &gt; TrackSize::FitContent(ref lop) =&gt; TrackSize::FitContent(lop.to_computed_value(context)), &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; match *computed { &gt; TrackSize::Breadth(ref b) =&gt; { &gt; TrackSize::Breadth(ToComputedValue::from_computed_value(b)) &gt;- }, &gt;+ } &gt; TrackSize::Minmax(ref b1, ref b2) =&gt; TrackSize::Minmax( &gt; ToComputedValue::from_computed_value(b1), &gt; ToComputedValue::from_computed_value(b2), &gt; ), &gt; TrackSize::FitContent(ref lop) =&gt; { &gt; TrackSize::FitContent(ToComputedValue::from_computed_value(lop)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// Helper function for serializing identifiers with a prefix and suffix, used &gt; /// for serializing &lt;line-names&gt; (in grid). &gt; pub fn concat_serialize_idents&lt;W&gt;( &gt; prefix: &amp;str, &gt;@@ -378,18 +386,17 @@ impl Parse for RepeatCount&lt;specified::Integer&gt; { &gt; } &gt; } &gt; } &gt; &gt; /// The structure containing `&lt;line-names&gt;` and `&lt;track-size&gt;` values. &gt; /// &gt; /// It can also hold `repeat()` function parameters, which expands into the respective &gt; /// values in its computed form. &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; #[css(function = "repeat")] &gt; pub struct TrackRepeat&lt;L, I&gt; { &gt; /// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`) &gt; pub count: RepeatCount&lt;I&gt;, &gt; /// `&lt;line-names&gt;` accompanying `&lt;track_size&gt;` values. &gt; /// &gt; /// If there's no `&lt;line-names&gt;`, then it's represented by an empty vector. &gt; /// For N `&lt;track-size&gt;` values, there will be N+1 `&lt;line-names&gt;`, and so this vector's &gt;@@ -404,17 +411,18 @@ impl&lt;L: ToCss, I: ToCss&gt; ToCss for TrackRepeat&lt;L, I&gt; { &gt; where &gt; W: Write, &gt; { &gt; dest.write_str("repeat(")?; &gt; self.count.to_css(dest)?; &gt; dest.write_str(", ")?; &gt; &gt; let mut line_names_iter = self.line_names.iter(); &gt;- for (i, (ref size, ref names)) in self.track_sizes &gt;+ for (i, (ref size, ref names)) in self &gt;+ .track_sizes &gt; .iter() &gt; .zip(&amp;mut line_names_iter) &gt; .enumerate() &gt; { &gt; if i &gt; 0 { &gt; dest.write_str(" ")?; &gt; } &gt; &gt;@@ -466,18 +474,17 @@ impl&lt;L: Clone&gt; TrackRepeat&lt;L, specified::Integer&gt; { &gt; track_sizes: self.track_sizes.clone(), &gt; line_names: self.line_names.clone(), &gt; } &gt; } &gt; } &gt; } &gt; &gt; /// Track list values. Can be &lt;track-size&gt; or &lt;track-repeat&gt; &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub enum TrackListValue&lt;LengthOrPercentage, Integer&gt; { &gt; /// A &lt;track-size&gt; value. &gt; TrackSize(TrackSize&lt;LengthOrPercentage&gt;), &gt; /// A &lt;track-repeat&gt; value. &gt; TrackRepeat(TrackRepeat&lt;LengthOrPercentage, Integer&gt;), &gt; } &gt; &gt; /// The type of a `&lt;track-list&gt;` as determined during parsing. &gt;@@ -544,47 +551,46 @@ impl&lt;L: ToCss, I: ToCss&gt; ToCss for TrackList&lt;L, I&gt; { &gt; &gt; match self.auto_repeat { &gt; Some(ref repeat) if idx == auto_idx =&gt; { &gt; if !names.is_empty() { &gt; dest.write_str(" ")?; &gt; } &gt; &gt; repeat.to_css(dest)?; &gt;- }, &gt;+ } &gt; _ =&gt; match values_iter.next() { &gt; Some(value) =&gt; { &gt; if !names.is_empty() { &gt; dest.write_str(" ")?; &gt; } &gt; &gt; value.to_css(dest)?; &gt;- }, &gt;+ } &gt; None =&gt; break, &gt; }, &gt; } &gt; &gt;- if values_iter.peek().is_some() || &gt;- line_names_iter.peek().map_or(false, |v| !v.is_empty()) || &gt;- (idx + 1 == auto_idx) &gt;+ if values_iter.peek().is_some() &gt;+ || line_names_iter.peek().map_or(false, |v| !v.is_empty()) &gt;+ || (idx + 1 == auto_idx) &gt; { &gt; dest.write_str(" ")?; &gt; } &gt; } &gt; &gt; Ok(()) &gt; } &gt; } &gt; &gt; /// The `&lt;line-name-list&gt;` for subgrids. &gt; /// &gt; /// `subgrid [ &lt;line-names&gt; | repeat(&lt;positive-integer&gt; | auto-fill, &lt;line-names&gt;+) ]+` &gt; /// Old spec: https://www.w3.org/TR/2015/WD-css-grid-1-20150917/#typedef-line-name-list &gt;-#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Debug, Default, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct LineNameList { &gt; /// The optional `&lt;line-name-list&gt;` &gt; pub names: Box&lt;[Box&lt;[CustomIdent]&gt;]&gt;, &gt; /// Indicates the line name that requires `auto-fill` &gt; pub fill_idx: Option&lt;u32&gt;, &gt; } &gt; &gt; impl Parse for LineNameList { &gt;@@ -619,23 +625,25 @@ impl Parse for LineNameList { &gt; .iter() &gt; .cloned() &gt; .cycle() &gt; .take(num.value() as usize * names_list.len()), &gt; ), &gt; RepeatCount::AutoFill if fill_idx.is_none() =&gt; { &gt; // `repeat(autof-fill, ..)` should have just one line name. &gt; if names_list.len() != 1 { &gt;- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt;+ return Err( &gt;+ input.new_custom_error(StyleParseErrorKind::UnspecifiedError) &gt;+ ); &gt; } &gt; let names = names_list.pop().unwrap(); &gt; &gt; line_names.push(names); &gt; fill_idx = Some(line_names.len() as u32 - 1); &gt;- }, &gt;+ } &gt; _ =&gt; return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)), &gt; } &gt; } else if let Ok(names) = input.try(parse_line_names) { &gt; line_names.push(names); &gt; } else { &gt; break; &gt; } &gt; } &gt;@@ -677,18 +685,17 @@ impl ToCss for LineNameList { &gt; &gt; Ok(()) &gt; } &gt; } &gt; &gt; /// Variants for `&lt;grid-template-rows&gt; | &lt;grid-template-columns&gt;` &gt; /// Subgrid deferred to Level 2 spec due to lack of implementation. &gt; /// But it's implemented in gecko, so we have to as well. &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub enum GridTemplateComponent&lt;L, I&gt; { &gt; /// `none` value. &gt; None, &gt; /// The grid `&lt;track-list&gt;` &gt; TrackList(#[compute(field_bound)] TrackList&lt;L, I&gt;), &gt; /// A `subgrid &lt;line-name-list&gt;?` &gt; Subgrid(LineNameList), &gt; } &gt;diff --git a/servo/components/style/values/generics/image.rs b/servo/components/style/values/generics/image.rs &gt;index 2da4d2900398..ccf732f9d517 100644 &gt;--- a/servo/components/style/values/generics/image.rs &gt;+++ b/servo/components/style/values/generics/image.rs &gt;@@ -1,22 +1,22 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for the handling of [images]. &gt; //! &gt; //! [images]: https://drafts.csswg.org/css-images/#image-values &gt; &gt;-use Atom; &gt; use custom_properties; &gt; use servo_arc::Arc; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ToCss}; &gt; use values::serialize_atom_identifier; &gt;+use Atom; &gt; &gt; /// An [image]. &gt; /// &gt; /// [image]: https://drafts.csswg.org/css-images/#image-values &gt; #[derive(Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub enum Image&lt;Gradient, MozImageRect, ImageUrl&gt; { &gt; /// A `&lt;url()&gt;` image. &gt; Url(ImageUrl), &gt;@@ -140,17 +140,17 @@ pub struct PaintWorklet { &gt; /// The name the worklet was registered with. &gt; pub name: Atom, &gt; /// The arguments for the worklet. &gt; /// TODO: store a parsed representation of the arguments. &gt; #[cfg_attr(feature = "servo", ignore_malloc_size_of = "Arc")] &gt; pub arguments: Vec&lt;Arc&lt;custom_properties::SpecifiedValue&gt;&gt;, &gt; } &gt; &gt;-impl ::style_traits::SpecifiedValueInfo for PaintWorklet { } &gt;+impl ::style_traits::SpecifiedValueInfo for PaintWorklet {} &gt; &gt; impl ToCss for PaintWorklet { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; dest.write_str("paint(")?; &gt; serialize_atom_identifier(&amp;self.name, dest)?; &gt;@@ -162,18 +162,17 @@ impl ToCss for PaintWorklet { &gt; } &gt; } &gt; &gt; /// Values for `moz-image-rect`. &gt; /// &gt; /// `-moz-image-rect(&lt;uri&gt;, top, right, bottom, left);` &gt; #[allow(missing_docs)] &gt; #[css(comma, function)] &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub struct MozImageRect&lt;NumberOrPercentage, MozImageRectUrl&gt; { &gt; pub url: MozImageRectUrl, &gt; pub top: NumberOrPercentage, &gt; pub right: NumberOrPercentage, &gt; pub bottom: NumberOrPercentage, &gt; pub left: NumberOrPercentage, &gt; } &gt; &gt;@@ -203,17 +202,17 @@ where &gt; Image::Gradient(ref gradient) =&gt; gradient.to_css(dest), &gt; Image::Rect(ref rect) =&gt; rect.to_css(dest), &gt; #[cfg(feature = "servo")] &gt; Image::PaintWorklet(ref paint_worklet) =&gt; paint_worklet.to_css(dest), &gt; Image::Element(ref selector) =&gt; { &gt; dest.write_str("-moz-element(#")?; &gt; serialize_atom_identifier(selector, dest)?; &gt; dest.write_str(")") &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl&lt;D, L, LoP, P, C, A&gt; ToCss for Gradient&lt;D, L, LoP, P, C, A&gt; &gt; where &gt; D: LineDirection, &gt; L: ToCss, &gt;@@ -224,36 +223,36 @@ where &gt; { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; match self.compat_mode { &gt; CompatMode::WebKit =&gt; dest.write_str("-webkit-")?, &gt; CompatMode::Moz =&gt; dest.write_str("-moz-")?, &gt;- _ =&gt; {}, &gt;+ _ =&gt; {} &gt; } &gt; &gt; if self.repeating { &gt; dest.write_str("repeating-")?; &gt; } &gt; dest.write_str(self.kind.label())?; &gt; dest.write_str("-gradient(")?; &gt; let mut skip_comma = match self.kind { &gt; GradientKind::Linear(ref direction) if direction.points_downwards(self.compat_mode) =&gt; { &gt; true &gt;- }, &gt;+ } &gt; GradientKind::Linear(ref direction) =&gt; { &gt; direction.to_css(dest, self.compat_mode)?; &gt; false &gt;- }, &gt;+ } &gt; GradientKind::Radial(ref shape, ref position, ref angle) =&gt; { &gt; let omit_shape = match *shape { &gt;- EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::Cover)) | &gt;- EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) =&gt; true, &gt;+ EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::Cover)) &gt;+ | EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) =&gt; true, &gt; _ =&gt; false, &gt; }; &gt; if self.compat_mode == CompatMode::Modern { &gt; if !omit_shape { &gt; shape.to_css(dest)?; &gt; dest.write_str(" ")?; &gt; } &gt; dest.write_str("at ")?; &gt;@@ -265,17 +264,17 @@ where &gt; a.to_css(dest)?; &gt; } &gt; if !omit_shape { &gt; dest.write_str(", ")?; &gt; shape.to_css(dest)?; &gt; } &gt; } &gt; false &gt;- }, &gt;+ } &gt; }; &gt; for item in &amp;self.items { &gt; if !skip_comma { &gt; dest.write_str(", ")?; &gt; } &gt; skip_comma = false; &gt; item.to_css(dest)?; &gt; } &gt;@@ -309,17 +308,17 @@ where &gt; { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; match *self { &gt; Circle::Extent(ShapeExtent::FarthestCorner) | Circle::Extent(ShapeExtent::Cover) =&gt; { &gt; dest.write_str("circle") &gt;- }, &gt;+ } &gt; Circle::Extent(keyword) =&gt; { &gt; dest.write_str("circle ")?; &gt; keyword.to_css(dest) &gt;- }, &gt;+ } &gt; Circle::Radius(ref length) =&gt; length.to_css(dest), &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/style/values/generics/mod.rs b/servo/components/style/values/generics/mod.rs &gt;index e6c1befea9f8..056c0e529c4b 100644 &gt;--- a/servo/components/style/values/generics/mod.rs &gt;+++ b/servo/components/style/values/generics/mod.rs &gt;@@ -1,21 +1,21 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types that share their serialization implementations &gt; //! for both specified and computed values. &gt; &gt;+use super::CustomIdent; &gt; use counter_style::{parse_counter_style_name, Symbols}; &gt; use cssparser::Parser; &gt; use parser::{Parse, ParserContext}; &gt; use style_traits::{KeywordsCollectFn, ParseError}; &gt; use style_traits::{SpecifiedValueInfo, StyleParseErrorKind}; &gt;-use super::CustomIdent; &gt; &gt; pub mod background; &gt; pub mod basic_shape; &gt; pub mod border; &gt; #[path = "box.rs"] &gt; pub mod box_; &gt; pub mod color; &gt; pub mod column; &gt;@@ -118,18 +118,18 @@ impl Parse for CounterStyleOrNone { &gt; if input.try(|i| i.expect_function_matching("symbols")).is_ok() { &gt; return input.parse_nested_block(|input| { &gt; let symbols_type = input &gt; .try(|i| SymbolsType::parse(i)) &gt; .unwrap_or(SymbolsType::Symbolic); &gt; let symbols = Symbols::parse(context, input)?; &gt; // There must be at least two symbols for alphabetic or &gt; // numeric system. &gt;- if (symbols_type == SymbolsType::Alphabetic || &gt;- symbols_type == SymbolsType::Numeric) &amp;&amp; symbols.0.len() &lt; 2 &gt;+ if (symbols_type == SymbolsType::Alphabetic || symbols_type == SymbolsType::Numeric) &gt;+ &amp;&amp; symbols.0.len() &lt; 2 &gt; { &gt; return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt; // Identifier is not allowed in symbols() function. &gt; if symbols.0.iter().any(|sym| !sym.is_allowed_in_symbols()) { &gt; return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt; Ok(CounterStyleOrNone::Symbols(symbols_type, symbols)) &gt;@@ -152,19 +152,42 @@ impl SpecifiedValueInfo for CounterStyleOrNone { &gt; } &gt; } &gt; include!("../../counter_style/predefined.rs"); &gt; } &gt; } &gt; &gt; /// A wrapper of Non-negative values. &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, Hash, MallocSizeOf, &gt;- PartialEq, PartialOrd, SpecifiedValueInfo, ToAnimatedZero, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ Hash, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ PartialOrd, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub struct NonNegative&lt;T&gt;(pub T); &gt; &gt; /// A wrapper of greater-than-or-equal-to-one values. &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, PartialOrd, SpecifiedValueInfo, ToAnimatedZero, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ PartialOrd, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub struct GreaterThanOrEqualToOne&lt;T&gt;(pub T); &gt;diff --git a/servo/components/style/values/generics/position.rs b/servo/components/style/values/generics/position.rs &gt;index 67c167c41ab6..83dc48d0905e 100644 &gt;--- a/servo/components/style/values/generics/position.rs &gt;+++ b/servo/components/style/values/generics/position.rs &gt;@@ -1,18 +1,28 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for CSS handling of specified and computed values of &gt; //! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position) &gt; &gt; /// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position). &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+)] &gt; pub struct Position&lt;H, V&gt; { &gt; /// The horizontal component of position. &gt; pub horizontal: H, &gt; /// The vertical component of position. &gt; pub vertical: V, &gt; } &gt; &gt; impl&lt;H, V&gt; Position&lt;H, V&gt; { &gt;@@ -21,18 +31,29 @@ impl&lt;H, V&gt; Position&lt;H, V&gt; { &gt; Self { &gt; horizontal: horizontal, &gt; vertical: vertical, &gt; } &gt; } &gt; } &gt; &gt; /// A generic value for the `z-index` property. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum ZIndex&lt;Integer&gt; { &gt; /// An integer value. &gt; Integer(Integer), &gt; /// The keyword `auto`. &gt; Auto, &gt; } &gt; &gt; impl&lt;Integer&gt; ZIndex&lt;Integer&gt; { &gt;diff --git a/servo/components/style/values/generics/rect.rs b/servo/components/style/values/generics/rect.rs &gt;index fb67e48a3954..510cb75a6f8b 100644 &gt;--- a/servo/components/style/values/generics/rect.rs &gt;+++ b/servo/components/style/values/generics/rect.rs &gt;@@ -6,18 +6,27 @@ &gt; &gt; use cssparser::Parser; &gt; use parser::{Parse, ParserContext}; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ParseError, ToCss}; &gt; &gt; /// A CSS value made of four components, where its `ToCss` impl will try to &gt; /// serialize as few components as possible, like for example in `border-width`. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+)] &gt; pub struct Rect&lt;T&gt;(pub T, pub T, pub T, pub T); &gt; &gt; impl&lt;T&gt; Rect&lt;T&gt; { &gt; /// Returns a new `Rect&lt;T&gt;` value. &gt; pub fn new(first: T, second: T, third: T, fourth: T) -&gt; Self { &gt; Rect(first, second, third, fourth) &gt; } &gt; } &gt;diff --git a/servo/components/style/values/generics/size.rs b/servo/components/style/values/generics/size.rs &gt;index ad93b94e65ee..d7ef5810f05b 100644 &gt;--- a/servo/components/style/values/generics/size.rs &gt;+++ b/servo/components/style/values/generics/size.rs &gt;@@ -8,18 +8,27 @@ use cssparser::Parser; &gt; use euclid::Size2D; &gt; use parser::ParserContext; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss}; &gt; use values::animated::ToAnimatedValue; &gt; &gt; /// A generic size, for `border-*-radius` longhand properties, or &gt; /// `border-spacing`. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, &gt;- ToAnimatedZero, ToComputedValue)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+)] &gt; pub struct Size&lt;L&gt;(pub Size2D&lt;L&gt;); &gt; &gt; impl&lt;L&gt; Size&lt;L&gt; { &gt; #[inline] &gt; /// Create a new `Size` for an area of given width and height. &gt; pub fn new(width: L, height: L) -&gt; Size&lt;L&gt; { &gt; Size(Size2D::new(width, height)) &gt; } &gt;diff --git a/servo/components/style/values/generics/svg.rs b/servo/components/style/values/generics/svg.rs &gt;index 0fbaacf22833..a923f99dcfa4 100644 &gt;--- a/servo/components/style/values/generics/svg.rs &gt;+++ b/servo/components/style/values/generics/svg.rs &gt;@@ -2,43 +2,63 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for CSS values in SVG &gt; &gt; use cssparser::Parser; &gt; use parser::{Parse, ParserContext}; &gt; use style_traits::{ParseError, StyleParseErrorKind}; &gt;-use values::{Either, None_}; &gt;-use values::computed::NumberOrPercentage; &gt; use values::computed::length::LengthOrPercentage; &gt;+use values::computed::NumberOrPercentage; &gt; use values::distance::{ComputeSquaredDistance, SquaredDistance}; &gt;+use values::{Either, None_}; &gt; &gt; /// An SVG paint value &gt; /// &gt; /// &lt;https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint&gt; &gt; #[animation(no_bound(UrlPaintServer))] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub struct SVGPaint&lt;ColorType, UrlPaintServer&gt; { &gt; /// The paint source &gt; pub kind: SVGPaintKind&lt;ColorType, UrlPaintServer&gt;, &gt; /// The fallback color. It would be empty, the `none` keyword or &lt;color&gt;. &gt; pub fallback: Option&lt;Either&lt;ColorType, None_&gt;&gt;, &gt; } &gt; &gt; /// An SVG paint value without the fallback &gt; /// &gt; /// Whereas the spec only allows PaintServer &gt; /// to have a fallback, Gecko lets the context &gt; /// properties have a fallback as well. &gt; #[animation(no_bound(UrlPaintServer))] &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue, &gt;- ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum SVGPaintKind&lt;ColorType, UrlPaintServer&gt; { &gt; /// `none` &gt; #[animation(error)] &gt; None, &gt; /// `&lt;color&gt;` &gt; Color(ColorType), &gt; /// `url(...)` &gt; #[animation(error)] &gt;@@ -108,18 +128,28 @@ impl&lt;ColorType: Parse, UrlPaintServer: Parse&gt; Parse for SVGPaint&lt;ColorType, UrlP &gt; } else { &gt; Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt; } &gt; } &gt; } &gt; &gt; /// A value of &lt;length&gt; | &lt;percentage&gt; | &lt;number&gt; for svg which allow unitless length. &gt; /// &lt;https://www.w3.org/TR/SVG11/painting.html#StrokeProperties&gt; &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum SvgLengthOrPercentageOrNumber&lt;LengthOrPercentage, Number&gt; { &gt; /// &lt;length&gt; | &lt;percentage&gt; &gt; LengthOrPercentage(LengthOrPercentage), &gt; /// &lt;number&gt; &gt; Number(Number), &gt; } &gt; &gt; impl&lt;L, N&gt; ComputeSquaredDistance for SvgLengthOrPercentageOrNumber&lt;L, N&gt; &gt;@@ -159,17 +189,17 @@ where &gt; /// return true if this struct has calc value. &gt; pub fn has_calc(&amp;self) -&gt; bool { &gt; match self { &gt; &amp;SvgLengthOrPercentageOrNumber::LengthOrPercentage(lop) =&gt; { &gt; match LengthOrPercentage::from(lop) { &gt; LengthOrPercentage::Calc(_) =&gt; true, &gt; _ =&gt; false, &gt; } &gt;- }, &gt;+ } &gt; _ =&gt; false, &gt; } &gt; } &gt; } &gt; &gt; /// Parsing the SvgLengthOrPercentageOrNumber. At first, we need to parse number &gt; /// since prevent converting to the length. &gt; impl&lt;LengthOrPercentageType: Parse, NumberType: Parse&gt; Parse &gt;@@ -186,44 +216,69 @@ impl&lt;LengthOrPercentageType: Parse, NumberType: Parse&gt; Parse &gt; if let Ok(lop) = input.try(|i| LengthOrPercentageType::parse(context, i)) { &gt; return Ok(SvgLengthOrPercentageOrNumber::LengthOrPercentage(lop)); &gt; } &gt; Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt; } &gt; } &gt; &gt; /// An SVG length value supports `context-value` in addition to length. &gt;-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue, &gt;- ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum SVGLength&lt;LengthType&gt; { &gt; /// `&lt;length&gt; | &lt;percentage&gt; | &lt;number&gt;` &gt; Length(LengthType), &gt; /// `context-value` &gt; ContextValue, &gt; } &gt; &gt; /// Generic value for stroke-dasharray. &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum SVGStrokeDashArray&lt;LengthType&gt; { &gt; /// `[ &lt;length&gt; | &lt;percentage&gt; | &lt;number&gt; ]#` &gt; #[css(comma)] &gt;- Values( &gt;- #[css(if_empty = "none", iterable)] &gt;- Vec&lt;LengthType&gt;, &gt;- ), &gt;+ Values(#[css(if_empty = "none", iterable)] Vec&lt;LengthType&gt;), &gt; /// `context-value` &gt; ContextValue, &gt; } &gt; &gt; /// An SVG opacity value accepts `context-{fill,stroke}-opacity` in &gt; /// addition to opacity value. &gt;-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum SVGOpacity&lt;OpacityType&gt; { &gt; /// `&lt;opacity-value&gt;` &gt; Opacity(OpacityType), &gt; /// `context-fill-opacity` &gt; ContextFillOpacity, &gt; /// `context-stroke-opacity` &gt; ContextStrokeOpacity, &gt; } &gt;diff --git a/servo/components/style/values/generics/text.rs b/servo/components/style/values/generics/text.rs &gt;index 6cc5caaac777..e85c444a6956 100644 &gt;--- a/servo/components/style/values/generics/text.rs &gt;+++ b/servo/components/style/values/generics/text.rs &gt;@@ -7,36 +7,38 @@ &gt; use app_units::Au; &gt; use cssparser::Parser; &gt; use parser::ParserContext; &gt; use style_traits::ParseError; &gt; use values::animated::{Animate, Procedure, ToAnimatedZero}; &gt; use values::distance::{ComputeSquaredDistance, SquaredDistance}; &gt; &gt; /// A generic value for the `initial-letter` property. &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; pub enum InitialLetter&lt;Number, Integer&gt; { &gt; /// `normal` &gt; Normal, &gt; /// `&lt;number&gt; &lt;integer&gt;?` &gt; Specified(Number, Option&lt;Integer&gt;), &gt; } &gt; &gt; impl&lt;N, I&gt; InitialLetter&lt;N, I&gt; { &gt; /// Returns `normal`. &gt; #[inline] &gt; pub fn normal() -&gt; Self { &gt; InitialLetter::Normal &gt; } &gt; } &gt; &gt; /// A generic spacing value for the `letter-spacing` and `word-spacing` properties. &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; pub enum Spacing&lt;Value&gt; { &gt; /// `normal` &gt; Normal, &gt; /// `&lt;value&gt;` &gt; Value(Value), &gt; } &gt; &gt; impl&lt;Value&gt; Spacing&lt;Value&gt; { &gt;@@ -107,18 +109,28 @@ where &gt; { &gt; #[inline] &gt; fn to_animated_zero(&amp;self) -&gt; Result&lt;Self, ()&gt; { &gt; Err(()) &gt; } &gt; } &gt; &gt; /// A generic value for the `line-height` property. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum LineHeight&lt;Number, LengthOrPercentage&gt; { &gt; /// `normal` &gt; Normal, &gt; /// `-moz-block-height` &gt; #[cfg(feature = "gecko")] &gt; MozBlockHeight, &gt; /// `&lt;number&gt;` &gt; Number(Number), &gt;@@ -137,17 +149,28 @@ impl&lt;N, L&gt; LineHeight&lt;N, L&gt; { &gt; /// Returns `normal`. &gt; #[inline] &gt; pub fn normal() -&gt; Self { &gt; LineHeight::Normal &gt; } &gt; } &gt; &gt; /// A generic value for the `-moz-tab-size` property. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum MozTabSize&lt;Number, Length&gt; { &gt; /// A number. &gt; Number(Number), &gt; /// A length. &gt; Length(Length), &gt; } &gt;diff --git a/servo/components/style/values/generics/transform.rs b/servo/components/style/values/generics/transform.rs &gt;index a0cbc57d6b43..fc81617bfc73 100644 &gt;--- a/servo/components/style/values/generics/transform.rs &gt;+++ b/servo/components/style/values/generics/transform.rs &gt;@@ -2,26 +2,27 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic types for CSS values that are related to transformations. &gt; &gt; use app_units::Au; &gt; use euclid::{self, Rect, Transform3D}; &gt; use num_traits::Zero; &gt;-use values::{computed, CSSFloat}; &gt; use values::computed::length::Length as ComputedLength; &gt; use values::computed::length::LengthOrPercentage as ComputedLengthOrPercentage; &gt; use values::specified::length::Length as SpecifiedLength; &gt; use values::specified::length::LengthOrPercentage as SpecifiedLengthOrPercentage; &gt;+use values::{computed, CSSFloat}; &gt; &gt; /// A generic 2D transformation matrix. &gt; #[allow(missing_docs)] &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; #[css(comma, function)] &gt; pub struct Matrix&lt;T&gt; { &gt; pub a: T, &gt; pub b: T, &gt; pub c: T, &gt; pub d: T, &gt; pub e: T, &gt; pub f: T, &gt;@@ -61,32 +62,42 @@ impl&lt;T: Into&lt;f64&gt;&gt; From&lt;Matrix3D&lt;T&gt;&gt; for Transform3D&lt;f64&gt; { &gt; m.m21.into(), m.m22.into(), m.m23.into(), m.m24.into(), &gt; m.m31.into(), m.m32.into(), m.m33.into(), m.m34.into(), &gt; m.m41.into(), m.m42.into(), m.m43.into(), m.m44.into(), &gt; ) &gt; } &gt; } &gt; &gt; /// A generic transform origin. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, &gt;- PartialEq, SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub struct TransformOrigin&lt;H, V, Depth&gt; { &gt; /// The horizontal origin. &gt; pub horizontal: H, &gt; /// The vertical origin. &gt; pub vertical: V, &gt; /// The depth. &gt; pub depth: Depth, &gt; } &gt; &gt; /// A generic timing function. &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-timing-1/#single-timing-function-production&gt; &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToCss)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] &gt; #[value_info(ty = "TIMING_FUNCTION")] &gt; pub enum TimingFunction&lt;Integer, Number&gt; { &gt; /// `linear | ease | ease-in | ease-out | ease-in-out` &gt; Keyword(TimingKeyword), &gt; /// `cubic-bezier(&lt;number&gt;, &lt;number&gt;, &lt;number&gt;, &lt;number&gt;)` &gt; #[allow(missing_docs)] &gt; #[css(comma, function)] &gt; CubicBezier { &gt;@@ -101,18 +112,28 @@ pub enum TimingFunction&lt;Integer, Number&gt; { &gt; Steps(Integer, #[css(skip_if = "is_end")] StepPosition), &gt; /// `frames(&lt;integer&gt;)` &gt; #[css(comma, function)] &gt; Frames(Integer), &gt; } &gt; &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum TimingKeyword { &gt; Linear, &gt; Ease, &gt; EaseIn, &gt; EaseOut, &gt; EaseInOut, &gt; } &gt; &gt;@@ -158,18 +179,17 @@ impl TimingKeyword { &gt; TimingKeyword::Ease =&gt; (0.25, 0.1, 0.25, 1.), &gt; TimingKeyword::EaseIn =&gt; (0.42, 0., 1., 1.), &gt; TimingKeyword::EaseOut =&gt; (0., 0., 0.58, 1.), &gt; TimingKeyword::EaseInOut =&gt; (0.42, 0., 0.58, 1.), &gt; } &gt; } &gt; } &gt; &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; /// A single operation in the list of a `transform` value &gt; pub enum TransformOperation&lt;Angle, Number, Length, Integer, LengthOrPercentage&gt; { &gt; /// Represents a 2D 2x3 matrix. &gt; Matrix(Matrix&lt;Number&gt;), &gt; /// Represents a 3D 4x4 matrix. &gt; Matrix3D(Matrix3D&lt;Number&gt;), &gt; /// A 2D skew. &gt; /// &gt;@@ -263,44 +283,39 @@ pub enum TransformOperation&lt;Angle, Number, Length, Integer, LengthOrPercentage&gt; &gt; AccumulateMatrix { &gt; from_list: &gt; Transform&lt;TransformOperation&lt;Angle, Number, Length, Integer, LengthOrPercentage&gt;&gt;, &gt; to_list: Transform&lt;TransformOperation&lt;Angle, Number, Length, Integer, LengthOrPercentage&gt;&gt;, &gt; count: Integer, &gt; }, &gt; } &gt; &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; /// A value of the `transform` property &gt; pub struct Transform&lt;T&gt;(#[css(if_empty = "none", iterable)] pub Vec&lt;T&gt;); &gt; &gt; impl&lt;Angle, Number, Length, Integer, LengthOrPercentage&gt; &gt; TransformOperation&lt;Angle, Number, Length, Integer, LengthOrPercentage&gt; &gt; { &gt; /// Check if it is any rotate function. &gt; pub fn is_rotate(&amp;self) -&gt; bool { &gt; use self::TransformOperation::*; &gt; matches!( &gt; *self, &gt;- Rotate(..) | &gt;- Rotate3D(..) | &gt;- RotateX(..) | &gt;- RotateY(..) | &gt;- RotateZ(..) &gt;+ Rotate(..) | Rotate3D(..) | RotateX(..) | RotateY(..) | RotateZ(..) &gt; ) &gt; } &gt; &gt; /// Check if it is any translate function &gt; pub fn is_translate(&amp;self) -&gt; bool { &gt; use self::TransformOperation::*; &gt; match *self { &gt; Translate(..) | Translate3D(..) | TranslateX(..) | TranslateY(..) | TranslateZ(..) =&gt; { &gt; true &gt;- }, &gt;+ } &gt; _ =&gt; false, &gt; } &gt; } &gt; &gt; /// Check if it is any scale function &gt; pub fn is_scale(&amp;self) -&gt; bool { &gt; use self::TransformOperation::*; &gt; match *self { &gt;@@ -386,18 +401,18 @@ where &gt; Number: Copy + Into&lt;f32&gt; + Into&lt;f64&gt;, &gt; Length: ToAbsoluteLength, &gt; LoP: ToAbsoluteLength, &gt; { &gt; #[inline] &gt; fn is_3d(&amp;self) -&gt; bool { &gt; use self::TransformOperation::*; &gt; match *self { &gt;- Translate3D(..) | TranslateZ(..) | Rotate3D(..) | RotateX(..) | RotateY(..) | &gt;- RotateZ(..) | Scale3D(..) | ScaleZ(..) | Perspective(..) | Matrix3D(..) =&gt; true, &gt;+ Translate3D(..) | TranslateZ(..) | Rotate3D(..) | RotateX(..) | RotateY(..) &gt;+ | RotateZ(..) | Scale3D(..) | ScaleZ(..) | Perspective(..) | Matrix3D(..) =&gt; true, &gt; _ =&gt; false, &gt; } &gt; } &gt; &gt; /// If |reference_box| is None, we will drop the percent part from translate because &gt; /// we cannot resolve it without the layout info, for computed TransformOperation. &gt; /// However, for specified TransformOperation, we will return Err(()) if there is any relative &gt; /// lengths because the only caller, DOMMatrix, doesn't accept relative lengths. &gt;@@ -415,59 +430,59 @@ where &gt; let (ax, ay, az, theta) = &gt; get_normalized_vector_and_angle(ax.into(), ay.into(), az.into(), theta); &gt; Transform3D::create_rotation( &gt; ax as f64, &gt; ay as f64, &gt; az as f64, &gt; euclid::Angle::radians(theta), &gt; ) &gt;- }, &gt;+ } &gt; RotateX(theta) =&gt; { &gt; let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64()); &gt; Transform3D::create_rotation(1., 0., 0., theta) &gt;- }, &gt;+ } &gt; RotateY(theta) =&gt; { &gt; let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64()); &gt; Transform3D::create_rotation(0., 1., 0., theta) &gt;- }, &gt;+ } &gt; RotateZ(theta) | Rotate(theta) =&gt; { &gt; let theta = euclid::Angle::radians(TWO_PI - theta.as_ref().radians64()); &gt; Transform3D::create_rotation(0., 0., 1., theta) &gt;- }, &gt;+ } &gt; Perspective(ref d) =&gt; { &gt; let m = create_perspective_matrix(d.to_pixel_length(None)?); &gt; m.cast() &gt;- }, &gt;+ } &gt; Scale3D(sx, sy, sz) =&gt; Transform3D::create_scale(sx.into(), sy.into(), sz.into()), &gt; Scale(sx, sy) =&gt; Transform3D::create_scale(sx.into(), sy.unwrap_or(sx).into(), 1.), &gt; ScaleX(s) =&gt; Transform3D::create_scale(s.into(), 1., 1.), &gt; ScaleY(s) =&gt; Transform3D::create_scale(1., s.into(), 1.), &gt; ScaleZ(s) =&gt; Transform3D::create_scale(1., 1., s.into()), &gt; Translate3D(ref tx, ref ty, ref tz) =&gt; { &gt; let tx = tx.to_pixel_length(reference_width)? as f64; &gt; let ty = ty.to_pixel_length(reference_height)? as f64; &gt; Transform3D::create_translation(tx, ty, tz.to_pixel_length(None)? as f64) &gt;- }, &gt;+ } &gt; Translate(ref tx, Some(ref ty)) =&gt; { &gt; let tx = tx.to_pixel_length(reference_width)? as f64; &gt; let ty = ty.to_pixel_length(reference_height)? as f64; &gt; Transform3D::create_translation(tx, ty, 0.) &gt;- }, &gt;+ } &gt; TranslateX(ref t) | Translate(ref t, None) =&gt; { &gt; let t = t.to_pixel_length(reference_width)? as f64; &gt; Transform3D::create_translation(t, 0., 0.) &gt;- }, &gt;+ } &gt; TranslateY(ref t) =&gt; { &gt; let t = t.to_pixel_length(reference_height)? as f64; &gt; Transform3D::create_translation(0., t, 0.) &gt;- }, &gt;+ } &gt; TranslateZ(ref z) =&gt; { &gt; Transform3D::create_translation(0., 0., z.to_pixel_length(None)? as f64) &gt;- }, &gt;+ } &gt; Skew(theta_x, theta_y) =&gt; Transform3D::create_skew( &gt; euclid::Angle::radians(theta_x.as_ref().radians64()), &gt; euclid::Angle::radians(theta_y.map_or(0., |a| a.as_ref().radians64())), &gt; ), &gt; SkewX(theta) =&gt; Transform3D::create_skew( &gt; euclid::Angle::radians(theta.as_ref().radians64()), &gt; euclid::Angle::radians(0.), &gt; ), &gt;@@ -480,17 +495,17 @@ where &gt; InterpolateMatrix { .. } | AccumulateMatrix { .. } =&gt; { &gt; // TODO: Convert InterpolateMatrix/AccumulateMatrix into a valid Transform3D by &gt; // the reference box and do interpolation on these two Transform3D matrices. &gt; // Both Gecko and Servo don't support this for computing distance, and Servo &gt; // doesn't support animations on InterpolateMatrix/AccumulateMatrix, so &gt; // return an identity matrix. &gt; // Note: DOMMatrix doesn't go into this arm. &gt; Transform3D::identity() &gt;- }, &gt;+ } &gt; }; &gt; Ok(matrix) &gt; } &gt; } &gt; &gt; impl&lt;T&gt; Transform&lt;T&gt; { &gt; /// `none` &gt; pub fn none() -&gt; Self { &gt;@@ -569,64 +584,94 @@ pub fn get_normalized_vector_and_angle&lt;T: Zero&gt;( &gt; // rotation to not be applied, so we use identity matrix (i.e. rotate3d(0, 0, 1, 0)). &gt; (0., 0., 1., T::zero()) &gt; } else { &gt; let vector = vector.robust_normalize(); &gt; (vector.x, vector.y, vector.z, angle) &gt; } &gt; } &gt; &gt;-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; /// A value of the `Rotate` property &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-transforms-2/#individual-transforms&gt; &gt; pub enum Rotate&lt;Number, Angle&gt; { &gt; /// 'none' &gt; None, &gt; /// '&lt;angle&gt;' &gt; Rotate(Angle), &gt; /// '&lt;number&gt;{3} &lt;angle&gt;' &gt; Rotate3D(Number, Number, Number, Angle), &gt; } &gt; &gt;-#[derive(Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; /// A value of the `Scale` property &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-transforms-2/#individual-transforms&gt; &gt; pub enum Scale&lt;Number&gt; { &gt; /// 'none' &gt; None, &gt; /// '&lt;number&gt;' &gt; ScaleX(Number), &gt; /// '&lt;number&gt;{2}' &gt; Scale(Number, Number), &gt; /// '&lt;number&gt;{3}' &gt; Scale3D(Number, Number, Number), &gt; } &gt; &gt;-#[derive(Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedZero, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; /// A value of the `Translate` property &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-transforms-2/#individual-transforms&gt; &gt; pub enum Translate&lt;LengthOrPercentage, Length&gt; { &gt; /// 'none' &gt; None, &gt; /// '&lt;length-percentage&gt;' &gt; TranslateX(LengthOrPercentage), &gt; /// '&lt;length-percentage&gt; &lt;length-percentage&gt;' &gt; Translate(LengthOrPercentage, LengthOrPercentage), &gt; /// '&lt;length-percentage&gt; &lt;length-percentage&gt; &lt;length&gt;' &gt; Translate3D(LengthOrPercentage, LengthOrPercentage, Length), &gt; } &gt; &gt; #[allow(missing_docs)] &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; pub enum TransformStyle { &gt; #[cfg(feature = "servo")] &gt; Auto, &gt; Flat, &gt; #[css(keyword = "preserve-3d")] &gt; Preserve3d, &gt; } &gt;diff --git a/servo/components/style/values/generics/ui.rs b/servo/components/style/values/generics/ui.rs &gt;index 9ccf1f80d537..68841c82778c 100644 &gt;--- a/servo/components/style/values/generics/ui.rs &gt;+++ b/servo/components/style/values/generics/ui.rs &gt;@@ -1,23 +1,22 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Generic values for UI properties. &gt; &gt; use std::fmt::{self, Write}; &gt;-use style_traits::{CssWriter, ToCss}; &gt; use style_traits::cursor::CursorKind; &gt;+use style_traits::{CssWriter, ToCss}; &gt; &gt; /// A generic value for the `cursor` property. &gt; /// &gt; /// https://drafts.csswg.org/css-ui/#cursor &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct Cursor&lt;Image&gt; { &gt; /// The parsed images for the cursor. &gt; pub images: Box&lt;[Image]&gt;, &gt; /// The kind of the cursor [default | help | ...]. &gt; pub keyword: CursorKind, &gt; } &gt; &gt; impl&lt;Image&gt; Cursor&lt;Image&gt; { &gt;@@ -40,18 +39,17 @@ impl&lt;Image: ToCss&gt; ToCss for Cursor&lt;Image&gt; { &gt; image.to_css(dest)?; &gt; dest.write_str(", ")?; &gt; } &gt; self.keyword.to_css(dest) &gt; } &gt; } &gt; &gt; /// A generic value for item of `image cursors`. &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct CursorImage&lt;ImageUrl, Number&gt; { &gt; /// The url to parse images from. &gt; pub url: ImageUrl, &gt; /// The &lt;x&gt; and &lt;y&gt; coordinates. &gt; pub hotspot: Option&lt;(Number, Number)&gt;, &gt; } &gt; &gt; impl&lt;ImageUrl: ToCss, Number: ToCss&gt; ToCss for CursorImage&lt;ImageUrl, Number&gt; { &gt;diff --git a/servo/components/style/values/generics/url.rs b/servo/components/style/values/generics/url.rs &gt;index 5da74a7b0874..ff9fa16d6655 100644 &gt;--- a/servo/components/style/values/generics/url.rs &gt;+++ b/servo/components/style/values/generics/url.rs &gt;@@ -4,19 +4,29 @@ &gt; &gt; //! Generic types for url properties. &gt; &gt; use cssparser::Parser; &gt; use parser::{Parse, ParserContext}; &gt; use style_traits::ParseError; &gt; &gt; /// An image url or none, used for example in list-style-image &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Debug, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue, &gt;- ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Debug, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum UrlOrNone&lt;Url&gt; { &gt; /// `none` &gt; None, &gt; /// `A URL` &gt; Url(Url), &gt; } &gt; &gt; impl&lt;Url&gt; UrlOrNone&lt;Url&gt; { &gt;diff --git a/servo/components/style/values/mod.rs b/servo/components/style/values/mod.rs &gt;index a5f8d0abd32e..f182477e374a 100644 &gt;--- a/servo/components/style/values/mod.rs &gt;+++ b/servo/components/style/values/mod.rs &gt;@@ -3,29 +3,31 @@ &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Common [values][values] used in CSS. &gt; //! &gt; //! [values]: https://drafts.csswg.org/css-values/ &gt; &gt; #![deny(missing_docs)] &gt; &gt;-use Atom; &gt;-pub use cssparser::{serialize_identifier, serialize_name, CowRcStr, Parser, SourceLocation, Token, RGBA}; &gt;+pub use cssparser::{ &gt;+ serialize_identifier, serialize_name, CowRcStr, Parser, SourceLocation, Token, RGBA, &gt;+}; &gt; use parser::{Parse, ParserContext}; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use std::fmt::{self, Debug, Write}; &gt; use std::hash; &gt; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt; use values::distance::{ComputeSquaredDistance, SquaredDistance}; &gt;+use Atom; &gt; &gt;-#[cfg(feature = "servo")] &gt;-pub use servo::url::CssUrl; &gt; #[cfg(feature = "gecko")] &gt; pub use gecko::url::CssUrl; &gt;+#[cfg(feature = "servo")] &gt;+pub use servo::url::CssUrl; &gt; &gt; pub mod animated; &gt; pub mod computed; &gt; pub mod distance; &gt; pub mod generics; &gt; pub mod specified; &gt; &gt; /// A CSS float value. &gt;@@ -87,18 +89,23 @@ pub fn serialize_percentage&lt;W&gt;(value: CSSFloat, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt: &gt; where &gt; W: Write, &gt; { &gt; (value * 100.).to_css(dest)?; &gt; dest.write_str("%") &gt; } &gt; &gt; /// Convenience void type to disable some properties and values through types. &gt;-#[cfg_attr(feature = "servo", derive(Deserialize, MallocSizeOf, Serialize))] &gt;-#[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss)] &gt;+#[cfg_attr( &gt;+ feature = "servo", &gt;+ derive(Deserialize, MallocSizeOf, Serialize) &gt;+)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToComputedValue, ToCss, &gt;+)] &gt; pub enum Impossible {} &gt; &gt; // FIXME(nox): This should be derived but the derive code cannot cope &gt; // with uninhabited enums. &gt; impl ComputeSquaredDistance for Impossible { &gt; #[inline] &gt; fn compute_squared_distance(&amp;self, _other: &amp;Self) -&gt; Result&lt;SquaredDistance, ()&gt; { &gt; match *self {} &gt;@@ -110,19 +117,29 @@ impl Parse for Impossible { &gt; _context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt; } &gt; } &gt; &gt; /// A struct representing one of two kinds of values. &gt;-#[derive(Animate, Clone, ComputeSquaredDistance, Copy, MallocSizeOf, PartialEq, &gt;- SpecifiedValueInfo, ToAnimatedValue, ToAnimatedZero, ToComputedValue, &gt;- ToCss)] &gt;+#[derive( &gt;+ Animate, &gt;+ Clone, &gt;+ ComputeSquaredDistance, &gt;+ Copy, &gt;+ MallocSizeOf, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToAnimatedValue, &gt;+ ToAnimatedZero, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum Either&lt;A, B&gt; { &gt; /// The first value. &gt; First(A), &gt; /// The second kind of value. &gt; Second(B), &gt; } &gt; &gt; impl&lt;A: Debug, B: Debug&gt; Debug for Either&lt;A, B&gt; { &gt;@@ -143,33 +160,34 @@ impl&lt;A: Parse, B: Parse&gt; Parse for Either&lt;A, B&gt; { &gt; Ok(Either::First(v)) &gt; } else { &gt; B::parse(context, input).map(Either::Second) &gt; } &gt; } &gt; } &gt; &gt; /// &lt;https://drafts.csswg.org/css-values-4/#custom-idents&gt; &gt;-#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct CustomIdent(pub Atom); &gt; &gt; impl CustomIdent { &gt; /// Parse an already-tokenizer identifier &gt; pub fn from_ident&lt;'i&gt;( &gt; location: SourceLocation, &gt; ident: &amp;CowRcStr&lt;'i&gt;, &gt; excluding: &amp;[&amp;str], &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let valid = match_ignore_ascii_case! { ident, &gt; "initial" | "inherit" | "unset" | "default" =&gt; false, &gt; _ =&gt; true &gt; }; &gt; if !valid { &gt;- return Err(location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))); &gt;+ return Err( &gt;+ location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())) &gt;+ ); &gt; } &gt; if excluding.iter().any(|s| ident.eq_ignore_ascii_case(s)) { &gt; Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt; } else { &gt; Ok(CustomIdent(Atom::from(ident.as_ref()))) &gt; } &gt; } &gt; } &gt;diff --git a/servo/components/style/values/specified/align.rs b/servo/components/style/values/specified/align.rs &gt;index 731844bcb52c..780ab60edb76 100644 &gt;--- a/servo/components/style/values/specified/align.rs &gt;+++ b/servo/components/style/values/specified/align.rs &gt;@@ -85,23 +85,23 @@ impl ToCss for AlignFlags { &gt; &gt; match extra_flags { &gt; AlignFlags::LEGACY =&gt; { &gt; dest.write_str("legacy")?; &gt; if value.is_empty() { &gt; return Ok(()); &gt; } &gt; dest.write_char(' ')?; &gt;- }, &gt;+ } &gt; AlignFlags::SAFE =&gt; dest.write_str("safe ")?, &gt; // Don't serialize "unsafe", since it's the default. &gt;- AlignFlags::UNSAFE =&gt; {}, &gt;+ AlignFlags::UNSAFE =&gt; {} &gt; _ =&gt; { &gt; debug_assert_eq!(extra_flags, AlignFlags::empty()); &gt;- }, &gt;+ } &gt; } &gt; &gt; dest.write_str(match value { &gt; AlignFlags::AUTO =&gt; "auto", &gt; AlignFlags::NORMAL =&gt; "normal", &gt; AlignFlags::START =&gt; "start", &gt; AlignFlags::END =&gt; "end", &gt; AlignFlags::FLEX_START =&gt; "flex-start", &gt;@@ -678,18 +678,23 @@ fn parse_self_position&lt;'i, 't&gt;( &gt; "self-end" =&gt; AlignFlags::SELF_END, &gt; "left" if axis == AxisDirection::Inline =&gt; AlignFlags::LEFT, &gt; "right" if axis == AxisDirection::Inline =&gt; AlignFlags::RIGHT, &gt; }) &gt; } &gt; &gt; fn list_self_position_keywords(f: KeywordsCollectFn, axis: AxisDirection) { &gt; f(&amp;[ &gt;- "start", "end", "flex-start", "flex-end", &gt;- "center", "self-start", "self-end", &gt;+ "start", &gt;+ "end", &gt;+ "flex-start", &gt;+ "flex-end", &gt;+ "center", &gt;+ "self-start", &gt;+ "self-end", &gt; ]); &gt; if axis == AxisDirection::Inline { &gt; f(&amp;["left", "right"]); &gt; } &gt; } &gt; &gt; fn parse_left_right_center&lt;'i, 't&gt;( &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt;diff --git a/servo/components/style/values/specified/angle.rs b/servo/components/style/values/specified/angle.rs &gt;index 040ea9d9a7c8..e10f8cc5f142 100644 &gt;--- a/servo/components/style/values/specified/angle.rs &gt;+++ b/servo/components/style/values/specified/angle.rs &gt;@@ -3,20 +3,20 @@ &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Specified angles. &gt; &gt; use cssparser::{Parser, Token}; &gt; use parser::{Parse, ParserContext}; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss}; &gt;-use values::CSSFloat; &gt;-use values::computed::{Context, ToComputedValue}; &gt; use values::computed::angle::Angle as ComputedAngle; &gt;+use values::computed::{Context, ToComputedValue}; &gt; use values::specified::calc::CalcNode; &gt;+use values::CSSFloat; &gt; &gt; /// A specified angle. &gt; /// &gt; /// Computed angles are essentially same as specified ones except for `calc()` &gt; /// value serialization. Therefore we are storing a computed angle inside &gt; /// to hold the actual value and its unit. &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt; #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)] &gt;@@ -186,22 +186,22 @@ impl Angle { &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; // FIXME: remove clone() when lifetimes are non-lexical &gt; let token = input.next()?.clone(); &gt; match token { &gt; Token::Dimension { &gt; value, ref unit, .. &gt; } =&gt; { &gt; Angle::parse_dimension(value, unit, /* from_calc = */ false) &gt;- }, &gt;+ } &gt; Token::Number { value, .. } if value == 0. =&gt; match allow_unitless_zero { &gt; AllowUnitlessZeroAngle::Yes =&gt; Ok(Angle::zero()), &gt; AllowUnitlessZeroAngle::No =&gt; Err(()), &gt; }, &gt; Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; { &gt; return input.parse_nested_block(|i| CalcNode::parse_angle(context, i)) &gt;- }, &gt;+ } &gt; _ =&gt; Err(()), &gt; }.map_err(|()| input.new_unexpected_token_error(token.clone())) &gt; } &gt; } &gt; &gt; impl SpecifiedValueInfo for Angle {} &gt;diff --git a/servo/components/style/values/specified/background.rs b/servo/components/style/values/specified/background.rs &gt;index d7c4ec629cad..93c39f81ebd1 100644 &gt;--- a/servo/components/style/values/specified/background.rs &gt;+++ b/servo/components/style/values/specified/background.rs &gt;@@ -38,31 +38,40 @@ impl BackgroundSize { &gt; GenericBackgroundSize::Explicit { &gt; width: NonNegativeLengthOrPercentageOrAuto::auto(), &gt; height: NonNegativeLengthOrPercentageOrAuto::auto(), &gt; } &gt; } &gt; } &gt; &gt; /// One of the keywords for `background-repeat`. &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; #[allow(missing_docs)] &gt; pub enum BackgroundRepeatKeyword { &gt; Repeat, &gt; Space, &gt; Round, &gt; NoRepeat, &gt; } &gt; &gt; /// The specified value for the `background-repeat` property. &gt; /// &gt; /// https://drafts.csswg.org/css-backgrounds/#the-background-repeat &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToCss)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] &gt; pub enum BackgroundRepeat { &gt; /// `repeat-x` &gt; RepeatX, &gt; /// `repeat-y` &gt; RepeatY, &gt; /// `[repeat | space | round | no-repeat]{1,2}` &gt; Keywords(BackgroundRepeatKeyword, Option&lt;BackgroundRepeatKeyword&gt;), &gt; } &gt;@@ -86,16 +95,18 @@ impl Parse for BackgroundRepeat { &gt; "repeat-x" =&gt; return Ok(BackgroundRepeat::RepeatX), &gt; "repeat-y" =&gt; return Ok(BackgroundRepeat::RepeatY), &gt; _ =&gt; {}, &gt; } &gt; &gt; let horizontal = match BackgroundRepeatKeyword::from_ident(&amp;ident) { &gt; Ok(h) =&gt; h, &gt; Err(()) =&gt; { &gt;- return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))); &gt;- }, &gt;+ return Err( &gt;+ input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())) &gt;+ ); &gt;+ } &gt; }; &gt; &gt; let vertical = input.try(BackgroundRepeatKeyword::parse).ok(); &gt; Ok(BackgroundRepeat::Keywords(horizontal, vertical)) &gt; } &gt; } &gt;diff --git a/servo/components/style/values/specified/basic_shape.rs b/servo/components/style/values/specified/basic_shape.rs &gt;index 23ae91d564e5..6c1872f37754 100644 &gt;--- a/servo/components/style/values/specified/basic_shape.rs &gt;+++ b/servo/components/style/values/specified/basic_shape.rs &gt;@@ -11,22 +11,22 @@ use cssparser::Parser; &gt; use parser::{Parse, ParserContext}; &gt; use std::borrow::Cow; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt; use values::computed::Percentage; &gt; use values::generics::basic_shape as generic; &gt; use values::generics::basic_shape::{FillRule, GeometryBox, ShapeBox, ShapeSource}; &gt; use values::generics::rect::Rect; &gt;-use values::specified::LengthOrPercentage; &gt; use values::specified::border::BorderRadius; &gt; use values::specified::image::Image; &gt; use values::specified::position::{HorizontalPosition, Position, PositionComponent}; &gt; use values::specified::position::{Side, VerticalPosition}; &gt; use values::specified::url::SpecifiedUrl; &gt;+use values::specified::LengthOrPercentage; &gt; &gt; /// A specified clipping shape. &gt; pub type ClippingShape = generic::ClippingShape&lt;BasicShape, SpecifiedUrl&gt;; &gt; &gt; /// A specified float area shape. &gt; pub type FloatAreaShape = generic::FloatAreaShape&lt;BasicShape, Image&gt;; &gt; &gt; /// A specified basic shape. &gt;@@ -75,18 +75,18 @@ where &gt; &gt; *component = input.try(|i| U::parse(context, i)).ok(); &gt; component.is_some() &gt; } &gt; &gt; let mut shape = None; &gt; let mut ref_box = None; &gt; &gt;- while parse_component(context, input, &amp;mut shape) || &gt;- parse_component(context, input, &amp;mut ref_box) &gt;+ while parse_component(context, input, &amp;mut shape) &gt;+ || parse_component(context, input, &amp;mut ref_box) &gt; { &gt; // &gt; } &gt; &gt; if let Some(shp) = shape { &gt; return Ok(ShapeSource::Shape(shp, ref_box)); &gt; } &gt; &gt;@@ -224,18 +224,17 @@ impl Ellipse { &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let (a, b) = input &gt; .try(|i| -&gt; Result&lt;_, ParseError&gt; { &gt; Ok(( &gt; ShapeRadius::parse(context, i)?, &gt; ShapeRadius::parse(context, i)?, &gt; )) &gt;- }) &gt;- .unwrap_or_default(); &gt;+ }).unwrap_or_default(); &gt; let position = if input.try(|i| i.expect_ident_matching("at")).is_ok() { &gt; Position::parse(context, input)? &gt; } else { &gt; Position::center() &gt; }; &gt; &gt; Ok(generic::Ellipse { &gt; semiaxis_x: a, &gt;@@ -302,38 +301,38 @@ where &gt; PositionComponent::Side(keyword, None) =&gt; { &gt; // left | top =&gt; 0% &gt; // right | bottom =&gt; 100% &gt; let p = if keyword.is_start() { 0. } else { 1. }; &gt; ( &gt; S::start(), &gt; Cow::Owned(LengthOrPercentage::Percentage(Percentage(p))), &gt; ) &gt;- }, &gt;+ } &gt; PositionComponent::Side(keyword, Some(ref lop)) if !keyword.is_start() =&gt; { &gt; if let LengthOrPercentage::Percentage(p) = *to_non_zero_length(lop) { &gt; ( &gt; S::start(), &gt; Cow::Owned(LengthOrPercentage::Percentage(Percentage(1. - p.0))), &gt; ) &gt; } else { &gt; (keyword, Cow::Borrowed(lop)) &gt; } &gt;- }, &gt;+ } &gt; PositionComponent::Length(ref lop) | PositionComponent::Side(_, Some(ref lop)) =&gt; { &gt; (S::start(), to_non_zero_length(lop)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; fn to_non_zero_length(lop: &amp;LengthOrPercentage) -&gt; Cow&lt;LengthOrPercentage&gt; { &gt; match *lop { &gt; LengthOrPercentage::Length(ref l) if l.is_zero() =&gt; { &gt; Cow::Owned(LengthOrPercentage::Percentage(Percentage(0.))) &gt;- }, &gt;+ } &gt; _ =&gt; Cow::Borrowed(lop), &gt; } &gt; } &gt; &gt; fn write_pair&lt;A, B, W&gt;(a: &amp;A, b: &amp;B, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; A: ToCss, &gt; B: ToCss, &gt;@@ -372,18 +371,17 @@ impl Polygon { &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let fill = input &gt; .try(|i| -&gt; Result&lt;_, ParseError&gt; { &gt; let fill = FillRule::parse(i)?; &gt; i.expect_comma()?; // only eat the comma if there is something before it &gt; Ok(fill) &gt;- }) &gt;- .unwrap_or_default(); &gt;+ }).unwrap_or_default(); &gt; &gt; let buf = input.parse_comma_separated(|i| { &gt; Ok(( &gt; LengthOrPercentage::parse(context, i)?, &gt; LengthOrPercentage::parse(context, i)?, &gt; )) &gt; })?; &gt; &gt;diff --git a/servo/components/style/values/specified/border.rs b/servo/components/style/values/specified/border.rs &gt;index 0713ed99eb94..21d774c2fe5b 100644 &gt;--- a/servo/components/style/values/specified/border.rs &gt;+++ b/servo/components/style/values/specified/border.rs &gt;@@ -11,18 +11,18 @@ use style_traits::{CssWriter, ParseError, ToCss}; &gt; use values::computed::{self, Context, ToComputedValue}; &gt; use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; &gt; use values::generics::border::BorderImageSideWidth as GenericBorderImageSideWidth; &gt; use values::generics::border::BorderImageSlice as GenericBorderImageSlice; &gt; use values::generics::border::BorderRadius as GenericBorderRadius; &gt; use values::generics::border::BorderSpacing as GenericBorderSpacing; &gt; use values::generics::rect::Rect; &gt; use values::generics::size::Size; &gt;-use values::specified::{AllowQuirks, Number, NumberOrPercentage}; &gt; use values::specified::length::{Length, LengthOrPercentage, NonNegativeLength}; &gt;+use values::specified::{AllowQuirks, Number, NumberOrPercentage}; &gt; &gt; /// A specified value for a single side of the `border-width` property. &gt; #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] &gt; pub enum BorderSideWidth { &gt; /// `thin` &gt; Thin, &gt; /// `medium` &gt; Medium, &gt;@@ -184,30 +184,28 @@ impl Parse for BorderSpacing { &gt; Length::parse_non_negative_quirky(context, input, AllowQuirks::Yes).map(From::from) &gt; }).map(GenericBorderSpacing) &gt; } &gt; } &gt; &gt; /// A single border-image-repeat keyword. &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToCss)] &gt;+#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)] &gt; pub enum BorderImageRepeatKeyword { &gt; Stretch, &gt; Repeat, &gt; Round, &gt; Space, &gt; } &gt; &gt; /// The specified value for the `border-image-repeat` property. &gt; /// &gt; /// https://drafts.csswg.org/css-backgrounds/#the-border-image-repeat &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct BorderImageRepeat(pub BorderImageRepeatKeyword, pub BorderImageRepeatKeyword); &gt; &gt; impl ToCss for BorderImageRepeat { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; self.0.to_css(dest)?; &gt;diff --git a/servo/components/style/values/specified/box.rs b/servo/components/style/values/specified/box.rs &gt;index 6b474689df37..8fc8955f8f60 100644 &gt;--- a/servo/components/style/values/specified/box.rs &gt;+++ b/servo/components/style/values/specified/box.rs &gt;@@ -1,69 +1,79 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Specified types for box properties. &gt; &gt;-use Atom; &gt; use cssparser::Parser; &gt; use custom_properties::Name as CustomPropertyName; &gt; use parser::{Parse, ParserContext}; &gt;-use properties::{LonghandId, ShorthandId, PropertyId, PropertyFlags, PropertyDeclarationId}; &gt;+use properties::{LonghandId, PropertyDeclarationId, PropertyFlags, PropertyId, ShorthandId}; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use std::fmt::{self, Write}; &gt;-use style_traits::{CssWriter, KeywordsCollectFn, ParseError, StyleParseErrorKind, SpecifiedValueInfo, ToCss}; &gt;-use values::{CustomIdent, KeyframesName}; &gt;+use style_traits::{ &gt;+ CssWriter, KeywordsCollectFn, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss, &gt;+}; &gt; use values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount; &gt; use values::generics::box_::Perspective as GenericPerspective; &gt; use values::generics::box_::VerticalAlign as GenericVerticalAlign; &gt;-use values::specified::{AllowQuirks, Number}; &gt; use values::specified::length::{LengthOrPercentage, NonNegativeLength}; &gt;+use values::specified::{AllowQuirks, Number}; &gt;+use values::{CustomIdent, KeyframesName}; &gt;+use Atom; &gt; &gt; fn in_ua_or_chrome_sheet(context: &amp;ParserContext) -&gt; bool { &gt; use stylesheets::Origin; &gt;- context.stylesheet_origin == Origin::UserAgent || &gt;- context.chrome_rules_enabled() &gt;+ context.stylesheet_origin == Origin::UserAgent || context.chrome_rules_enabled() &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt; fn moz_display_values_enabled(context: &amp;ParserContext) -&gt; bool { &gt; use gecko_bindings::structs; &gt;- in_ua_or_chrome_sheet(context) || &gt;- unsafe { &gt;- structs::StaticPrefs_sVarCache_layout_css_xul_display_values_content_enabled &gt;- } &gt;+ in_ua_or_chrome_sheet(context) &gt;+ || unsafe { structs::StaticPrefs_sVarCache_layout_css_xul_display_values_content_enabled } &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt; fn moz_box_display_values_enabled(context: &amp;ParserContext) -&gt; bool { &gt; use gecko_bindings::structs; &gt;- in_ua_or_chrome_sheet(context) || &gt;- unsafe { &gt;- structs::StaticPrefs_sVarCache_layout_css_xul_box_display_values_content_enabled &gt;- } &gt;+ in_ua_or_chrome_sheet(context) &gt;+ || unsafe { &gt;+ structs::StaticPrefs_sVarCache_layout_css_xul_box_display_values_content_enabled &gt;+ } &gt; } &gt; &gt; /// Defines an element’s display type, which consists of &gt; /// the two basic qualities of how an element generates boxes &gt; /// &lt;https://drafts.csswg.org/css-display/#propdef-display&gt; &gt; /// &gt; /// &gt; /// NOTE(emilio): Order is important in Gecko! &gt; /// &gt; /// If you change it, make sure to take a look at the &gt; /// FrameConstructionDataByDisplay stuff (both the XUL and non-XUL version), and &gt; /// ensure it's still correct! &gt; /// &gt; /// Also, when you change this from Gecko you may need to regenerate the &gt; /// C++-side bindings (see components/style/cbindgen.toml). &gt; #[allow(missing_docs)] &gt;-#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ Hash, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt; #[repr(u8)] &gt; pub enum Display { &gt; None = 0, &gt; Block, &gt; #[cfg(feature = "gecko")] &gt; FlowRoot, &gt; Inline, &gt;@@ -178,35 +188,38 @@ impl Display { &gt; /// has a vastly different meaning. See bug 1107378 and bug 1407701. &gt; /// &gt; /// FIXME(emilio): This is a pretty decent hack, we should try to &gt; /// remove it. &gt; pub fn should_ignore_parsed_value(_old_display: Self, _new_display: Self) -&gt; bool { &gt; #[cfg(feature = "gecko")] &gt; { &gt; match (_old_display, _new_display) { &gt;- (Display::WebkitBox, Display::MozBox) | &gt;- (Display::WebkitInlineBox, Display::MozInlineBox) =&gt; { &gt;+ (Display::WebkitBox, Display::MozBox) &gt;+ | (Display::WebkitInlineBox, Display::MozInlineBox) =&gt; { &gt; return true; &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; } &gt; &gt; return false; &gt; } &gt; &gt; /// Returns whether this "display" value is one of the types for &gt; /// ruby. &gt; #[cfg(feature = "gecko")] &gt; pub fn is_ruby_type(&amp;self) -&gt; bool { &gt; matches!( &gt; *self, &gt;- Display::Ruby | Display::RubyBase | Display::RubyText | Display::RubyBaseContainer | &gt;- Display::RubyTextContainer &gt;+ Display::Ruby &gt;+ | Display::RubyBase &gt;+ | Display::RubyText &gt;+ | Display::RubyBaseContainer &gt;+ | Display::RubyTextContainer &gt; ) &gt; } &gt; &gt; /// Returns whether this "display" value is a ruby level container. &gt; #[cfg(feature = "gecko")] &gt; pub fn is_ruby_level_container(&amp;self) -&gt; bool { &gt; matches!( &gt; *self, &gt;@@ -229,22 +242,22 @@ impl Display { &gt; Display::WebkitInlineBox =&gt; Display::WebkitBox, &gt; &gt; // Special handling for contents and list-item on the root &gt; // element for Gecko. &gt; #[cfg(feature = "gecko")] &gt; Display::Contents | Display::ListItem if _is_root_element =&gt; &gt; { &gt; Display::Block &gt;- }, &gt;+ } &gt; &gt; // These are not changed by blockification. &gt; Display::None | Display::Block | Display::Flex | Display::ListItem | Display::Table =&gt; { &gt; *self &gt;- }, &gt;+ } &gt; &gt; #[cfg(feature = "gecko")] &gt; Display::Contents | Display::FlowRoot | Display::Grid | Display::WebkitBox =&gt; *self, &gt; &gt; // Everything else becomes block. &gt; _ =&gt; Display::Block, &gt; } &gt; } &gt;@@ -341,18 +354,17 @@ impl AnimationIterationCount { &gt; /// Returns the value `1.0`. &gt; #[inline] &gt; pub fn one() -&gt; Self { &gt; GenericAnimationIterationCount::Number(Number::new(1.0)) &gt; } &gt; } &gt; &gt; /// A value for the `animation-name` property. &gt;-#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; #[value_info(other_values = "none")] &gt; pub struct AnimationName(pub Option&lt;KeyframesName&gt;); &gt; &gt; impl AnimationName { &gt; /// Get the name of the animation as an `Atom`. &gt; pub fn as_atom(&amp;self) -&gt; Option&lt;&amp;Atom&gt; { &gt; self.0.as_ref().map(|n| n.as_atom()) &gt; } &gt;@@ -386,45 +398,74 @@ impl Parse for AnimationName { &gt; &gt; input.expect_ident_matching("none")?; &gt; Ok(AnimationName(None)) &gt; } &gt; } &gt; &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum ScrollSnapType { &gt; None, &gt; Mandatory, &gt; Proximity, &gt; } &gt; &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum OverscrollBehavior { &gt; Auto, &gt; Contain, &gt; None, &gt; } &gt; &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum OverflowClipBox { &gt; PaddingBox, &gt; ContentBox, &gt; } &gt; &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; /// Provides a rendering hint to the user agent, &gt; /// stating what kinds of changes the author expects &gt; /// to perform on the element &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-will-change/#will-change&gt; &gt; pub enum WillChange { &gt; /// Expresses no particular intent &gt; Auto, &gt;@@ -492,21 +533,21 @@ fn change_bits_for_longhand(longhand: LonghandId) -&gt; WillChangeBits { &gt; &gt; fn change_bits_for_maybe_property(ident: &amp;str, context: &amp;ParserContext) -&gt; WillChangeBits { &gt; let id = match PropertyId::parse_ignoring_rule_type(ident, context) { &gt; Ok(id) =&gt; id, &gt; Err(..) =&gt; return WillChangeBits::empty(), &gt; }; &gt; &gt; match id.as_shorthand() { &gt;- Ok(shorthand) =&gt; { &gt;- shorthand.longhands().fold(WillChangeBits::empty(), |flags, p| { &gt;+ Ok(shorthand) =&gt; shorthand &gt;+ .longhands() &gt;+ .fold(WillChangeBits::empty(), |flags, p| { &gt; flags | change_bits_for_longhand(p) &gt;- }) &gt;- } &gt;+ }), &gt; Err(PropertyDeclarationId::Longhand(longhand)) =&gt; change_bits_for_longhand(longhand), &gt; Err(PropertyDeclarationId::Custom(..)) =&gt; WillChangeBits::empty(), &gt; } &gt; } &gt; &gt; impl Parse for WillChange { &gt; /// auto | &lt;animateable-feature&gt;# &gt; fn parse&lt;'i, 't&gt;( &gt;@@ -576,22 +617,21 @@ impl ToCss for TouchAction { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; match *self { &gt; TouchAction::TOUCH_ACTION_NONE =&gt; dest.write_str("none"), &gt; TouchAction::TOUCH_ACTION_AUTO =&gt; dest.write_str("auto"), &gt; TouchAction::TOUCH_ACTION_MANIPULATION =&gt; dest.write_str("manipulation"), &gt;- _ if self.contains( &gt;- TouchAction::TOUCH_ACTION_PAN_X | TouchAction::TOUCH_ACTION_PAN_Y, &gt;- ) =&gt; &gt;+ _ if self &gt;+ .contains(TouchAction::TOUCH_ACTION_PAN_X | TouchAction::TOUCH_ACTION_PAN_Y) =&gt; &gt; { &gt; dest.write_str("pan-x pan-y") &gt;- }, &gt;+ } &gt; _ if self.contains(TouchAction::TOUCH_ACTION_PAN_X) =&gt; dest.write_str("pan-x"), &gt; _ if self.contains(TouchAction::TOUCH_ACTION_PAN_Y) =&gt; dest.write_str("pan-y"), &gt; _ =&gt; panic!("invalid touch-action value"), &gt; } &gt; } &gt; } &gt; &gt; impl Parse for TouchAction { &gt;@@ -726,17 +766,17 @@ impl Parse for Contain { &gt; "none" if result.is_empty() =&gt; return Ok(result), &gt; _ =&gt; None &gt; }; &gt; &gt; let flag = match flag { &gt; Some(flag) if !result.contains(flag) =&gt; flag, &gt; _ =&gt; { &gt; return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name))) &gt;- }, &gt;+ } &gt; }; &gt; result.insert(flag); &gt; } &gt; &gt; if !result.is_empty() { &gt; Ok(result) &gt; } else { &gt; Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt;@@ -751,18 +791,17 @@ impl Parse for Perspective { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; if input.try(|i| i.expect_ident_matching("none")).is_ok() { &gt; return Ok(GenericPerspective::None); &gt; } &gt; Ok(GenericPerspective::Length(NonNegativeLength::parse( &gt;- context, &gt;- input, &gt;+ context, input, &gt; )?)) &gt; } &gt; } &gt; &gt; /// A given transition property, that is either `All`, a longhand or shorthand &gt; /// property, or an unsupported or custom property. &gt; #[derive(Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue)] &gt; pub enum TransitionProperty { &gt;@@ -800,31 +839,31 @@ impl Parse for TransitionProperty { &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let location = input.current_source_location(); &gt; let ident = input.expect_ident()?; &gt; &gt; let id = match PropertyId::parse_ignoring_rule_type(&amp;ident, context) { &gt; Ok(id) =&gt; id, &gt;- Err(..) =&gt; return Ok(TransitionProperty::Unsupported( &gt;- CustomIdent::from_ident(location, ident, &amp;["none"])?, &gt;- )), &gt;+ Err(..) =&gt; { &gt;+ return Ok(TransitionProperty::Unsupported(CustomIdent::from_ident( &gt;+ location, &gt;+ ident, &gt;+ &amp;["none"], &gt;+ )?)) &gt;+ } &gt; }; &gt; &gt; Ok(match id.as_shorthand() { &gt; Ok(s) =&gt; TransitionProperty::Shorthand(s), &gt;- Err(longhand_or_custom) =&gt; { &gt;- match longhand_or_custom { &gt;- PropertyDeclarationId::Longhand(id) =&gt; TransitionProperty::Longhand(id), &gt;- PropertyDeclarationId::Custom(custom) =&gt; { &gt;- TransitionProperty::Custom(custom.clone()) &gt;- } &gt;- } &gt;- } &gt;+ Err(longhand_or_custom) =&gt; match longhand_or_custom { &gt;+ PropertyDeclarationId::Longhand(id) =&gt; TransitionProperty::Longhand(id), &gt;+ PropertyDeclarationId::Custom(custom) =&gt; TransitionProperty::Custom(custom.clone()), &gt;+ }, &gt; }) &gt; } &gt; } &gt; &gt; impl SpecifiedValueInfo for TransitionProperty { &gt; fn collect_completion_keywords(f: KeywordsCollectFn) { &gt; // `transition-property` can actually accept all properties and &gt; // arbitrary identifiers, but `all` is a special one we'd like &gt;@@ -844,56 +883,58 @@ impl TransitionProperty { &gt; #[cfg(feature = "gecko")] &gt; pub fn to_nscsspropertyid(&amp;self) -&gt; Result&lt;::gecko_bindings::structs::nsCSSPropertyID, ()&gt; { &gt; Ok(match *self { &gt; TransitionProperty::Shorthand(ShorthandId::All) =&gt; { &gt; ::gecko_bindings::structs::nsCSSPropertyID::eCSSPropertyExtra_all_properties &gt; } &gt; TransitionProperty::Shorthand(ref id) =&gt; id.to_nscsspropertyid(), &gt; TransitionProperty::Longhand(ref id) =&gt; id.to_nscsspropertyid(), &gt;- TransitionProperty::Custom(..) | &gt;- TransitionProperty::Unsupported(..) =&gt; return Err(()), &gt;+ TransitionProperty::Custom(..) | TransitionProperty::Unsupported(..) =&gt; return Err(()), &gt; }) &gt; } &gt; } &gt; &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, &gt;+)] &gt; /// https://drafts.csswg.org/css-box/#propdef-float &gt; pub enum Float { &gt; Left, &gt; Right, &gt; None, &gt; // https://drafts.csswg.org/css-logical-props/#float-clear &gt; InlineStart, &gt;- InlineEnd &gt;+ InlineEnd, &gt; } &gt; &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, &gt;+)] &gt; /// https://drafts.csswg.org/css-box/#propdef-clear &gt; pub enum Clear { &gt; None, &gt; Left, &gt; Right, &gt; Both, &gt; // https://drafts.csswg.org/css-logical-props/#float-clear &gt; InlineStart, &gt;- InlineEnd &gt;+ InlineEnd, &gt; } &gt; &gt; /// https://drafts.csswg.org/css-ui/#propdef-resize &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, &gt;+)] &gt; pub enum Resize { &gt; None, &gt; Both, &gt; Horizontal, &gt; Vertical, &gt; // https://drafts.csswg.org/css-logical-1/#resize &gt; Inline, &gt; Block, &gt;@@ -901,18 +942,29 @@ pub enum Resize { &gt; &gt; /// The value for the `appearance` property. &gt; /// &gt; /// https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance &gt; /// &gt; /// NOTE(emilio): When changing this you may want to regenerate the C++ bindings &gt; /// (see components/style/cbindgen.toml) &gt; #[allow(missing_docs)] &gt;-#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToCss, ToComputedValue)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ Hash, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToCss, &gt;+ ToComputedValue, &gt;+)] &gt; #[repr(u8)] &gt; pub enum Appearance { &gt; /// No appearance at all. &gt; None, &gt; /// A typical dialog button. &gt; Button, &gt; /// Various arrows that go in buttons &gt; ButtonArrowDown, &gt;diff --git a/servo/components/style/values/specified/calc.rs b/servo/components/style/values/specified/calc.rs &gt;index 06c1dba29559..ece8dcb814c7 100644 &gt;--- a/servo/components/style/values/specified/calc.rs &gt;+++ b/servo/components/style/values/specified/calc.rs &gt;@@ -4,23 +4,23 @@ &gt; &gt; //! [Calc expressions][calc]. &gt; //! &gt; //! [calc]: https://drafts.csswg.org/css-values/#calc-notation &gt; &gt; use cssparser::{AngleOrNumber, NumberOrPercentage, Parser, Token}; &gt; use parser::ParserContext; &gt; use std::fmt::{self, Write}; &gt;-use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; &gt; use style_traits::values::specified::AllowedNumericType; &gt;-use values::{CSSFloat, CSSInteger}; &gt;+use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; &gt; use values::computed; &gt;-use values::specified::{Angle, Time}; &gt;-use values::specified::length::{AbsoluteLength, FontRelativeLength, NoCalcLength}; &gt; use values::specified::length::ViewportPercentageLength; &gt;+use values::specified::length::{AbsoluteLength, FontRelativeLength, NoCalcLength}; &gt;+use values::specified::{Angle, Time}; &gt;+use values::{CSSFloat, CSSInteger}; &gt; &gt; /// A node inside a `Calc` expression's AST. &gt; #[derive(Clone, Debug)] &gt; pub enum CalcNode { &gt; /// `&lt;length&gt;` &gt; Length(NoCalcLength), &gt; /// `&lt;angle&gt;` &gt; Angle(Angle), &gt;@@ -168,53 +168,53 @@ impl CalcNode { &gt; // FIXME: remove early returns when lifetimes are non-lexical &gt; match (input.next()?, expected_unit) { &gt; (&amp;Token::Number { value, .. }, _) =&gt; return Ok(CalcNode::Number(value)), &gt; ( &gt; &amp;Token::Dimension { &gt; value, ref unit, .. &gt; }, &gt; CalcUnit::Length, &gt;- ) | &gt;- ( &gt;+ ) &gt;+ | ( &gt; &amp;Token::Dimension { &gt; value, ref unit, .. &gt; }, &gt; CalcUnit::LengthOrPercentage, &gt; ) =&gt; { &gt; return NoCalcLength::parse_dimension(context, value, unit) &gt; .map(CalcNode::Length) &gt; .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt;- }, &gt;+ } &gt; ( &gt; &amp;Token::Dimension { &gt; value, ref unit, .. &gt; }, &gt; CalcUnit::Angle, &gt; ) =&gt; { &gt; return Angle::parse_dimension(value, unit, /* from_calc = */ true) &gt; .map(CalcNode::Angle) &gt; .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt;- }, &gt;+ } &gt; ( &gt; &amp;Token::Dimension { &gt; value, ref unit, .. &gt; }, &gt; CalcUnit::Time, &gt; ) =&gt; { &gt; return Time::parse_dimension(value, unit, /* from_calc = */ true) &gt; .map(CalcNode::Time) &gt; .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt;- }, &gt;- (&amp;Token::Percentage { unit_value, .. }, CalcUnit::LengthOrPercentage) | &gt;- (&amp;Token::Percentage { unit_value, .. }, CalcUnit::Percentage) =&gt; { &gt;+ } &gt;+ (&amp;Token::Percentage { unit_value, .. }, CalcUnit::LengthOrPercentage) &gt;+ | (&amp;Token::Percentage { unit_value, .. }, CalcUnit::Percentage) =&gt; { &gt; return Ok(CalcNode::Percentage(unit_value)) &gt;- }, &gt;- (&amp;Token::ParenthesisBlock, _) =&gt; {}, &gt;- (&amp;Token::Function(ref name), _) if name.eq_ignore_ascii_case("calc") =&gt; {}, &gt;+ } &gt;+ (&amp;Token::ParenthesisBlock, _) =&gt; {} &gt;+ (&amp;Token::Function(ref name), _) if name.eq_ignore_ascii_case("calc") =&gt; {} &gt; (t, _) =&gt; return Err(location.new_unexpected_token_error(t.clone())), &gt; } &gt; input.parse_nested_block(|i| CalcNode::parse(context, i, expected_unit)) &gt; } &gt; &gt; /// Parse a top-level `calc` expression, with all nested sub-expressions. &gt; /// &gt; /// This is in charge of parsing, for example, `2 + 3 * 100%`. &gt;@@ -233,29 +233,29 @@ impl CalcNode { &gt; break; // allow trailing whitespace &gt; } &gt; // FIXME: remove clone() when lifetimes are non-lexical &gt; match input.next()?.clone() { &gt; Token::Delim('+') =&gt; { &gt; let rhs = Self::parse_product(context, input, expected_unit)?; &gt; let new_root = CalcNode::Sum(Box::new(root), Box::new(rhs)); &gt; root = new_root; &gt;- }, &gt;+ } &gt; Token::Delim('-') =&gt; { &gt; let rhs = Self::parse_product(context, input, expected_unit)?; &gt; let new_root = CalcNode::Sub(Box::new(root), Box::new(rhs)); &gt; root = new_root; &gt;- }, &gt;+ } &gt; t =&gt; return Err(input.new_unexpected_token_error(t)), &gt; } &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; input.reset(&amp;start); &gt; break; &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; Ok(root) &gt; } &gt; &gt; /// Parse a top-level `calc` expression, and all the products that may &gt; /// follow, and stop as soon as a non-product expression is found. &gt;@@ -275,27 +275,27 @@ impl CalcNode { &gt; &gt; loop { &gt; let start = input.state(); &gt; match input.next() { &gt; Ok(&amp;Token::Delim('*')) =&gt; { &gt; let rhs = Self::parse_one(context, input, expected_unit)?; &gt; let new_root = CalcNode::Mul(Box::new(root), Box::new(rhs)); &gt; root = new_root; &gt;- }, &gt;+ } &gt; // TODO(emilio): Figure out why the `Integer` check. &gt; Ok(&amp;Token::Delim('/')) if expected_unit != CalcUnit::Integer =&gt; { &gt; let rhs = Self::parse_one(context, input, expected_unit)?; &gt; let new_root = CalcNode::Div(Box::new(root), Box::new(rhs)); &gt; root = new_root; &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; input.reset(&amp;start); &gt; break; &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; Ok(root) &gt; } &gt; &gt; /// Tries to simplify this expression into a `&lt;length&gt;` or `&lt;percentage`&gt; &gt; /// value. &gt;@@ -316,35 +316,35 @@ impl CalcNode { &gt; Ok(match *self { &gt; CalcNode::Percentage(percentage) =&gt; percentage, &gt; CalcNode::Sub(ref a, ref b) =&gt; a.to_percentage()? - b.to_percentage()?, &gt; CalcNode::Sum(ref a, ref b) =&gt; a.to_percentage()? + b.to_percentage()?, &gt; CalcNode::Mul(ref a, ref b) =&gt; match a.to_percentage() { &gt; Ok(lhs) =&gt; { &gt; let rhs = b.to_number()?; &gt; lhs * rhs &gt;- }, &gt;+ } &gt; Err(..) =&gt; { &gt; let lhs = a.to_number()?; &gt; let rhs = b.to_percentage()?; &gt; lhs * rhs &gt;- }, &gt;+ } &gt; }, &gt; CalcNode::Div(ref a, ref b) =&gt; { &gt; let lhs = a.to_percentage()?; &gt; let rhs = b.to_number()?; &gt; if rhs == 0. { &gt; return Err(()); &gt; } &gt; lhs / rhs &gt;- }, &gt;- CalcNode::Number(..) | &gt;- CalcNode::Length(..) | &gt;- CalcNode::Angle(..) | &gt;- CalcNode::Time(..) =&gt; return Err(()), &gt;+ } &gt;+ CalcNode::Number(..) &gt;+ | CalcNode::Length(..) &gt;+ | CalcNode::Angle(..) &gt;+ | CalcNode::Time(..) =&gt; return Err(()), &gt; }) &gt; } &gt; &gt; /// Puts this `&lt;length&gt;` or `&lt;percentage&gt;` into `ret`, or error. &gt; /// &gt; /// `factor` is the sign or multiplicative factor to account for the sign &gt; /// (this allows adding and substracting into the return value). &gt; fn add_length_or_percentage_to( &gt;@@ -352,161 +352,161 @@ impl CalcNode { &gt; ret: &amp;mut CalcLengthOrPercentage, &gt; factor: CSSFloat, &gt; ) -&gt; Result&lt;(), ()&gt; { &gt; match *self { &gt; CalcNode::Percentage(pct) =&gt; { &gt; ret.percentage = Some(computed::Percentage( &gt; ret.percentage.map_or(0., |p| p.0) + pct * factor, &gt; )); &gt;- }, &gt;+ } &gt; CalcNode::Length(ref l) =&gt; match *l { &gt; NoCalcLength::Absolute(abs) =&gt; { &gt; ret.absolute = Some(match ret.absolute { &gt; Some(value) =&gt; value + abs * factor, &gt; None =&gt; abs * factor, &gt; }); &gt;- }, &gt;+ } &gt; NoCalcLength::FontRelative(rel) =&gt; match rel { &gt; FontRelativeLength::Em(em) =&gt; { &gt; ret.em = Some(ret.em.unwrap_or(0.) + em * factor); &gt;- }, &gt;+ } &gt; FontRelativeLength::Ex(ex) =&gt; { &gt; ret.ex = Some(ret.ex.unwrap_or(0.) + ex * factor); &gt;- }, &gt;+ } &gt; FontRelativeLength::Ch(ch) =&gt; { &gt; ret.ch = Some(ret.ch.unwrap_or(0.) + ch * factor); &gt;- }, &gt;+ } &gt; FontRelativeLength::Rem(rem) =&gt; { &gt; ret.rem = Some(ret.rem.unwrap_or(0.) + rem * factor); &gt;- }, &gt;+ } &gt; }, &gt; NoCalcLength::ViewportPercentage(rel) =&gt; match rel { &gt; ViewportPercentageLength::Vh(vh) =&gt; { &gt; ret.vh = Some(ret.vh.unwrap_or(0.) + vh * factor) &gt;- }, &gt;+ } &gt; ViewportPercentageLength::Vw(vw) =&gt; { &gt; ret.vw = Some(ret.vw.unwrap_or(0.) + vw * factor) &gt;- }, &gt;+ } &gt; ViewportPercentageLength::Vmax(vmax) =&gt; { &gt; ret.vmax = Some(ret.vmax.unwrap_or(0.) + vmax * factor) &gt;- }, &gt;+ } &gt; ViewportPercentageLength::Vmin(vmin) =&gt; { &gt; ret.vmin = Some(ret.vmin.unwrap_or(0.) + vmin * factor) &gt;- }, &gt;+ } &gt; }, &gt; NoCalcLength::ServoCharacterWidth(..) =&gt; unreachable!(), &gt; }, &gt; CalcNode::Sub(ref a, ref b) =&gt; { &gt; a.add_length_or_percentage_to(ret, factor)?; &gt; b.add_length_or_percentage_to(ret, factor * -1.0)?; &gt;- }, &gt;+ } &gt; CalcNode::Sum(ref a, ref b) =&gt; { &gt; a.add_length_or_percentage_to(ret, factor)?; &gt; b.add_length_or_percentage_to(ret, factor)?; &gt;- }, &gt;+ } &gt; CalcNode::Mul(ref a, ref b) =&gt; match b.to_number() { &gt; Ok(rhs) =&gt; { &gt; a.add_length_or_percentage_to(ret, factor * rhs)?; &gt;- }, &gt;+ } &gt; Err(..) =&gt; { &gt; let lhs = a.to_number()?; &gt; b.add_length_or_percentage_to(ret, factor * lhs)?; &gt;- }, &gt;+ } &gt; }, &gt; CalcNode::Div(ref a, ref b) =&gt; { &gt; let new_factor = b.to_number()?; &gt; if new_factor == 0. { &gt; return Err(()); &gt; } &gt; a.add_length_or_percentage_to(ret, factor / new_factor)?; &gt;- }, &gt;+ } &gt; CalcNode::Angle(..) | CalcNode::Time(..) | CalcNode::Number(..) =&gt; return Err(()), &gt; } &gt; &gt; Ok(()) &gt; } &gt; &gt; /// Tries to simplify this expression into a `&lt;time&gt;` value. &gt; fn to_time(&amp;self) -&gt; Result&lt;Time, ()&gt; { &gt; Ok(match *self { &gt; CalcNode::Time(ref time) =&gt; time.clone(), &gt; CalcNode::Sub(ref a, ref b) =&gt; { &gt; let lhs = a.to_time()?; &gt; let rhs = b.to_time()?; &gt; Time::from_calc(lhs.seconds() - rhs.seconds()) &gt;- }, &gt;+ } &gt; CalcNode::Sum(ref a, ref b) =&gt; { &gt; let lhs = a.to_time()?; &gt; let rhs = b.to_time()?; &gt; Time::from_calc(lhs.seconds() + rhs.seconds()) &gt;- }, &gt;+ } &gt; CalcNode::Mul(ref a, ref b) =&gt; match b.to_number() { &gt; Ok(rhs) =&gt; { &gt; let lhs = a.to_time()?; &gt; Time::from_calc(lhs.seconds() * rhs) &gt;- }, &gt;+ } &gt; Err(()) =&gt; { &gt; let lhs = a.to_number()?; &gt; let rhs = b.to_time()?; &gt; Time::from_calc(lhs * rhs.seconds()) &gt;- }, &gt;+ } &gt; }, &gt; CalcNode::Div(ref a, ref b) =&gt; { &gt; let lhs = a.to_time()?; &gt; let rhs = b.to_number()?; &gt; if rhs == 0. { &gt; return Err(()); &gt; } &gt; Time::from_calc(lhs.seconds() / rhs) &gt;- }, &gt;- CalcNode::Number(..) | &gt;- CalcNode::Length(..) | &gt;- CalcNode::Percentage(..) | &gt;- CalcNode::Angle(..) =&gt; return Err(()), &gt;+ } &gt;+ CalcNode::Number(..) &gt;+ | CalcNode::Length(..) &gt;+ | CalcNode::Percentage(..) &gt;+ | CalcNode::Angle(..) =&gt; return Err(()), &gt; }) &gt; } &gt; &gt; /// Tries to simplify this expression into an `Angle` value. &gt; fn to_angle(&amp;self) -&gt; Result&lt;Angle, ()&gt; { &gt; Ok(match *self { &gt; CalcNode::Angle(ref angle) =&gt; angle.clone(), &gt; CalcNode::Sub(ref a, ref b) =&gt; { &gt; let lhs = a.to_angle()?; &gt; let rhs = b.to_angle()?; &gt; Angle::from_calc(lhs.radians() - rhs.radians()) &gt;- }, &gt;+ } &gt; CalcNode::Sum(ref a, ref b) =&gt; { &gt; let lhs = a.to_angle()?; &gt; let rhs = b.to_angle()?; &gt; Angle::from_calc(lhs.radians() + rhs.radians()) &gt;- }, &gt;+ } &gt; CalcNode::Mul(ref a, ref b) =&gt; match a.to_angle() { &gt; Ok(lhs) =&gt; { &gt; let rhs = b.to_number()?; &gt; Angle::from_calc(lhs.radians() * rhs) &gt;- }, &gt;+ } &gt; Err(..) =&gt; { &gt; let lhs = a.to_number()?; &gt; let rhs = b.to_angle()?; &gt; Angle::from_calc(lhs * rhs.radians()) &gt;- }, &gt;+ } &gt; }, &gt; CalcNode::Div(ref a, ref b) =&gt; { &gt; let lhs = a.to_angle()?; &gt; let rhs = b.to_number()?; &gt; if rhs == 0. { &gt; return Err(()); &gt; } &gt; Angle::from_calc(lhs.radians() / rhs) &gt;- }, &gt;- CalcNode::Number(..) | &gt;- CalcNode::Length(..) | &gt;- CalcNode::Percentage(..) | &gt;- CalcNode::Time(..) =&gt; return Err(()), &gt;+ } &gt;+ CalcNode::Number(..) &gt;+ | CalcNode::Length(..) &gt;+ | CalcNode::Percentage(..) &gt;+ | CalcNode::Time(..) =&gt; return Err(()), &gt; }) &gt; } &gt; &gt; /// Tries to simplify this expression into a `&lt;number&gt;` value. &gt; fn to_number(&amp;self) -&gt; Result&lt;CSSFloat, ()&gt; { &gt; Ok(match *self { &gt; CalcNode::Number(n) =&gt; n, &gt; CalcNode::Sum(ref a, ref b) =&gt; a.to_number()? + b.to_number()?, &gt;@@ -514,21 +514,21 @@ impl CalcNode { &gt; CalcNode::Mul(ref a, ref b) =&gt; a.to_number()? * b.to_number()?, &gt; CalcNode::Div(ref a, ref b) =&gt; { &gt; let lhs = a.to_number()?; &gt; let rhs = b.to_number()?; &gt; if rhs == 0. { &gt; return Err(()); &gt; } &gt; lhs / rhs &gt;- }, &gt;- CalcNode::Length(..) | &gt;- CalcNode::Percentage(..) | &gt;- CalcNode::Angle(..) | &gt;- CalcNode::Time(..) =&gt; return Err(()), &gt;+ } &gt;+ CalcNode::Length(..) &gt;+ | CalcNode::Percentage(..) &gt;+ | CalcNode::Angle(..) &gt;+ | CalcNode::Time(..) =&gt; return Err(()), &gt; }) &gt; } &gt; &gt; /// Convenience parsing function for integers. &gt; pub fn parse_integer&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;CSSInteger, ParseError&lt;'i&gt;&gt; { &gt;diff --git a/servo/components/style/values/specified/color.rs b/servo/components/style/values/specified/color.rs &gt;index c05f0ddce0ef..bbe1b1824e40 100644 &gt;--- a/servo/components/style/values/specified/color.rs &gt;+++ b/servo/components/style/values/specified/color.rs &gt;@@ -1,27 +1,27 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Specified color values. &gt; &gt;+use super::AllowQuirks; &gt; use cssparser::{AngleOrNumber, Color as CSSParserColor, Parser, Token, RGBA}; &gt; use cssparser::{BasicParseErrorKind, NumberOrPercentage, ParseErrorKind}; &gt; #[cfg(feature = "gecko")] &gt; use gecko_bindings::structs::nscolor; &gt; use itoa; &gt; use parser::{Parse, ParserContext}; &gt; #[cfg(feature = "gecko")] &gt; use properties::longhands::system_colors::SystemColor; &gt; use std::fmt::{self, Write}; &gt; use std::io::Write as IoWrite; &gt; use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError, StyleParseErrorKind}; &gt; use style_traits::{SpecifiedValueInfo, ToCss, ValueParseErrorKind}; &gt;-use super::AllowQuirks; &gt; use values::computed::{Color as ComputedColor, Context, ToComputedValue}; &gt; use values::generics::color::Color as GenericColor; &gt; use values::specified::calc::CalcNode; &gt; &gt; /// Specified color value &gt; #[derive(Clone, Debug, MallocSizeOf, PartialEq)] &gt; pub enum Color { &gt; /// The 'currentColor' keyword &gt;diff --git a/servo/components/style/values/specified/column.rs b/servo/components/style/values/specified/column.rs &gt;index d065835423d6..4cd8ad0777f0 100644 &gt;--- a/servo/components/style/values/specified/column.rs &gt;+++ b/servo/components/style/values/specified/column.rs &gt;@@ -17,13 +17,12 @@ impl Parse for ColumnCount { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; if input.try(|i| i.expect_ident_matching("auto")).is_ok() { &gt; return Ok(GenericColumnCount::Auto); &gt; } &gt; Ok(GenericColumnCount::Integer(PositiveInteger::parse( &gt;- context, &gt;- input, &gt;+ context, input, &gt; )?)) &gt; } &gt; } &gt;diff --git a/servo/components/style/values/specified/counters.rs b/servo/components/style/values/specified/counters.rs &gt;index ea369f9dec75..771551b7e95a 100644 &gt;--- a/servo/components/style/values/specified/counters.rs &gt;+++ b/servo/components/style/values/specified/counters.rs &gt;@@ -5,27 +5,27 @@ &gt; //! Specified types for counter properties. &gt; &gt; #[cfg(feature = "servo")] &gt; use computed_values::list_style_type::T as ListStyleType; &gt; use cssparser::{Parser, Token}; &gt; use parser::{Parse, ParserContext}; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use style_traits::{ParseError, StyleParseErrorKind}; &gt;-use values::CustomIdent; &gt;-#[cfg(feature = "gecko")] &gt;-use values::generics::CounterStyleOrNone; &gt; use values::generics::counters as generics; &gt; use values::generics::counters::CounterIncrement as GenericCounterIncrement; &gt; use values::generics::counters::CounterPair; &gt; use values::generics::counters::CounterReset as GenericCounterReset; &gt; #[cfg(feature = "gecko")] &gt;+use values::generics::CounterStyleOrNone; &gt;+use values::specified::url::SpecifiedImageUrl; &gt;+#[cfg(feature = "gecko")] &gt; use values::specified::Attr; &gt; use values::specified::Integer; &gt;-use values::specified::url::SpecifiedImageUrl; &gt;+use values::CustomIdent; &gt; &gt; /// A specified value for the `counter-increment` property. &gt; pub type CounterIncrement = GenericCounterIncrement&lt;Integer&gt;; &gt; &gt; impl Parse for CounterIncrement { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt;@@ -88,28 +88,26 @@ pub type ContentItem = generics::ContentItem&lt;SpecifiedImageUrl&gt;; &gt; &gt; impl Content { &gt; #[cfg(feature = "servo")] &gt; fn parse_counter_style(_: &amp;ParserContext, input: &amp;mut Parser) -&gt; ListStyleType { &gt; input &gt; .try(|input| { &gt; input.expect_comma()?; &gt; ListStyleType::parse(input) &gt;- }) &gt;- .unwrap_or(ListStyleType::Decimal) &gt;+ }).unwrap_or(ListStyleType::Decimal) &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt; fn parse_counter_style(context: &amp;ParserContext, input: &amp;mut Parser) -&gt; CounterStyleOrNone { &gt; input &gt; .try(|input| { &gt; input.expect_comma()?; &gt; CounterStyleOrNone::parse(context, input) &gt;- }) &gt;- .unwrap_or(CounterStyleOrNone::decimal()) &gt;+ }).unwrap_or(CounterStyleOrNone::decimal()) &gt; } &gt; } &gt; &gt; impl Parse for Content { &gt; // normal | none | [ &lt;string&gt; | &lt;counter&gt; | open-quote | close-quote | no-open-quote | &gt; // no-close-quote ]+ &gt; // TODO: &lt;uri&gt;, attr(&lt;identifier&gt;) &gt; fn parse&lt;'i, 't&gt;( &gt;@@ -148,17 +146,17 @@ impl Parse for Content { &gt; } &gt; } &gt; // FIXME: remove clone() when lifetimes are non-lexical &gt; match input.next().map(|t| t.clone()) { &gt; Ok(Token::QuotedString(ref value)) =&gt; { &gt; content.push(generics::ContentItem::String( &gt; value.as_ref().to_owned().into_boxed_str(), &gt; )); &gt;- }, &gt;+ } &gt; Ok(Token::Function(ref name)) =&gt; { &gt; let result = match_ignore_ascii_case! { &amp;name, &gt; "counter" =&gt; Some(input.parse_nested_block(|input| { &gt; let location = input.current_source_location(); &gt; let name = CustomIdent::from_ident(location, input.expect_ident()?, &amp;[])?; &gt; let style = Content::parse_counter_style(context, input); &gt; Ok(generics::ContentItem::Counter(name, style)) &gt; })), &gt;@@ -177,30 +175,30 @@ impl Parse for Content { &gt; _ =&gt; None &gt; }; &gt; match result { &gt; Some(result) =&gt; content.push(result?), &gt; None =&gt; { &gt; return Err(input.new_custom_error( &gt; StyleParseErrorKind::UnexpectedFunction(name.clone()), &gt; )) &gt;- }, &gt;+ } &gt; } &gt;- }, &gt;+ } &gt; Ok(Token::Ident(ref ident)) =&gt; { &gt; content.push(match_ignore_ascii_case! { &amp;ident, &gt; "open-quote" =&gt; generics::ContentItem::OpenQuote, &gt; "close-quote" =&gt; generics::ContentItem::CloseQuote, &gt; "no-open-quote" =&gt; generics::ContentItem::NoOpenQuote, &gt; "no-close-quote" =&gt; generics::ContentItem::NoCloseQuote, &gt; _ =&gt; return Err(input.new_custom_error( &gt; SelectorParseErrorKind::UnexpectedIdent(ident.clone()) &gt; )) &gt; }); &gt;- }, &gt;+ } &gt; Err(_) =&gt; break, &gt; Ok(t) =&gt; return Err(input.new_unexpected_token_error(t)), &gt; } &gt; } &gt; if content.is_empty() { &gt; return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt; Ok(generics::Content::Items(content.into_boxed_slice())) &gt;diff --git a/servo/components/style/values/specified/effects.rs b/servo/components/style/values/specified/effects.rs &gt;index c3304b05af0a..65b27cc7dca0 100644 &gt;--- a/servo/components/style/values/specified/effects.rs &gt;+++ b/servo/components/style/values/specified/effects.rs &gt;@@ -2,30 +2,30 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Specified types for CSS values related to effects. &gt; &gt; use cssparser::{self, BasicParseErrorKind, Parser, Token}; &gt; use parser::{Parse, ParserContext}; &gt; use style_traits::{ParseError, StyleParseErrorKind, ValueParseErrorKind}; &gt;-#[cfg(not(feature = "gecko"))] &gt;-use values::Impossible; &gt;-use values::computed::{Context, NonNegativeNumber as ComputedNonNegativeNumber, ToComputedValue}; &gt; use values::computed::effects::BoxShadow as ComputedBoxShadow; &gt; use values::computed::effects::SimpleShadow as ComputedSimpleShadow; &gt;-use values::generics::NonNegative; &gt;+use values::computed::{Context, NonNegativeNumber as ComputedNonNegativeNumber, ToComputedValue}; &gt; use values::generics::effects::BoxShadow as GenericBoxShadow; &gt; use values::generics::effects::Filter as GenericFilter; &gt; use values::generics::effects::SimpleShadow as GenericSimpleShadow; &gt;-use values::specified::{Angle, NumberOrPercentage}; &gt;+use values::generics::NonNegative; &gt; use values::specified::color::Color; &gt; use values::specified::length::{Length, NonNegativeLength}; &gt; #[cfg(feature = "gecko")] &gt; use values::specified::url::SpecifiedUrl; &gt;+use values::specified::{Angle, NumberOrPercentage}; &gt;+#[cfg(not(feature = "gecko"))] &gt;+use values::Impossible; &gt; &gt; /// A specified value for a single shadow of the `box-shadow` property. &gt; pub type BoxShadow = &gt; GenericBoxShadow&lt;Option&lt;Color&gt;, Length, Option&lt;NonNegativeLength&gt;, Option&lt;Length&gt;&gt;; &gt; &gt; /// A specified value for a single `filter`. &gt; #[cfg(feature = "gecko")] &gt; pub type Filter = GenericFilter&lt;Angle, Factor, NonNegativeLength, SimpleShadow, SpecifiedUrl&gt;; &gt;@@ -49,20 +49,20 @@ impl Factor { &gt; } &gt; &gt; /// Clamp the value to 1 if the value is over 100%. &gt; #[inline] &gt; fn clamp_to_one(self) -&gt; Self { &gt; match self.0 { &gt; NumberOrPercentage::Percentage(percent) =&gt; { &gt; Factor(NumberOrPercentage::Percentage(percent.clamp_to_hundred())) &gt;- }, &gt;+ } &gt; NumberOrPercentage::Number(number) =&gt; { &gt; Factor(NumberOrPercentage::Number(number.clamp_to_one())) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl Parse for Factor { &gt; #[inline] &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt;@@ -113,23 +113,23 @@ impl Parse for BoxShadow { &gt; inset = true; &gt; continue; &gt; } &gt; } &gt; if lengths.is_none() { &gt; let value = input.try::&lt;_, _, ParseError&gt;(|i| { &gt; let horizontal = Length::parse(context, i)?; &gt; let vertical = Length::parse(context, i)?; &gt;- let (blur, spread) = match i.try::&lt;_, _, ParseError&gt;(|i| { &gt;- Length::parse_non_negative(context, i) &gt;- }) { &gt;+ let (blur, spread) = match i &gt;+ .try::&lt;_, _, ParseError&gt;(|i| Length::parse_non_negative(context, i)) &gt;+ { &gt; Ok(blur) =&gt; { &gt; let spread = i.try(|i| Length::parse(context, i)).ok(); &gt; (Some(blur.into()), spread) &gt;- }, &gt;+ } &gt; Err(_) =&gt; (None, None), &gt; }; &gt; Ok((horizontal, vertical, blur, spread)) &gt; }); &gt; if let Ok(value) = value { &gt; lengths = Some(value); &gt; continue; &gt; } &gt;@@ -138,17 +138,18 @@ impl Parse for BoxShadow { &gt; if let Ok(value) = input.try(|i| Color::parse(context, i)) { &gt; color = Some(value); &gt; continue; &gt; } &gt; } &gt; break; &gt; } &gt; &gt;- let lengths = lengths.ok_or(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))?; &gt;+ let lengths = &gt;+ lengths.ok_or(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))?; &gt; Ok(BoxShadow { &gt; base: SimpleShadow { &gt; color: color, &gt; horizontal: lengths.0, &gt; vertical: lengths.1, &gt; blur: lengths.2, &gt; }, &gt; spread: lengths.3, &gt;@@ -159,17 +160,18 @@ impl Parse for BoxShadow { &gt; &gt; impl ToComputedValue for BoxShadow { &gt; type ComputedValue = ComputedBoxShadow; &gt; &gt; #[inline] &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Self::ComputedValue { &gt; ComputedBoxShadow { &gt; base: self.base.to_computed_value(context), &gt;- spread: self.spread &gt;+ spread: self &gt;+ .spread &gt; .as_ref() &gt; .unwrap_or(&amp;Length::zero()) &gt; .to_computed_value(context), &gt; inset: self.inset, &gt; } &gt; } &gt; &gt; #[inline] &gt;@@ -266,23 +268,25 @@ impl Parse for SimpleShadow { &gt; } &gt; &gt; impl ToComputedValue for SimpleShadow { &gt; type ComputedValue = ComputedSimpleShadow; &gt; &gt; #[inline] &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Self::ComputedValue { &gt; ComputedSimpleShadow { &gt;- color: self.color &gt;+ color: self &gt;+ .color &gt; .as_ref() &gt; .unwrap_or(&amp;Color::currentcolor()) &gt; .to_computed_value(context), &gt; horizontal: self.horizontal.to_computed_value(context), &gt; vertical: self.vertical.to_computed_value(context), &gt;- blur: self.blur &gt;+ blur: self &gt;+ .blur &gt; .as_ref() &gt; .unwrap_or(&amp;NonNegativeLength::zero()) &gt; .to_computed_value(context), &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt;diff --git a/servo/components/style/values/specified/font.rs b/servo/components/style/values/specified/font.rs &gt;index 8d8355821e8c..45f78da081d2 100644 &gt;--- a/servo/components/style/values/specified/font.rs &gt;+++ b/servo/components/style/values/specified/font.rs &gt;@@ -1,37 +1,39 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Specified values for font properties &gt; &gt;-use Atom; &gt; use app_units::Au; &gt; use byteorder::{BigEndian, ByteOrder}; &gt; use cssparser::{Parser, Token}; &gt; #[cfg(feature = "gecko")] &gt; use gecko_bindings::bindings; &gt; #[cfg(feature = "gecko")] &gt; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; &gt; use parser::{Parse, ParserContext}; &gt; use properties::longhands::system_font::SystemFont; &gt; use std::fmt::{self, Write}; &gt;+use style_traits::values::SequenceWriter; &gt; use style_traits::{CssWriter, KeywordsCollectFn, ParseError}; &gt; use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; &gt;-use style_traits::values::SequenceWriter; &gt;-use values::CustomIdent; &gt;-use values::computed::{Angle as ComputedAngle, Percentage as ComputedPercentage}; &gt;-use values::computed::{font as computed, Context, Length, NonNegativeLength, ToComputedValue}; &gt; use values::computed::font::{FamilyName, FontFamilyList, FontStyleAngle, SingleFontFamily}; &gt;-use values::generics::NonNegative; &gt;-use values::generics::font::{KeywordSize, VariationValue}; &gt;+use values::computed::{font as computed, Context, Length, NonNegativeLength, ToComputedValue}; &gt;+use values::computed::{Angle as ComputedAngle, Percentage as ComputedPercentage}; &gt; use values::generics::font::{self as generics, FeatureTagValue, FontSettings, FontTag}; &gt;-use values::specified::{AllowQuirks, Angle, Integer, LengthOrPercentage, NoCalcLength, Number, Percentage}; &gt;+use values::generics::font::{KeywordSize, VariationValue}; &gt;+use values::generics::NonNegative; &gt; use values::specified::length::{FontBaseSize, AU_PER_PT, AU_PER_PX}; &gt;+use values::specified::{ &gt;+ AllowQuirks, Angle, Integer, LengthOrPercentage, NoCalcLength, Number, Percentage, &gt;+}; &gt;+use values::CustomIdent; &gt;+use Atom; &gt; &gt; // FIXME(emilio): The system font code is copy-pasta, and should be cleaned up. &gt; macro_rules! system_font_methods { &gt; ($ty:ident, $field:ident) =&gt; { &gt; system_font_methods!($ty); &gt; &gt; fn compute_system(&amp;self, _context: &amp;Context) -&gt; &lt;$ty as ToComputedValue&gt;::ComputedValue { &gt; debug_assert!(matches!(*self, $ty::System(..))); &gt;@@ -143,19 +145,19 @@ impl ToComputedValue for FontWeight { &gt; .clone_font_weight() &gt; .lighter(), &gt; FontWeight::System(_) =&gt; self.compute_system(context), &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;computed::FontWeight) -&gt; Self { &gt;- FontWeight::Absolute(AbsoluteFontWeight::Weight( &gt;- Number::from_computed_value(&amp;computed.0) &gt;- )) &gt;+ FontWeight::Absolute(AbsoluteFontWeight::Weight(Number::from_computed_value( &gt;+ &amp;computed.0, &gt;+ ))) &gt; } &gt; } &gt; &gt; /// An absolute font-weight value for a @font-face rule. &gt; /// &gt; /// https://drafts.csswg.org/css-fonts-4/#font-weight-absolute-values &gt; #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] &gt; pub enum AbsoluteFontWeight { &gt;@@ -169,42 +171,39 @@ pub enum AbsoluteFontWeight { &gt; Bold, &gt; } &gt; &gt; impl AbsoluteFontWeight { &gt; /// Returns the computed value for this absolute font weight. &gt; pub fn compute(&amp;self) -&gt; computed::FontWeight { &gt; match *self { &gt; AbsoluteFontWeight::Weight(weight) =&gt; { &gt;- computed::FontWeight( &gt;- weight.get().max(MIN_FONT_WEIGHT).min(MAX_FONT_WEIGHT) &gt;- ) &gt;- }, &gt;+ computed::FontWeight(weight.get().max(MIN_FONT_WEIGHT).min(MAX_FONT_WEIGHT)) &gt;+ } &gt; AbsoluteFontWeight::Normal =&gt; computed::FontWeight::normal(), &gt; AbsoluteFontWeight::Bold =&gt; computed::FontWeight::bold(), &gt; } &gt; } &gt; } &gt; &gt; impl Parse for AbsoluteFontWeight { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; if let Ok(number) = input.try(|input| Number::parse(context, input)) { &gt; // We could add another AllowedNumericType value, but it doesn't &gt; // seem worth it just for a single property with such a weird range, &gt; // so we do the clamping here manually. &gt;- if !number.was_calc() &amp;&amp; &gt;- (number.get() &lt; MIN_FONT_WEIGHT || number.get() &gt; MAX_FONT_WEIGHT) { &gt;- return Err(input.new_custom_error( &gt;- StyleParseErrorKind::UnspecifiedError &gt;- )) &gt;+ if !number.was_calc() &gt;+ &amp;&amp; (number.get() &lt; MIN_FONT_WEIGHT || number.get() &gt; MAX_FONT_WEIGHT) &gt;+ { &gt;+ return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt;- return Ok(AbsoluteFontWeight::Weight(number)) &gt;+ return Ok(AbsoluteFontWeight::Weight(number)); &gt; } &gt; &gt; Ok(try_match_ident_ignore_ascii_case! { input, &gt; "normal" =&gt; AbsoluteFontWeight::Normal, &gt; "bold" =&gt; AbsoluteFontWeight::Bold, &gt; }) &gt; } &gt; } &gt;@@ -270,17 +269,16 @@ impl ToComputedValue for SpecifiedFontStyle { &gt; generics::FontStyle::Italic =&gt; generics::FontStyle::Italic, &gt; generics::FontStyle::Oblique(ref angle) =&gt; { &gt; generics::FontStyle::Oblique(Angle::from_computed_value(&amp;angle.0)) &gt; } &gt; } &gt; } &gt; } &gt; &gt;- &gt; /// The default angle for `font-style: oblique`. &gt; /// &gt; /// NOTE(emilio): As of right now this diverges from the spec, which specifies &gt; /// 20, because it's not updated yet to account for the resolution in: &gt; /// &gt; /// https://github.com/w3c/csswg-drafts/issues/2295 &gt; pub const DEFAULT_FONT_STYLE_OBLIQUE_ANGLE_DEGREES: f32 = 14.; &gt; &gt;@@ -294,55 +292,53 @@ pub const FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES: f32 = 90.; &gt; &gt; /// The minimum angle value that `font-style: oblique` should compute to. &gt; pub const FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES: f32 = -90.; &gt; &gt; impl SpecifiedFontStyle { &gt; /// Gets a clamped angle from a specified Angle. &gt; pub fn compute_angle(angle: &amp;Angle) -&gt; ComputedAngle { &gt; ComputedAngle::Deg( &gt;- angle.degrees() &gt;+ angle &gt;+ .degrees() &gt; .max(FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES) &gt;- .min(FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES) &gt;+ .min(FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES), &gt; ) &gt; } &gt; &gt; /// Parse a suitable angle for font-style: oblique. &gt; pub fn parse_angle&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Angle, ParseError&lt;'i&gt;&gt; { &gt; let angle = Angle::parse(context, input)?; &gt; if angle.was_calc() { &gt; return Ok(angle); &gt; } &gt; &gt; let degrees = angle.degrees(); &gt;- if degrees &lt; FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES || &gt;- degrees &gt; FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES &gt;+ if degrees &lt; FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES &gt;+ || degrees &gt; FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES &gt; { &gt;- return Err(input.new_custom_error( &gt;- StyleParseErrorKind::UnspecifiedError &gt;- )); &gt;+ return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt;- return Ok(angle) &gt;+ return Ok(angle); &gt; } &gt; &gt; /// The default angle for `font-style: oblique`. &gt; pub fn default_angle() -&gt; Angle { &gt; Angle::from_degrees( &gt; DEFAULT_FONT_STYLE_OBLIQUE_ANGLE_DEGREES, &gt; /* was_calc = */ false, &gt; ) &gt; } &gt; } &gt; &gt; /// The specified value of the `font-style` property. &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToCss)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] &gt; #[allow(missing_docs)] &gt; pub enum FontStyle { &gt; Specified(SpecifiedFontStyle), &gt; #[css(skip)] &gt; System(SystemFont), &gt; } &gt; &gt; impl FontStyle { &gt;@@ -370,36 +366,36 @@ impl ToComputedValue for FontStyle { &gt; } &gt; } &gt; &gt; impl Parse for FontStyle { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt;- Ok(FontStyle::Specified(SpecifiedFontStyle::parse(context, input)?)) &gt;+ Ok(FontStyle::Specified(SpecifiedFontStyle::parse( &gt;+ context, input, &gt;+ )?)) &gt; } &gt; } &gt; &gt; /// A value for the `font-stretch` property. &gt; /// &gt; /// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop &gt; #[allow(missing_docs)] &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToCss)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] &gt; pub enum FontStretch { &gt; Stretch(Percentage), &gt; Keyword(FontStretchKeyword), &gt; #[css(skip)] &gt; System(SystemFont), &gt; } &gt; &gt; /// A keyword value for `font-stretch`. &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, &gt;- ToCss)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)] &gt; #[allow(missing_docs)] &gt; pub enum FontStretchKeyword { &gt; Normal, &gt; Condensed, &gt; UltraCondensed, &gt; ExtraCondensed, &gt; SemiCondensed, &gt; SemiExpanded, &gt;@@ -491,20 +487,18 @@ impl Parse for FontStretch { &gt; &gt; impl ToComputedValue for FontStretch { &gt; type ComputedValue = computed::FontStretch; &gt; &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Self::ComputedValue { &gt; match *self { &gt; FontStretch::Stretch(ref percentage) =&gt; { &gt; computed::FontStretch(NonNegative(percentage.to_computed_value(context))) &gt;- }, &gt;- FontStretch::Keyword(ref kw) =&gt; { &gt;- computed::FontStretch(NonNegative(kw.compute())) &gt;- }, &gt;+ } &gt;+ FontStretch::Keyword(ref kw) =&gt; computed::FontStretch(NonNegative(kw.compute())), &gt; FontStretch::System(_) =&gt; self.compute_system(context), &gt; } &gt; } &gt; &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; FontStretch::Stretch(Percentage::from_computed_value(&amp;(computed.0).0)) &gt; } &gt; } &gt;@@ -589,17 +583,17 @@ impl ToComputedValue for FontFamily { &gt; #[cfg(feature = "gecko")] &gt; impl MallocSizeOf for FontFamily { &gt; fn size_of(&amp;self, _ops: &amp;mut MallocSizeOfOps) -&gt; usize { &gt; match *self { &gt; FontFamily::Values(ref v) =&gt; { &gt; // Although a SharedFontList object is refcounted, we always &gt; // attribute its size to the specified value. &gt; unsafe { bindings::Gecko_SharedFontList_SizeOfIncludingThis(v.0.get()) } &gt;- }, &gt;+ } &gt; FontFamily::System(_) =&gt; 0, &gt; } &gt; } &gt; } &gt; &gt; impl Parse for FontFamily { &gt; /// &lt;family-name&gt;# &gt; /// &lt;family-name&gt; = &lt;string&gt; | [ &lt;ident&gt;+ ] &gt;@@ -620,17 +614,17 @@ impl Parse for FamilyName { &gt; fn parse&lt;'i, 't&gt;( &gt; _: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; match SingleFontFamily::parse(input) { &gt; Ok(SingleFontFamily::FamilyName(name)) =&gt; Ok(name), &gt; Ok(SingleFontFamily::Generic(_)) =&gt; { &gt; Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt;- }, &gt;+ } &gt; Err(e) =&gt; Err(e), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] &gt; /// Preserve the readability of text when font fallback occurs &gt; pub enum FontSizeAdjust { &gt;@@ -656,27 +650,27 @@ impl FontSizeAdjust { &gt; impl ToComputedValue for FontSizeAdjust { &gt; type ComputedValue = computed::FontSizeAdjust; &gt; &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Self::ComputedValue { &gt; match *self { &gt; FontSizeAdjust::None =&gt; computed::FontSizeAdjust::None, &gt; FontSizeAdjust::Number(ref n) =&gt; { &gt; computed::FontSizeAdjust::Number(n.to_computed_value(context)) &gt;- }, &gt;+ } &gt; FontSizeAdjust::System(_) =&gt; self.compute_system(context), &gt; } &gt; } &gt; &gt; fn from_computed_value(computed: &amp;computed::FontSizeAdjust) -&gt; Self { &gt; match *computed { &gt; computed::FontSizeAdjust::None =&gt; FontSizeAdjust::None, &gt; computed::FontSizeAdjust::Number(ref v) =&gt; { &gt; FontSizeAdjust::Number(Number::from_computed_value(v)) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl Parse for FontSizeAdjust { &gt; /// none | &lt;number&gt; &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt;@@ -685,18 +679,17 @@ impl Parse for FontSizeAdjust { &gt; if input &gt; .try(|input| input.expect_ident_matching("none")) &gt; .is_ok() &gt; { &gt; return Ok(FontSizeAdjust::None); &gt; } &gt; &gt; Ok(FontSizeAdjust::Number(Number::parse_non_negative( &gt;- context, &gt;- input, &gt;+ context, input, &gt; )?)) &gt; } &gt; } &gt; &gt; /// Additional information for specified keyword-derived font sizes. &gt; pub type KeywordInfo = generics::KeywordInfo&lt;NonNegativeLength&gt;; &gt; &gt; impl KeywordInfo { &gt;@@ -865,32 +858,32 @@ impl FontSize { &gt; let size = match *self { &gt; FontSize::Length(LengthOrPercentage::Length(NoCalcLength::FontRelative(value))) =&gt; { &gt; if let FontRelativeLength::Em(em) = value { &gt; // If the parent font was keyword-derived, this is too. &gt; // Tack the em unit onto the factor &gt; info = compose_keyword(em); &gt; } &gt; value.to_computed_value(context, base_size).into() &gt;- }, &gt;+ } &gt; FontSize::Length(LengthOrPercentage::Length(NoCalcLength::ServoCharacterWidth( &gt; value, &gt; ))) =&gt; value.to_computed_value(base_size.resolve(context)).into(), &gt; FontSize::Length(LengthOrPercentage::Length(NoCalcLength::Absolute(ref l))) =&gt; { &gt; context.maybe_zoom_text(l.to_computed_value(context).into()) &gt;- }, &gt;+ } &gt; FontSize::Length(LengthOrPercentage::Length(ref l)) =&gt; { &gt; l.to_computed_value(context).into() &gt;- }, &gt;+ } &gt; FontSize::Length(LengthOrPercentage::Percentage(pc)) =&gt; { &gt; // If the parent font was keyword-derived, this is too. &gt; // Tack the % onto the factor &gt; info = compose_keyword(pc.0); &gt; base_size.resolve(context).scale_by(pc.0).into() &gt;- }, &gt;+ } &gt; FontSize::Length(LengthOrPercentage::Calc(ref calc)) =&gt; { &gt; let parent = context.style().get_parent_font().clone_font_size(); &gt; // if we contain em/% units and the parent was keyword derived, this is too &gt; // Extract the ratio/offset and compose it &gt; if (calc.em.is_some() || calc.percentage.is_some()) &amp;&amp; parent.keyword_info.is_some() &gt; { &gt; let ratio = calc.em.unwrap_or(0.) + calc.percentage.map_or(0., |pc| pc.0); &gt; // Compute it, but shave off the font-relative part (em, %). &gt;@@ -901,56 +894,57 @@ impl FontSize { &gt; // &gt; // There's no particular "right answer" for what to do here, &gt; // Gecko recascades as if the font had changed, we instead &gt; // track the changes and reapply, which means that we carry &gt; // over old computed ex/ch values whilst Gecko recomputes &gt; // new ones. &gt; // &gt; // This is enough of an edge case to not really matter. &gt;- let abs = calc.to_computed_value_zoomed( &gt;- context, &gt;- FontBaseSize::InheritedStyleButStripEmUnits, &gt;- ).length_component(); &gt;+ let abs = calc &gt;+ .to_computed_value_zoomed( &gt;+ context, &gt;+ FontBaseSize::InheritedStyleButStripEmUnits, &gt;+ ).length_component(); &gt; &gt; info = parent.keyword_info.map(|i| i.compose(ratio, abs.into())); &gt; } &gt; let calc = calc.to_computed_value_zoomed(context, base_size); &gt; calc.to_used_value(Some(base_size.resolve(context))) &gt; .unwrap() &gt; .into() &gt;- }, &gt;+ } &gt; FontSize::Keyword(i) =&gt; { &gt; // As a specified keyword, this is keyword derived &gt; info = Some(i); &gt; i.to_computed_value(context) &gt;- }, &gt;+ } &gt; FontSize::Smaller =&gt; { &gt; info = compose_keyword(1. / LARGER_FONT_SIZE_RATIO); &gt; FontRelativeLength::Em(1. / LARGER_FONT_SIZE_RATIO) &gt; .to_computed_value(context, base_size) &gt; .into() &gt;- }, &gt;+ } &gt; FontSize::Larger =&gt; { &gt; info = compose_keyword(LARGER_FONT_SIZE_RATIO); &gt; FontRelativeLength::Em(LARGER_FONT_SIZE_RATIO) &gt; .to_computed_value(context, base_size) &gt; .into() &gt;- }, &gt;+ } &gt; &gt; FontSize::System(_) =&gt; { &gt; #[cfg(feature = "servo")] &gt; { &gt; unreachable!() &gt; } &gt; #[cfg(feature = "gecko")] &gt; { &gt; context.cached_system_font.as_ref().unwrap().font_size.size &gt; } &gt;- }, &gt;+ } &gt; }; &gt; computed::FontSize { &gt; size: size, &gt; keyword_info: info, &gt; } &gt; } &gt; } &gt; &gt;@@ -1009,20 +1003,20 @@ impl FontSize { &gt; mut computed: computed::FontSize, &gt; ) { &gt; // we could use clone_language and clone_font_family() here but that's &gt; // expensive. Do it only in gecko mode for now. &gt; #[cfg(feature = "gecko")] &gt; { &gt; // if the language or generic changed, we need to recalculate &gt; // the font size from the stored font-size origin information. &gt;- if context.builder.get_font().gecko().mLanguage.mRawPtr != &gt;- context.builder.get_parent_font().gecko().mLanguage.mRawPtr || &gt;- context.builder.get_font().gecko().mGenericID != &gt;- context.builder.get_parent_font().gecko().mGenericID &gt;+ if context.builder.get_font().gecko().mLanguage.mRawPtr &gt;+ != context.builder.get_parent_font().gecko().mLanguage.mRawPtr &gt;+ || context.builder.get_font().gecko().mGenericID &gt;+ != context.builder.get_parent_font().gecko().mGenericID &gt; { &gt; if let Some(info) = computed.keyword_info { &gt; computed.size = info.to_computed_value(context); &gt; } &gt; } &gt; } &gt; &gt; let device = context.builder.device; &gt;@@ -1107,22 +1101,22 @@ pub enum VariantAlternates { &gt; pub struct VariantAlternatesList( &gt; #[css(if_empty = "normal", iterable)] pub Box&lt;[VariantAlternates]&gt;, &gt; ); &gt; &gt; impl VariantAlternatesList { &gt; /// Returns the length of all variant alternates. &gt; pub fn len(&amp;self) -&gt; usize { &gt; self.0.iter().fold(0, |acc, alternate| match *alternate { &gt;- VariantAlternates::Swash(_) | &gt;- VariantAlternates::Stylistic(_) | &gt;- VariantAlternates::Ornaments(_) | &gt;- VariantAlternates::Annotation(_) =&gt; acc + 1, &gt;- VariantAlternates::Styleset(ref slice) | &gt;- VariantAlternates::CharacterVariant(ref slice) =&gt; acc + slice.len(), &gt;+ VariantAlternates::Swash(_) &gt;+ | VariantAlternates::Stylistic(_) &gt;+ | VariantAlternates::Ornaments(_) &gt;+ | VariantAlternates::Annotation(_) =&gt; acc + 1, &gt;+ VariantAlternates::Styleset(ref slice) &gt;+ | VariantAlternates::CharacterVariant(ref slice) =&gt; acc + slice.len(), &gt; _ =&gt; acc, &gt; }) &gt; } &gt; } &gt; &gt; #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] &gt; /// Control over the selection of these alternate glyphs &gt; pub enum FontVariantAlternates { &gt;@@ -1934,18 +1928,17 @@ impl Parse for FontFeatureSettings { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;FontFeatureSettings, ParseError&lt;'i&gt;&gt; { &gt; SpecifiedFontFeatureSettings::parse(context, input).map(FontFeatureSettings::Value) &gt; } &gt; } &gt; &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; /// Whether user agents are allowed to synthesize bold or oblique font faces &gt; /// when a font family lacks bold or italic faces &gt; pub struct FontSynthesis { &gt; /// If a `font-weight` is requested that the font family does not contain, &gt; /// the user agent may synthesize the requested weight from the weights &gt; /// that do exist in the font family. &gt; #[css(represents_keyword)] &gt; pub weight: bool, &gt;@@ -2079,17 +2072,17 @@ impl ToComputedValue for FontLanguageOverride { &gt; return computed::FontLanguageOverride(0); &gt; } &gt; let mut computed_lang = lang.to_string(); &gt; while computed_lang.len() &lt; 4 { &gt; computed_lang.push(' '); &gt; } &gt; let bytes = computed_lang.into_bytes(); &gt; computed::FontLanguageOverride(BigEndian::read_u32(&amp;bytes)) &gt;- }, &gt;+ } &gt; FontLanguageOverride::System(_) =&gt; self.compute_system(context), &gt; } &gt; } &gt; #[inline] &gt; fn from_computed_value(computed: &amp;computed::FontLanguageOverride) -&gt; Self { &gt; if computed.0 == 0 { &gt; return FontLanguageOverride::Normal; &gt; } &gt;@@ -2212,36 +2205,36 @@ impl Parse for VariationValue&lt;Number&gt; { &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let tag = FontTag::parse(context, input)?; &gt; let value = Number::parse(context, input)?; &gt; Ok(Self { tag, value }) &gt; } &gt; } &gt; &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; /// text-zoom. Enable if true, disable if false &gt; pub struct XTextZoom(#[css(skip)] pub bool); &gt; &gt; impl Parse for XTextZoom { &gt; fn parse&lt;'i, 't&gt;( &gt; _: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;XTextZoom, ParseError&lt;'i&gt;&gt; { &gt; debug_assert!( &gt; false, &gt; "Should be set directly by presentation attributes only." &gt; ); &gt; Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt; } &gt; } &gt; &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; /// Internal property that reflects the lang attribute &gt; pub struct XLang(#[css(skip)] pub Atom); &gt; &gt; impl XLang { &gt; #[inline] &gt; /// Get default value for `-x-lang` &gt; pub fn get_initial_value() -&gt; XLang { &gt; XLang(atom!("")) &gt;@@ -2319,18 +2312,17 @@ impl Parse for MozScriptLevel { &gt; return Ok(MozScriptLevel::Relative(i)); &gt; } &gt; input.expect_ident_matching("auto")?; &gt; Ok(MozScriptLevel::Auto) &gt; } &gt; } &gt; &gt; #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] &gt;-#[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToComputedValue, &gt;- ToCss)] &gt;+#[derive(Clone, Copy, Debug, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; /// Specifies the multiplier to be used to adjust font size &gt; /// due to changes in scriptlevel. &gt; /// &gt; /// Ref: https://www.w3.org/TR/MathML3/chapter3.html#presm.mstyle.attrs &gt; pub struct MozScriptSizeMultiplier(pub f32); &gt; &gt; impl MozScriptSizeMultiplier { &gt; #[inline] &gt;diff --git a/servo/components/style/values/specified/gecko.rs b/servo/components/style/values/specified/gecko.rs &gt;index 847d632511e7..adb16c44cc8f 100644 &gt;--- a/servo/components/style/values/specified/gecko.rs &gt;+++ b/servo/components/style/values/specified/gecko.rs &gt;@@ -4,18 +4,18 @@ &gt; &gt; //! Specified types for legacy Gecko-only properties. &gt; &gt; use cssparser::{Parser, Token}; &gt; use gecko::values::GeckoStyleCoordConvertible; &gt; use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut}; &gt; use parser::{Parse, ParserContext}; &gt; use std::fmt; &gt;-use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt; use style_traits::values::SequenceWriter; &gt;+use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt; use values::computed; &gt; use values::computed::length::CSSPixelLength; &gt; use values::generics::gecko::ScrollSnapPoint as GenericScrollSnapPoint; &gt; use values::generics::rect::Rect; &gt; use values::specified::length::LengthOrPercentage; &gt; &gt; /// A specified type for scroll snap points. &gt; pub type ScrollSnapPoint = GenericScrollSnapPoint&lt;LengthOrPercentage&gt;; &gt;@@ -54,17 +54,17 @@ impl Parse for PixelOrPercentage { &gt; let value = match *token { &gt; Token::Dimension { &gt; value, ref unit, .. &gt; } =&gt; { &gt; match_ignore_ascii_case! { unit, &gt; "px" =&gt; Ok(PixelOrPercentage::Pixel(CSSPixelLength::new(value))), &gt; _ =&gt; Err(()), &gt; } &gt;- }, &gt;+ } &gt; Token::Percentage { unit_value, .. } =&gt; Ok(PixelOrPercentage::Percentage( &gt; computed::Percentage(unit_value), &gt; )), &gt; _ =&gt; Err(()), &gt; }; &gt; value.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt; } &gt; } &gt;diff --git a/servo/components/style/values/specified/grid.rs b/servo/components/style/values/specified/grid.rs &gt;index 830cccaf2e24..4e96f9e7b80e 100644 &gt;--- a/servo/components/style/values/specified/grid.rs &gt;+++ b/servo/components/style/values/specified/grid.rs &gt;@@ -4,33 +4,34 @@ &gt; &gt; //! CSS handling for the computed value of &gt; //! [grids](https://drafts.csswg.org/css-grid/) &gt; &gt; use cssparser::{ParseError as CssParseError, Parser, Token}; &gt; use parser::{Parse, ParserContext}; &gt; use std::mem; &gt; use style_traits::{ParseError, StyleParseErrorKind}; &gt;-use values::{CSSFloat, CustomIdent}; &gt; use values::computed::{self, Context, ToComputedValue}; &gt; use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth}; &gt; use values::generics::grid::{LineNameList, TrackKeyword, TrackRepeat, TrackSize}; &gt; use values::generics::grid::{TrackList, TrackListType, TrackListValue}; &gt; use values::specified::{Integer, LengthOrPercentage}; &gt;+use values::{CSSFloat, CustomIdent}; &gt; &gt; /// Parse a single flexible length. &gt; pub fn parse_flex&lt;'i, 't&gt;(input: &amp;mut Parser&lt;'i, 't&gt;) -&gt; Result&lt;CSSFloat, ParseError&lt;'i&gt;&gt; { &gt; let location = input.current_source_location(); &gt; match *input.next()? { &gt; Token::Dimension { &gt; value, ref unit, .. &gt;- } if unit.eq_ignore_ascii_case("fr") &amp;&amp; value.is_sign_positive() =&gt; &gt;+ } &gt;+ if unit.eq_ignore_ascii_case("fr") &amp;&amp; value.is_sign_positive() =&gt; &gt; { &gt; Ok(value) &gt;- }, &gt;+ } &gt; ref t =&gt; Err(location.new_unexpected_token_error(t.clone())), &gt; } &gt; } &gt; &gt; impl Parse for TrackBreadth&lt;LengthOrPercentage&gt; { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt;@@ -59,29 +60,30 @@ impl Parse for TrackSize&lt;LengthOrPercentage&gt; { &gt; if input.try(|i| i.expect_function_matching("minmax")).is_ok() { &gt; return input.parse_nested_block(|input| { &gt; let inflexible_breadth = &gt; match input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) { &gt; Ok(lop) =&gt; TrackBreadth::Breadth(lop), &gt; Err(..) =&gt; { &gt; let keyword = TrackKeyword::parse(input)?; &gt; TrackBreadth::Keyword(keyword) &gt;- }, &gt;+ } &gt; }; &gt; &gt; input.expect_comma()?; &gt; Ok(TrackSize::Minmax( &gt; inflexible_breadth, &gt; TrackBreadth::parse(context, input)?, &gt; )) &gt; }); &gt; } &gt; &gt; input.expect_function_matching("fit-content")?; &gt;- let lop = input.parse_nested_block(|i| LengthOrPercentage::parse_non_negative(context, i))?; &gt;+ let lop = &gt;+ input.parse_nested_block(|i| LengthOrPercentage::parse_non_negative(context, i))?; &gt; Ok(TrackSize::FitContent(lop)) &gt; } &gt; } &gt; &gt; /// Parse the grid line names into a vector of owned strings. &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-grid/#typedef-line-names&gt; &gt; pub fn parse_line_names&lt;'i, 't&gt;( &gt;@@ -170,17 +172,19 @@ impl TrackRepeat&lt;LengthOrPercentage, Integer&gt; { &gt; .try(parse_line_names) &gt; .unwrap_or(vec![].into_boxed_slice()), &gt; ); &gt; break; &gt; } &gt; } else { &gt; if values.is_empty() { &gt; // expecting at least one &lt;track-size&gt; &gt;- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt;+ return Err( &gt;+ input.new_custom_error(StyleParseErrorKind::UnspecifiedError) &gt;+ ); &gt; } &gt; &gt; names.push(current_names); // final `&lt;line-names&gt;` &gt; break; // no more &lt;track-size&gt;, breaking &gt; } &gt; } &gt; &gt; let repeat = TrackRepeat { &gt;@@ -212,19 +216,21 @@ impl Parse for TrackList&lt;LengthOrPercentage, Integer&gt; { &gt; // where idx points to the position of the &lt;auto-repeat&gt; in the track list. If there &gt; // is any repeat before &lt;auto-repeat&gt;, we need to take the number of repetitions into &gt; // account to set the position of &lt;auto-repeat&gt; so it remains the same while computing &gt; // values. &gt; let mut auto_offset = 0; &gt; // assume that everything is &lt;fixed-size&gt;. This flag is useful when we encounter &lt;auto-repeat&gt; &gt; let mut atleast_one_not_fixed = false; &gt; loop { &gt;- current_names.extend_from_slice(&amp;mut input &gt;- .try(parse_line_names) &gt;- .unwrap_or(vec![].into_boxed_slice())); &gt;+ current_names.extend_from_slice( &gt;+ &amp;mut input &gt;+ .try(parse_line_names) &gt;+ .unwrap_or(vec![].into_boxed_slice()), &gt;+ ); &gt; if let Ok(track_size) = input.try(|i| TrackSize::parse(context, i)) { &gt; if !track_size.is_fixed() { &gt; atleast_one_not_fixed = true; &gt; if auto_repeat.is_some() { &gt; // &lt;auto-track-list&gt; only accepts &lt;fixed-size&gt; and &lt;fixed-repeat&gt; &gt; return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt; } &gt;@@ -239,31 +245,35 @@ impl Parse for TrackList&lt;LengthOrPercentage, Integer&gt; { &gt; list_type = TrackListType::Normal; // &lt;explicit-track-list&gt; doesn't contain repeat() &gt; } &gt; &gt; match type_ { &gt; RepeatType::Normal =&gt; { &gt; atleast_one_not_fixed = true; &gt; if auto_repeat.is_some() { &gt; // only &lt;fixed-repeat&gt; &gt;- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt;+ return Err( &gt;+ input.new_custom_error(StyleParseErrorKind::UnspecifiedError) &gt;+ ); &gt; } &gt;- }, &gt;+ } &gt; RepeatType::Auto =&gt; { &gt; if auto_repeat.is_some() || atleast_one_not_fixed { &gt; // We've either seen &lt;auto-repeat&gt; earlier, or there's at least one non-fixed value &gt;- return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt;+ return Err( &gt;+ input.new_custom_error(StyleParseErrorKind::UnspecifiedError) &gt;+ ); &gt; } &gt; &gt; list_type = TrackListType::Auto(values.len() as u16 + auto_offset); &gt; auto_repeat = Some(repeat); &gt; let vec = mem::replace(&amp;mut current_names, vec![]); &gt; names.push(vec.into_boxed_slice()); &gt; continue; &gt;- }, &gt;+ } &gt; RepeatType::Fixed =&gt; (), &gt; } &gt; &gt; let vec = mem::replace(&amp;mut current_names, vec![]); &gt; names.push(vec.into_boxed_slice()); &gt; if let RepeatCount::Number(num) = repeat.count { &gt; auto_offset += (num.value() - 1) as u16; &gt; } &gt;@@ -312,42 +322,43 @@ impl ToComputedValue for TrackList&lt;LengthOrPercentage, Integer&gt; { &gt; continue; &gt; } &gt; &gt; match self.values[pos] { &gt; TrackListValue::TrackSize(ref size) =&gt; { &gt; let vec = mem::replace(&amp;mut prev_names, vec![]); &gt; line_names.push(vec.into_boxed_slice()); &gt; values.push(TrackListValue::TrackSize(size.to_computed_value(context))); &gt;- }, &gt;+ } &gt; TrackListValue::TrackRepeat(ref repeat) =&gt; { &gt; // If the repeat count is numeric, we expand and merge the values. &gt; let mut repeat = repeat.expand(); &gt; let mut repeat_names_iter = repeat.line_names.iter(); &gt; for (size, repeat_names) in &gt; repeat.track_sizes.drain(..).zip(&amp;mut repeat_names_iter) &gt; { &gt; prev_names.extend_from_slice(&amp;repeat_names); &gt; let vec = mem::replace(&amp;mut prev_names, vec![]); &gt; line_names.push(vec.into_boxed_slice()); &gt; values.push(TrackListValue::TrackSize(size.to_computed_value(context))); &gt; } &gt; &gt; if let Some(names) = repeat_names_iter.next() { &gt; prev_names.extend_from_slice(&amp;names); &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; TrackList { &gt; list_type: self.list_type.to_computed_value(context), &gt; values: values, &gt; line_names: line_names.into_boxed_slice(), &gt;- auto_repeat: self.auto_repeat &gt;+ auto_repeat: self &gt;+ .auto_repeat &gt; .clone() &gt; .map(|repeat| repeat.to_computed_value(context)), &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; let mut values = Vec::with_capacity(computed.values.len() + 1); &gt;diff --git a/servo/components/style/values/specified/image.rs b/servo/components/style/values/specified/image.rs &gt;index 64d24573f4a7..7f026c8fcfe3 100644 &gt;--- a/servo/components/style/values/specified/image.rs &gt;+++ b/servo/components/style/values/specified/image.rs &gt;@@ -2,38 +2,38 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! CSS handling for the specified value of &gt; //! [`image`][image]s &gt; //! &gt; //! [image]: https://drafts.csswg.org/css-images/#image-values &gt; &gt;-use Atom; &gt; use cssparser::{Parser, Token}; &gt; use custom_properties::SpecifiedValue; &gt; use parser::{Parse, ParserContext}; &gt; use selectors::parser::SelectorParseErrorKind; &gt; #[cfg(feature = "servo")] &gt; use servo_url::ServoUrl; &gt; use std::cmp::Ordering; &gt; use std::f32::consts::PI; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError}; &gt;-use style_traits::{StyleParseErrorKind, SpecifiedValueInfo, ToCss}; &gt;-use values::{Either, None_}; &gt;+use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; &gt; #[cfg(feature = "gecko")] &gt; use values::computed::{Context, Position as ComputedPosition, ToComputedValue}; &gt;-use values::generics::image::{self as generic, Circle, CompatMode, Ellipse, ShapeExtent}; &gt; use values::generics::image::PaintWorklet; &gt;+use values::generics::image::{self as generic, Circle, CompatMode, Ellipse, ShapeExtent}; &gt; use values::generics::position::Position as GenericPosition; &gt;-use values::specified::{Angle, Color, Length, LengthOrPercentage}; &gt;-use values::specified::{Number, NumberOrPercentage, Percentage}; &gt; use values::specified::position::{LegacyPosition, Position, PositionComponent, Side, X, Y}; &gt; use values::specified::url::SpecifiedImageUrl; &gt;+use values::specified::{Angle, Color, Length, LengthOrPercentage}; &gt;+use values::specified::{Number, NumberOrPercentage, Percentage}; &gt;+use values::{Either, None_}; &gt;+use Atom; &gt; &gt; /// A specified image layer. &gt; pub type ImageLayer = Either&lt;None_, Image&gt;; &gt; &gt; /// Specified values for an image according to CSS-IMAGES. &gt; /// &lt;https://drafts.csswg.org/css-images/#image-values&gt; &gt; pub type Image = generic::Image&lt;Gradient, MozImageRect, SpecifiedImageUrl&gt;; &gt; &gt;@@ -50,29 +50,29 @@ pub type Gradient = &gt; generic::Gradient&lt;LineDirection, Length, LengthOrPercentage, GradientPosition, Color, Angle&gt;; &gt; &gt; impl SpecifiedValueInfo for Gradient { &gt; const SUPPORTED_TYPES: u8 = CssType::GRADIENT; &gt; &gt; fn collect_completion_keywords(f: KeywordsCollectFn) { &gt; // This list here should keep sync with that in Gradient::parse. &gt; f(&amp;[ &gt;- "linear-gradient", &gt;- "-webkit-linear-gradient", &gt;- "-moz-linear-gradient", &gt;- "repeating-linear-gradient", &gt;- "-webkit-repeating-linear-gradient", &gt;- "-moz-repeating-linear-gradient", &gt;- "radial-gradient", &gt;- "-webkit-radial-gradient", &gt;- "-moz-radial-gradient", &gt;- "repeating-radial-gradient", &gt;- "-webkit-repeating-radial-gradient", &gt;- "-moz-repeating-radial-gradient", &gt;- "-webkit-gradient", &gt;+ "linear-gradient", &gt;+ "-webkit-linear-gradient", &gt;+ "-moz-linear-gradient", &gt;+ "repeating-linear-gradient", &gt;+ "-webkit-repeating-linear-gradient", &gt;+ "-moz-repeating-linear-gradient", &gt;+ "radial-gradient", &gt;+ "-webkit-radial-gradient", &gt;+ "-moz-radial-gradient", &gt;+ "repeating-radial-gradient", &gt;+ "-webkit-repeating-radial-gradient", &gt;+ "-moz-repeating-radial-gradient", &gt;+ "-webkit-gradient", &gt; ]); &gt; } &gt; } &gt; &gt; /// A specified gradient kind. &gt; #[cfg(not(feature = "gecko"))] &gt; pub type GradientKind = &gt; generic::GradientKind&lt;LineDirection, Length, LengthOrPercentage, Position, Angle&gt;; &gt;@@ -228,25 +228,25 @@ impl Parse for Gradient { &gt; }, &gt; _ =&gt; None, &gt; }; &gt; &gt; let (shape, repeating, mut compat_mode) = match result { &gt; Some(result) =&gt; result, &gt; None =&gt; { &gt; return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedFunction(func))) &gt;- }, &gt;+ } &gt; }; &gt; &gt; #[cfg(feature = "gecko")] &gt; { &gt; use gecko_bindings::structs; &gt;- if compat_mode == CompatMode::Moz &amp;&amp; !unsafe { &gt;- structs::StaticPrefs_sVarCache_layout_css_prefixes_gradients &gt;- } { &gt;+ if compat_mode == CompatMode::Moz &gt;+ &amp;&amp; !unsafe { structs::StaticPrefs_sVarCache_layout_css_prefixes_gradients } &gt;+ { &gt; return Err(input.new_custom_error(StyleParseErrorKind::UnexpectedFunction(func))); &gt; } &gt; } &gt; &gt; let (kind, items) = input.parse_nested_block(|i| { &gt; let shape = match shape { &gt; Shape::Linear =&gt; GradientKind::parse_linear(context, i, &amp;mut compat_mode)?, &gt; Shape::Radial =&gt; GradientKind::parse_radial(context, i, &amp;mut compat_mode)?, &gt;@@ -292,24 +292,24 @@ impl Gradient { &gt; }; &gt; match (h, v) { &gt; (Ordering::Less, Ordering::Less) =&gt; LineDirection::Corner(X::Right, Y::Bottom), &gt; (Ordering::Less, Ordering::Equal) =&gt; LineDirection::Horizontal(X::Right), &gt; (Ordering::Less, Ordering::Greater) =&gt; LineDirection::Corner(X::Right, Y::Top), &gt; (Ordering::Equal, Ordering::Greater) =&gt; LineDirection::Vertical(Y::Top), &gt; (Ordering::Equal, Ordering::Equal) | (Ordering::Equal, Ordering::Less) =&gt; { &gt; LineDirection::Vertical(Y::Bottom) &gt;- }, &gt;+ } &gt; (Ordering::Greater, Ordering::Less) =&gt; { &gt; LineDirection::Corner(X::Left, Y::Bottom) &gt;- }, &gt;+ } &gt; (Ordering::Greater, Ordering::Equal) =&gt; LineDirection::Horizontal(X::Left), &gt; (Ordering::Greater, Ordering::Greater) =&gt; { &gt; LineDirection::Corner(X::Left, Y::Top) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl From&lt;Point&gt; for Position { &gt; fn from(point: Point) -&gt; Self { &gt; Self::new(point.horizontal.into(), point.vertical.into()) &gt; } &gt;@@ -336,48 +336,48 @@ impl Gradient { &gt; Component::Number(number) =&gt; number, &gt; Component::Side(side) =&gt; { &gt; let p = if side.is_start() { &gt; Percentage::zero() &gt; } else { &gt; Percentage::hundred() &gt; }; &gt; NumberOrPercentage::Percentage(p) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl&lt;S: Side&gt; From&lt;Component&lt;S&gt;&gt; for PositionComponent&lt;S&gt; { &gt; fn from(component: Component&lt;S&gt;) -&gt; Self { &gt; match component { &gt; Component::Center =&gt; PositionComponent::Center, &gt; Component::Number(NumberOrPercentage::Number(number)) =&gt; { &gt; PositionComponent::Length(Length::from_px(number.value).into()) &gt;- }, &gt;+ } &gt; Component::Number(NumberOrPercentage::Percentage(p)) =&gt; { &gt; PositionComponent::Length(p.into()) &gt;- }, &gt;+ } &gt; Component::Side(side) =&gt; PositionComponent::Side(side, None), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;S: Copy + Side&gt; Component&lt;S&gt; { &gt; fn partial_cmp(&amp;self, other: &amp;Self) -&gt; Option&lt;Ordering&gt; { &gt; match ( &gt; NumberOrPercentage::from(*self), &gt; NumberOrPercentage::from(*other), &gt; ) { &gt; (NumberOrPercentage::Percentage(a), NumberOrPercentage::Percentage(b)) =&gt; { &gt; a.get().partial_cmp(&amp;b.get()) &gt;- }, &gt;+ } &gt; (NumberOrPercentage::Number(a), NumberOrPercentage::Number(b)) =&gt; { &gt; a.value.partial_cmp(&amp;b.value) &gt;- }, &gt;+ } &gt; (_, _) =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; impl&lt;S: Parse&gt; Parse for Component&lt;S&gt; { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt;@@ -507,20 +507,20 @@ impl Gradient { &gt; &amp;generic::GradientItem::ColorStop(ref a), &gt; &amp;generic::GradientItem::ColorStop(ref b), &gt; ) =&gt; match (&amp;a.position, &amp;b.position) { &gt; ( &gt; &amp;Some(LengthOrPercentage::Percentage(a)), &gt; &amp;Some(LengthOrPercentage::Percentage(b)), &gt; ) =&gt; { &gt; return a.0.partial_cmp(&amp;b.0).unwrap_or(Ordering::Equal); &gt;- }, &gt;- _ =&gt; {}, &gt;+ } &gt;+ _ =&gt; {} &gt; }, &gt;- _ =&gt; {}, &gt;+ _ =&gt; {} &gt; } &gt; if reverse_stops { &gt; Ordering::Greater &gt; } else { &gt; Ordering::Less &gt; } &gt; }) &gt; } &gt;@@ -563,27 +563,27 @@ impl GradientKind { &gt; let (shape, position, angle, moz_position) = match *compat_mode { &gt; CompatMode::Modern =&gt; { &gt; let shape = input.try(|i| EndingShape::parse(context, i, *compat_mode)); &gt; let position = input.try(|i| { &gt; i.expect_ident_matching("at")?; &gt; Position::parse(context, i) &gt; }); &gt; (shape, position.ok(), None, None) &gt;- }, &gt;+ } &gt; CompatMode::WebKit =&gt; { &gt; let position = input.try(|i| Position::parse(context, i)); &gt; let shape = input.try(|i| { &gt; if position.is_ok() { &gt; i.expect_comma()?; &gt; } &gt; EndingShape::parse(context, i, *compat_mode) &gt; }); &gt; (shape, position.ok(), None, None) &gt;- }, &gt;+ } &gt; // The syntax of `-moz-` prefixed radial gradient is: &gt; // -moz-radial-gradient( &gt; // [ [ &lt;position&gt; || &lt;angle&gt; ]? [ ellipse | [ &lt;length&gt; | &lt;percentage&gt; ]{2} ] , | &gt; // [ &lt;position&gt; || &lt;angle&gt; ]? [ [ circle | ellipse ] | &lt;extent-keyword&gt; ] , | &gt; // ]? &gt; // &lt;color-stop&gt; [ , &lt;color-stop&gt; ]+ &gt; // ) &gt; // where &lt;extent-keyword&gt; = closest-corner | closest-side | farthest-corner | farthest-side | &gt;@@ -599,17 +599,17 @@ impl GradientKind { &gt; let shape = input.try(|i| { &gt; if position.is_ok() || angle.is_some() { &gt; i.expect_comma()?; &gt; } &gt; EndingShape::parse(context, i, *compat_mode) &gt; }); &gt; &gt; (shape, None, angle, position.ok()) &gt;- }, &gt;+ } &gt; }; &gt; &gt; if shape.is_ok() || position.is_some() || angle.is_some() || moz_position.is_some() { &gt; input.expect_comma()?; &gt; } &gt; &gt; let shape = shape.unwrap_or({ &gt; generic::EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) &gt;@@ -676,62 +676,62 @@ impl generic::LineDirection for LineDirection { &gt; let y = match *y { &gt; OriginComponent::Side(Y::Top) =&gt; true, &gt; OriginComponent::Length(LengthOrPercentage::Percentage( &gt; ComputedPercentage(val), &gt; )) =&gt; val == 0.0, &gt; _ =&gt; false, &gt; }; &gt; x &amp;&amp; y &gt;- }, &gt;+ } &gt; _ =&gt; false, &gt; } &gt; } &gt; &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;, compat_mode: CompatMode) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; match *self { &gt; LineDirection::Angle(angle) =&gt; angle.to_css(dest), &gt; LineDirection::Horizontal(x) =&gt; { &gt; if compat_mode == CompatMode::Modern { &gt; dest.write_str("to ")?; &gt; } &gt; x.to_css(dest) &gt;- }, &gt;+ } &gt; LineDirection::Vertical(y) =&gt; { &gt; if compat_mode == CompatMode::Modern { &gt; dest.write_str("to ")?; &gt; } &gt; y.to_css(dest) &gt;- }, &gt;+ } &gt; LineDirection::Corner(x, y) =&gt; { &gt; if compat_mode == CompatMode::Modern { &gt; dest.write_str("to ")?; &gt; } &gt; x.to_css(dest)?; &gt; dest.write_str(" ")?; &gt; y.to_css(dest) &gt;- }, &gt;+ } &gt; #[cfg(feature = "gecko")] &gt; LineDirection::MozPosition(ref position, ref angle) =&gt; { &gt; let mut need_space = false; &gt; if let Some(ref position) = *position { &gt; position.to_css(dest)?; &gt; need_space = true; &gt; } &gt; if let Some(ref angle) = *angle { &gt; if need_space { &gt; dest.write_str(" ")?; &gt; } &gt; angle.to_css(dest)?; &gt; } &gt; Ok(()) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl LineDirection { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt;@@ -755,21 +755,21 @@ impl LineDirection { &gt; CompatMode::Modern =&gt; to_ident?, &gt; // Fall back to Modern compatibility mode in case there is a `to` keyword. &gt; // According to Gecko, `-moz-linear-gradient(to ...)` should serialize like &gt; // `linear-gradient(to ...)`. &gt; CompatMode::Moz if to_ident.is_ok() =&gt; *compat_mode = CompatMode::Modern, &gt; // There is no `to` keyword in webkit prefixed syntax. If it's consumed, &gt; // parsing should throw an error. &gt; CompatMode::WebKit if to_ident.is_ok() =&gt; { &gt;- return Err(i.new_custom_error(SelectorParseErrorKind::UnexpectedIdent( &gt;- "to".into(), &gt;- ))) &gt;- }, &gt;- _ =&gt; {}, &gt;+ return Err( &gt;+ i.new_custom_error(SelectorParseErrorKind::UnexpectedIdent("to".into())) &gt;+ ) &gt;+ } &gt;+ _ =&gt; {} &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt; { &gt; // `-moz-` prefixed linear gradient can be both Angle and Position. &gt; if *compat_mode == CompatMode::Moz { &gt; let position = i.try(|i| LegacyPosition::parse(context, i)).ok(); &gt; if _angle.is_none() { &gt;@@ -909,17 +909,17 @@ impl EndingShape { &gt; impl ShapeExtent { &gt; fn parse_with_compat_mode&lt;'i, 't&gt;( &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; compat_mode: CompatMode, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; match Self::parse(input)? { &gt; ShapeExtent::Contain | ShapeExtent::Cover if compat_mode == CompatMode::Modern =&gt; { &gt; Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt;- }, &gt;+ } &gt; ShapeExtent::Contain =&gt; Ok(ShapeExtent::ClosestSide), &gt; ShapeExtent::Cover =&gt; Ok(ShapeExtent::FarthestCorner), &gt; keyword =&gt; Ok(keyword), &gt; } &gt; } &gt; } &gt; &gt; impl GradientItem { &gt;@@ -964,18 +964,17 @@ impl Parse for PaintWorklet { &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; input.expect_function_matching("paint")?; &gt; input.parse_nested_block(|input| { &gt; let name = Atom::from(&amp;**input.expect_ident()?); &gt; let arguments = input &gt; .try(|input| { &gt; input.expect_comma()?; &gt; input.parse_comma_separated(|input| SpecifiedValue::parse(input)) &gt;- }) &gt;- .unwrap_or(vec![]); &gt;+ }).unwrap_or(vec![]); &gt; Ok(PaintWorklet { name, arguments }) &gt; }) &gt; } &gt; } &gt; &gt; impl Parse for MozImageRect { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt;diff --git a/servo/components/style/values/specified/length.rs b/servo/components/style/values/specified/length.rs &gt;index b6fe9bc23463..c8f3f0e65578 100644 &gt;--- a/servo/components/style/values/specified/length.rs &gt;+++ b/servo/components/style/values/specified/length.rs &gt;@@ -1,34 +1,34 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! [Length values][length]. &gt; //! &gt; //! [length]: https://drafts.csswg.org/css-values/#lengths &gt; &gt;+use super::{AllowQuirks, Number, Percentage, ToComputedValue}; &gt; use app_units::Au; &gt; use cssparser::{Parser, Token}; &gt; use euclid::Size2D; &gt; use font_metrics::FontMetricsQueryResult; &gt; use parser::{Parse, ParserContext}; &gt; use std::cmp; &gt; use std::ops::{Add, Mul}; &gt;-use style_traits::{ParseError, SpecifiedValueInfo, StyleParseErrorKind}; &gt; use style_traits::values::specified::AllowedNumericType; &gt;-use super::{AllowQuirks, Number, Percentage, ToComputedValue}; &gt;-use values::{Auto, CSSFloat, Either, Normal}; &gt;+use style_traits::{ParseError, SpecifiedValueInfo, StyleParseErrorKind}; &gt; use values::computed::{self, CSSPixelLength, Context, ExtremumLength}; &gt; use values::generics::NonNegative; &gt; use values::specified::calc::CalcNode; &gt;+use values::{Auto, CSSFloat, Either, Normal}; &gt; &gt;-pub use values::specified::calc::CalcLengthOrPercentage; &gt; pub use super::image::{ColorStop, EndingShape as GradientEndingShape, Gradient}; &gt; pub use super::image::{GradientKind, Image}; &gt;+pub use values::specified::calc::CalcLengthOrPercentage; &gt; &gt; /// Number of app units per pixel &gt; pub const AU_PER_PX: CSSFloat = 60.; &gt; /// Number of app units per inch &gt; pub const AU_PER_IN: CSSFloat = AU_PER_PX * 96.; &gt; /// Number of app units per centimeter &gt; pub const AU_PER_CM: CSSFloat = AU_PER_IN / 2.54; &gt; /// Number of app units per millimeter &gt;@@ -85,17 +85,17 @@ pub enum FontBaseSize { &gt; impl FontBaseSize { &gt; /// Calculate the actual size for a given context &gt; pub fn resolve(&amp;self, context: &amp;Context) -&gt; Au { &gt; match *self { &gt; FontBaseSize::Custom(size) =&gt; size, &gt; FontBaseSize::CurrentStyle =&gt; context.style().get_font().clone_font_size().size(), &gt; FontBaseSize::InheritedStyleButStripEmUnits | FontBaseSize::InheritedStyle =&gt; { &gt; context.style().get_parent_font().clone_font_size().size() &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl FontRelativeLength { &gt; /// Computes the font-relative length. &gt; pub fn to_computed_value(&amp;self, context: &amp;Context, base_size: FontBaseSize) -&gt; CSSPixelLength { &gt; use std::f32; &gt;@@ -143,33 +143,33 @@ impl FontRelativeLength { &gt; } &gt; } &gt; &gt; if base_size == FontBaseSize::InheritedStyleButStripEmUnits { &gt; (Au(0), length) &gt; } else { &gt; (reference_font_size, length) &gt; } &gt;- }, &gt;+ } &gt; FontRelativeLength::Ex(length) =&gt; { &gt; if context.for_non_inherited_property.is_some() { &gt; context.rule_cache_conditions.borrow_mut().set_uncacheable(); &gt; } &gt; let reference_size = match query_font_metrics(context, reference_font_size) { &gt; FontMetricsQueryResult::Available(metrics) =&gt; metrics.x_height, &gt; // https://drafts.csswg.org/css-values/#ex &gt; // &gt; // In the cases where it is impossible or impractical to &gt; // determine the x-height, a value of 0.5em must be &gt; // assumed. &gt; // &gt; FontMetricsQueryResult::NotAvailable =&gt; reference_font_size.scale_by(0.5), &gt; }; &gt; (reference_size, length) &gt;- }, &gt;+ } &gt; FontRelativeLength::Ch(length) =&gt; { &gt; if context.for_non_inherited_property.is_some() { &gt; context.rule_cache_conditions.borrow_mut().set_uncacheable(); &gt; } &gt; let reference_size = match query_font_metrics(context, reference_font_size) { &gt; FontMetricsQueryResult::Available(metrics) =&gt; metrics.zero_advance_measure, &gt; // https://drafts.csswg.org/css-values/#ch &gt; // &gt;@@ -182,34 +182,34 @@ impl FontRelativeLength { &gt; // text-orientation is upright). &gt; // &gt; FontMetricsQueryResult::NotAvailable =&gt; { &gt; if context.style().writing_mode.is_vertical() { &gt; reference_font_size &gt; } else { &gt; reference_font_size.scale_by(0.5) &gt; } &gt;- }, &gt;+ } &gt; }; &gt; (reference_size, length) &gt;- }, &gt;+ } &gt; FontRelativeLength::Rem(length) =&gt; { &gt; // https://drafts.csswg.org/css-values/#rem: &gt; // &gt; // When specified on the font-size property of the root &gt; // element, the rem units refer to the property's initial &gt; // value. &gt; // &gt; let reference_size = if context.is_root_element || context.in_media_query { &gt; reference_font_size &gt; } else { &gt; context.device().root_font_size() &gt; }; &gt; (reference_size, length) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// A viewport-relative length. &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-values/#viewport-relative-lengths&gt; &gt; #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss)] &gt;@@ -231,20 +231,20 @@ pub enum ViewportPercentageLength { &gt; impl ViewportPercentageLength { &gt; /// Computes the given viewport-relative length for the given viewport size. &gt; pub fn to_computed_value(&amp;self, viewport_size: Size2D&lt;Au&gt;) -&gt; CSSPixelLength { &gt; let (factor, length) = match *self { &gt; ViewportPercentageLength::Vw(length) =&gt; (length, viewport_size.width), &gt; ViewportPercentageLength::Vh(length) =&gt; (length, viewport_size.height), &gt; ViewportPercentageLength::Vmin(length) =&gt; { &gt; (length, cmp::min(viewport_size.width, viewport_size.height)) &gt;- }, &gt;+ } &gt; ViewportPercentageLength::Vmax(length) =&gt; { &gt; (length, cmp::max(viewport_size.width, viewport_size.height)) &gt;- }, &gt;+ } &gt; }; &gt; &gt; // FIXME: Bug 1396535, we need to fix the extremely small viewport length for transform. &gt; // See bug 989802. We truncate so that adding multiple viewport units &gt; // that add up to 100 does not overflow due to rounding differences &gt; let trunc_scaled = ((length.0 as f64) * factor as f64 / 100.).trunc(); &gt; Au::from_f64_au(trunc_scaled).into() &gt; } &gt;@@ -292,23 +292,23 @@ pub enum AbsoluteLength { &gt; /// An absolute length in pica (pc) &gt; #[css(dimension)] &gt; Pc(CSSFloat), &gt; } &gt; &gt; impl AbsoluteLength { &gt; fn is_zero(&amp;self) -&gt; bool { &gt; match *self { &gt;- AbsoluteLength::Px(v) | &gt;- AbsoluteLength::In(v) | &gt;- AbsoluteLength::Cm(v) | &gt;- AbsoluteLength::Mm(v) | &gt;- AbsoluteLength::Q(v) | &gt;- AbsoluteLength::Pt(v) | &gt;- AbsoluteLength::Pc(v) =&gt; v == 0., &gt;+ AbsoluteLength::Px(v) &gt;+ | AbsoluteLength::In(v) &gt;+ | AbsoluteLength::Cm(v) &gt;+ | AbsoluteLength::Mm(v) &gt;+ | AbsoluteLength::Q(v) &gt;+ | AbsoluteLength::Pt(v) &gt;+ | AbsoluteLength::Pc(v) =&gt; v == 0., &gt; } &gt; } &gt; &gt; /// Convert this into a pixel value. &gt; #[inline] &gt; pub fn to_px(&amp;self) -&gt; CSSFloat { &gt; use std::f32; &gt; &gt;@@ -561,33 +561,35 @@ impl Length { &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; // FIXME: remove early returns when lifetimes are non-lexical &gt; { &gt; let location = input.current_source_location(); &gt; let token = input.next()?; &gt; match *token { &gt; Token::Dimension { &gt; value, ref unit, .. &gt;- } if num_context.is_ok(context.parsing_mode, value) =&gt; &gt;+ } &gt;+ if num_context.is_ok(context.parsing_mode, value) =&gt; &gt; { &gt; return NoCalcLength::parse_dimension(context, value, unit) &gt; .map(Length::NoCalc) &gt; .map_err(|()| location.new_unexpected_token_error(token.clone())) &gt;- }, &gt;+ } &gt; Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) =&gt; { &gt;- if value != 0. &amp;&amp; !context.parsing_mode.allows_unitless_lengths() &amp;&amp; &gt;- !allow_quirks.allowed(context.quirks_mode) &gt;+ if value != 0. &gt;+ &amp;&amp; !context.parsing_mode.allows_unitless_lengths() &gt;+ &amp;&amp; !allow_quirks.allowed(context.quirks_mode) &gt; { &gt; return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt; return Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px( &gt; value, &gt; )))); &gt;- }, &gt;- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {}, &gt;+ } &gt;+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {} &gt; ref token =&gt; return Err(location.new_unexpected_token_error(token.clone())), &gt; } &gt; } &gt; input.parse_nested_block(|input| { &gt; CalcNode::parse_length(context, input, num_context) &gt; .map(|calc| Length::Calc(Box::new(calc))) &gt; }) &gt; } &gt;@@ -748,45 +750,48 @@ impl LengthOrPercentage { &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; // FIXME: remove early returns when lifetimes are non-lexical &gt; { &gt; let location = input.current_source_location(); &gt; let token = input.next()?; &gt; match *token { &gt; Token::Dimension { &gt; value, ref unit, .. &gt;- } if num_context.is_ok(context.parsing_mode, value) =&gt; &gt;+ } &gt;+ if num_context.is_ok(context.parsing_mode, value) =&gt; &gt; { &gt; return NoCalcLength::parse_dimension(context, value, unit) &gt; .map(LengthOrPercentage::Length) &gt; .map_err(|()| location.new_unexpected_token_error(token.clone())) &gt;- }, &gt;+ } &gt; Token::Percentage { unit_value, .. } &gt; if num_context.is_ok(context.parsing_mode, unit_value) =&gt; &gt; { &gt; return Ok(LengthOrPercentage::Percentage(computed::Percentage( &gt; unit_value, &gt; ))) &gt;- }, &gt;+ } &gt; Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) =&gt; { &gt;- if value != 0. &amp;&amp; !context.parsing_mode.allows_unitless_lengths() &amp;&amp; &gt;- !allow_quirks.allowed(context.quirks_mode) &gt;+ if value != 0. &gt;+ &amp;&amp; !context.parsing_mode.allows_unitless_lengths() &gt;+ &amp;&amp; !allow_quirks.allowed(context.quirks_mode) &gt; { &gt; return Err(location.new_unexpected_token_error(token.clone())); &gt; } else { &gt; return Ok(LengthOrPercentage::Length(NoCalcLength::from_px(value))); &gt; } &gt;- }, &gt;- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {}, &gt;+ } &gt;+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {} &gt; _ =&gt; return Err(location.new_unexpected_token_error(token.clone())), &gt; } &gt; } &gt; &gt;- let calc = input &gt;- .parse_nested_block(|i| CalcNode::parse_length_or_percentage(context, i, num_context))?; &gt;+ let calc = input.parse_nested_block(|i| { &gt;+ CalcNode::parse_length_or_percentage(context, i, num_context) &gt;+ })?; &gt; Ok(LengthOrPercentage::Calc(Box::new(calc))) &gt; } &gt; &gt; /// Parse a non-negative length. &gt; #[inline] &gt; pub fn parse_non_negative&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt;@@ -866,49 +871,52 @@ impl LengthOrPercentageOrAuto { &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; // FIXME: remove early returns when lifetimes are non-lexical &gt; { &gt; let location = input.current_source_location(); &gt; let token = input.next()?; &gt; match *token { &gt; Token::Dimension { &gt; value, ref unit, .. &gt;- } if num_context.is_ok(context.parsing_mode, value) =&gt; &gt;+ } &gt;+ if num_context.is_ok(context.parsing_mode, value) =&gt; &gt; { &gt; return NoCalcLength::parse_dimension(context, value, unit) &gt; .map(LengthOrPercentageOrAuto::Length) &gt; .map_err(|()| location.new_unexpected_token_error(token.clone())) &gt;- }, &gt;+ } &gt; Token::Percentage { unit_value, .. } &gt; if num_context.is_ok(context.parsing_mode, unit_value) =&gt; &gt; { &gt; return Ok(LengthOrPercentageOrAuto::Percentage(computed::Percentage( &gt; unit_value, &gt; ))) &gt;- }, &gt;+ } &gt; Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) =&gt; { &gt;- if value != 0. &amp;&amp; !context.parsing_mode.allows_unitless_lengths() &amp;&amp; &gt;- !allow_quirks.allowed(context.quirks_mode) &gt;+ if value != 0. &gt;+ &amp;&amp; !context.parsing_mode.allows_unitless_lengths() &gt;+ &amp;&amp; !allow_quirks.allowed(context.quirks_mode) &gt; { &gt; return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt; return Ok(LengthOrPercentageOrAuto::Length(NoCalcLength::Absolute( &gt; AbsoluteLength::Px(value), &gt; ))); &gt;- }, &gt;+ } &gt; Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") =&gt; { &gt; return Ok(LengthOrPercentageOrAuto::Auto) &gt;- }, &gt;- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {}, &gt;+ } &gt;+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {} &gt; _ =&gt; return Err(location.new_unexpected_token_error(token.clone())), &gt; } &gt; } &gt; &gt;- let calc = input &gt;- .parse_nested_block(|i| CalcNode::parse_length_or_percentage(context, i, num_context))?; &gt;+ let calc = input.parse_nested_block(|i| { &gt;+ CalcNode::parse_length_or_percentage(context, i, num_context) &gt;+ })?; &gt; Ok(LengthOrPercentageOrAuto::Calc(Box::new(calc))) &gt; } &gt; &gt; /// Parse a non-negative length, percentage, or auto. &gt; #[inline] &gt; pub fn parse_non_negative&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt;@@ -993,18 +1001,17 @@ impl NonNegativeLengthOrPercentageOrAuto { &gt; &gt; impl Parse for NonNegativeLengthOrPercentageOrAuto { &gt; #[inline] &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; Ok(NonNegative(LengthOrPercentageOrAuto::parse_non_negative( &gt;- context, &gt;- input, &gt;+ context, input, &gt; )?)) &gt; } &gt; } &gt; &gt; /// Either a `&lt;length&gt;`, a `&lt;percentage&gt;`, or the `none` keyword. &gt; #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] &gt; #[allow(missing_docs)] &gt; pub enum LengthOrPercentageOrNone { &gt;@@ -1023,49 +1030,52 @@ impl LengthOrPercentageOrNone { &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; // FIXME: remove early returns when lifetimes are non-lexical &gt; { &gt; let location = input.current_source_location(); &gt; let token = input.next()?; &gt; match *token { &gt; Token::Dimension { &gt; value, ref unit, .. &gt;- } if num_context.is_ok(context.parsing_mode, value) =&gt; &gt;+ } &gt;+ if num_context.is_ok(context.parsing_mode, value) =&gt; &gt; { &gt; return NoCalcLength::parse_dimension(context, value, unit) &gt; .map(LengthOrPercentageOrNone::Length) &gt; .map_err(|()| location.new_unexpected_token_error(token.clone())) &gt;- }, &gt;+ } &gt; Token::Percentage { unit_value, .. } &gt; if num_context.is_ok(context.parsing_mode, unit_value) =&gt; &gt; { &gt; return Ok(LengthOrPercentageOrNone::Percentage(computed::Percentage( &gt; unit_value, &gt; ))) &gt;- }, &gt;+ } &gt; Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) =&gt; { &gt;- if value != 0. &amp;&amp; !context.parsing_mode.allows_unitless_lengths() &amp;&amp; &gt;- !allow_quirks.allowed(context.quirks_mode) &gt;+ if value != 0. &gt;+ &amp;&amp; !context.parsing_mode.allows_unitless_lengths() &gt;+ &amp;&amp; !allow_quirks.allowed(context.quirks_mode) &gt; { &gt; return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt; return Ok(LengthOrPercentageOrNone::Length(NoCalcLength::Absolute( &gt; AbsoluteLength::Px(value), &gt; ))); &gt;- }, &gt;- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {}, &gt;+ } &gt;+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {} &gt; Token::Ident(ref value) if value.eq_ignore_ascii_case("none") =&gt; { &gt; return Ok(LengthOrPercentageOrNone::None) &gt;- }, &gt;+ } &gt; _ =&gt; return Err(location.new_unexpected_token_error(token.clone())), &gt; } &gt; } &gt; &gt;- let calc = input &gt;- .parse_nested_block(|i| CalcNode::parse_length_or_percentage(context, i, num_context))?; &gt;+ let calc = input.parse_nested_block(|i| { &gt;+ CalcNode::parse_length_or_percentage(context, i, num_context) &gt;+ })?; &gt; Ok(LengthOrPercentageOrNone::Calc(Box::new(calc))) &gt; } &gt; &gt; /// Parse a non-negative LengthOrPercentageOrNone. &gt; #[inline] &gt; pub fn parse_non_negative&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt;diff --git a/servo/components/style/values/specified/list.rs b/servo/components/style/values/specified/list.rs &gt;index ae61bb1ae9cb..c63d7d85018f 100644 &gt;--- a/servo/components/style/values/specified/list.rs &gt;+++ b/servo/components/style/values/specified/list.rs &gt;@@ -4,24 +4,23 @@ &gt; &gt; //! `list` specified values. &gt; &gt; use cssparser::{Parser, Token}; &gt; use parser::{Parse, ParserContext}; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt; #[cfg(feature = "gecko")] &gt;-use values::CustomIdent; &gt;-#[cfg(feature = "gecko")] &gt; use values::generics::CounterStyleOrNone; &gt;+#[cfg(feature = "gecko")] &gt;+use values::CustomIdent; &gt; &gt; /// Specified and computed `list-style-type` property. &gt; #[cfg(feature = "gecko")] &gt;-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub enum ListStyleType { &gt; /// &lt;counter-style&gt; | none &gt; CounterStyle(CounterStyleOrNone), &gt; /// &lt;string&gt; &gt; String(String), &gt; } &gt; &gt; #[cfg(feature = "gecko")] &gt;@@ -74,33 +73,32 @@ impl Parse for ListStyleType { &gt; } &gt; } &gt; &gt; /// Specified and computed `quote` property. &gt; /// &gt; /// FIXME(emilio): It's a shame that this allocates all the time it's computed, &gt; /// probably should just be refcounted. &gt; /// FIXME This can probably derive ToCss. &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct Quotes(#[css(if_empty = "none")] pub Box&lt;[(Box&lt;str&gt;, Box&lt;str&gt;)]&gt;); &gt; &gt; impl ToCss for Quotes { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; let mut iter = self.0.iter(); &gt; &gt; match iter.next() { &gt; Some(&amp;(ref l, ref r)) =&gt; { &gt; l.to_css(dest)?; &gt; dest.write_char(' ')?; &gt; r.to_css(dest)?; &gt;- }, &gt;+ } &gt; None =&gt; return dest.write_str("none"), &gt; } &gt; &gt; for &amp;(ref l, ref r) in iter { &gt; dest.write_char(' ')?; &gt; l.to_css(dest)?; &gt; dest.write_char(' ')?; &gt; r.to_css(dest)?; &gt;diff --git a/servo/components/style/values/specified/mod.rs b/servo/components/style/values/specified/mod.rs &gt;index 2da4c7e93d3e..ccb7440b42ff 100644 &gt;--- a/servo/components/style/values/specified/mod.rs &gt;+++ b/servo/components/style/values/specified/mod.rs &gt;@@ -1,87 +1,91 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Specified values. &gt; //! &gt; //! TODO(emilio): Enhance docs. &gt; &gt;-use {Atom, Namespace, Prefix}; &gt;+use super::computed::{Context, ToComputedValue}; &gt;+use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth}; &gt;+use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize}; &gt;+use super::generics::{GreaterThanOrEqualToOne, NonNegative}; &gt;+use super::{Auto, CSSFloat, CSSInteger, Either}; &gt; use context::QuirksMode; &gt; use cssparser::{Parser, Token}; &gt; use num_traits::One; &gt; use parser::{Parse, ParserContext}; &gt; use std::f32; &gt; use std::fmt::{self, Write}; &gt;-use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; &gt; use style_traits::values::specified::AllowedNumericType; &gt;-use super::{Auto, CSSFloat, CSSInteger, Either}; &gt;-use super::computed::{Context, ToComputedValue}; &gt;-use super::generics::{GreaterThanOrEqualToOne, NonNegative}; &gt;-use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as GenericTrackBreadth}; &gt;-use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize}; &gt;+use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; &gt; use values::serialize_atom_identifier; &gt; use values::specified::calc::CalcNode; &gt;+use {Atom, Namespace, Prefix}; &gt; &gt;-pub use self::angle::Angle; &gt; #[cfg(feature = "gecko")] &gt; pub use self::align::{AlignContent, AlignItems, AlignSelf, ContentDistribution}; &gt; #[cfg(feature = "gecko")] &gt; pub use self::align::{JustifyContent, JustifyItems, JustifySelf, SelfAlignment}; &gt;+pub use self::angle::Angle; &gt; pub use self::background::{BackgroundRepeat, BackgroundSize}; &gt; pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth}; &gt; pub use self::border::{BorderImageRepeat, BorderImageSideWidth}; &gt; pub use self::border::{BorderRadius, BorderSideWidth, BorderSpacing}; &gt;-pub use self::column::ColumnCount; &gt;-pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis, FontVariantAlternates, FontWeight}; &gt;-pub use self::font::{FontFamily, FontLanguageOverride, FontStyle, FontVariantEastAsian, FontVariationSettings}; &gt;-pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric}; &gt;-pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; &gt; pub use self::box_::{AnimationIterationCount, AnimationName, Contain, Display}; &gt; pub use self::box_::{Appearance, Clear, Float}; &gt; pub use self::box_::{OverflowClipBox, OverscrollBehavior, Perspective, Resize}; &gt; pub use self::box_::{ScrollSnapType, TouchAction, TransitionProperty, VerticalAlign, WillChange}; &gt; pub use self::color::{Color, ColorPropertyValue, RGBAColor}; &gt;+pub use self::column::ColumnCount; &gt; pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset}; &gt; pub use self::effects::{BoxShadow, Filter, SimpleShadow}; &gt; pub use self::flex::FlexBasis; &gt;+pub use self::font::{ &gt;+ FontFamily, FontLanguageOverride, FontStyle, FontVariantEastAsian, FontVariationSettings, &gt;+}; &gt;+pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric}; &gt;+pub use self::font::{ &gt;+ FontSize, FontSizeAdjust, FontStretch, FontSynthesis, FontVariantAlternates, FontWeight, &gt;+}; &gt;+pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; &gt; #[cfg(feature = "gecko")] &gt; pub use self::gecko::ScrollSnapPoint; &gt; pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient}; &gt; pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect}; &gt; pub use self::length::{AbsoluteLength, CalcLengthOrPercentage, CharacterWidth}; &gt; pub use self::length::{FontRelativeLength, Length, LengthOrNumber}; &gt; pub use self::length::{LengthOrPercentage, LengthOrPercentageOrAuto}; &gt; pub use self::length::{LengthOrPercentageOrNone, MaxLength, MozLength}; &gt; pub use self::length::{NoCalcLength, ViewportPercentageLength}; &gt; pub use self::length::{NonNegativeLengthOrPercentage, NonNegativeLengthOrPercentageOrAuto}; &gt;-pub use self::list::Quotes; &gt; #[cfg(feature = "gecko")] &gt; pub use self::list::ListStyleType; &gt;+pub use self::list::Quotes; &gt; pub use self::outline::OutlineStyle; &gt;-pub use self::rect::LengthOrNumberRect; &gt;-pub use self::resolution::Resolution; &gt; pub use self::percentage::Percentage; &gt; pub use self::position::{GridAutoFlow, GridTemplateAreas, Position}; &gt; pub use self::position::{PositionComponent, ZIndex}; &gt;+pub use self::rect::LengthOrNumberRect; &gt;+pub use self::resolution::Resolution; &gt;+pub use self::svg::MozContextProperties; &gt; pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; &gt; pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth}; &gt;-pub use self::svg::MozContextProperties; &gt; pub use self::table::XSpan; &gt; pub use self::text::{InitialLetter, LetterSpacing, LineHeight, MozTabSize, TextAlign}; &gt;-pub use self::text::{TextEmphasisPosition, TextEmphasisStyle}; &gt; pub use self::text::{TextAlignKeyword, TextDecorationLine, TextOverflow, WordSpacing}; &gt;+pub use self::text::{TextEmphasisPosition, TextEmphasisStyle}; &gt; pub use self::time::Time; &gt; pub use self::transform::{Rotate, Scale, TimingFunction, Transform}; &gt; pub use self::transform::{TransformOrigin, TransformStyle, Translate}; &gt;-pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon}; &gt; #[cfg(feature = "gecko")] &gt; pub use self::ui::CursorImage; &gt;+pub use self::ui::{ColorOrAuto, Cursor, MozForceBrokenImageIcon}; &gt; pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; &gt; &gt; #[cfg(feature = "gecko")] &gt; pub mod align; &gt; pub mod angle; &gt; pub mod background; &gt; pub mod basic_shape; &gt; pub mod border; &gt;@@ -123,18 +127,18 @@ fn parse_number_with_clamping_mode&lt;'i, 't&gt;( &gt; let location = input.current_source_location(); &gt; // FIXME: remove early returns when lifetimes are non-lexical &gt; match *input.next()? { &gt; Token::Number { value, .. } if clamping_mode.is_ok(context.parsing_mode, value) =&gt; { &gt; return Ok(Number { &gt; value: value.min(f32::MAX).max(f32::MIN), &gt; calc_clamping_mode: None, &gt; }) &gt;- }, &gt;- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {}, &gt;+ } &gt;+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {} &gt; ref t =&gt; return Err(location.new_unexpected_token_error(t.clone())), &gt; } &gt; &gt; let result = input.parse_nested_block(|i| CalcNode::parse_number(context, i))?; &gt; &gt; Ok(Number { &gt; value: result.min(f32::MAX).max(f32::MIN), &gt; calc_clamping_mode: Some(clamping_mode), &gt;@@ -142,18 +146,30 @@ fn parse_number_with_clamping_mode&lt;'i, 't&gt;( &gt; } &gt; &gt; // The integer values here correspond to the border conflict resolution rules in CSS 2.1 § &gt; // 17.6.2.1. Higher values override lower values. &gt; // &gt; // FIXME(emilio): Should move to border.rs &gt; #[allow(missing_docs)] &gt; #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Ord, Parse, PartialEq, &gt;- PartialOrd, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Ord, &gt;+ Parse, &gt;+ PartialEq, &gt;+ PartialOrd, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum BorderStyle { &gt; None = -1, &gt; Solid = 6, &gt; Double = 7, &gt; Dotted = 4, &gt; Dashed = 5, &gt; Hidden = -2, &gt; Groove = 1, &gt;@@ -321,18 +337,17 @@ impl Parse for GreaterThanOrEqualToOneNumber { &gt; } &gt; &gt; /// &lt;number&gt; | &lt;percentage&gt; &gt; /// &gt; /// Accepts only non-negative numbers. &gt; /// &gt; /// FIXME(emilio): Should probably use Either. &gt; #[allow(missing_docs)] &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToCss)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] &gt; pub enum NumberOrPercentage { &gt; Percentage(Percentage), &gt; Number(Number), &gt; } &gt; &gt; impl NumberOrPercentage { &gt; fn parse_with_clamping_mode&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt;@@ -360,18 +375,17 @@ impl Parse for NumberOrPercentage { &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; Self::parse_with_clamping_mode(context, input, AllowedNumericType::All) &gt; } &gt; } &gt; &gt; #[allow(missing_docs)] &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, &gt;- SpecifiedValueInfo, ToCss)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, SpecifiedValueInfo, ToCss)] &gt; pub struct Opacity(Number); &gt; &gt; impl Parse for Opacity { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; Number::parse(context, input).map(Opacity) &gt;@@ -454,17 +468,17 @@ impl Parse for Integer { &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let location = input.current_source_location(); &gt; &gt; // FIXME: remove early returns when lifetimes are non-lexical &gt; match *input.next()? { &gt; Token::Number { &gt; int_value: Some(v), .. &gt; } =&gt; return Ok(Integer::new(v)), &gt;- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {}, &gt;+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {} &gt; ref t =&gt; return Err(location.new_unexpected_token_error(t.clone())), &gt; } &gt; &gt; let result = input.parse_nested_block(|i| CalcNode::parse_integer(context, i))?; &gt; &gt; Ok(Integer::from_calc(result)) &gt; } &gt; } &gt;@@ -621,23 +635,26 @@ impl ToCss for ClipRect { &gt; &gt; impl ToComputedValue for ClipRect { &gt; type ComputedValue = super::computed::ClipRect; &gt; &gt; #[inline] &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; super::computed::ClipRect { &gt; super::computed::ClipRect { &gt; top: self.top.as_ref().map(|top| top.to_computed_value(context)), &gt;- right: self.right &gt;+ right: self &gt;+ .right &gt; .as_ref() &gt; .map(|right| right.to_computed_value(context)), &gt;- bottom: self.bottom &gt;+ bottom: self &gt;+ .bottom &gt; .as_ref() &gt; .map(|bottom| bottom.to_computed_value(context)), &gt;- left: self.left &gt;+ left: self &gt;+ .left &gt; .as_ref() &gt; .map(|left| left.to_computed_value(context)), &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;super::computed::ClipRect) -&gt; Self { &gt; ClipRect { &gt;@@ -751,18 +768,17 @@ impl AllowQuirks { &gt; pub fn allowed(self, quirks_mode: QuirksMode) -&gt; bool { &gt; self == AllowQuirks::Yes &amp;&amp; quirks_mode == QuirksMode::Quirks &gt; } &gt; } &gt; &gt; /// An attr(...) rule &gt; /// &gt; /// `[namespace? `|`]? ident` &gt;-#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; #[css(function)] &gt; pub struct Attr { &gt; /// Optional namespace prefix and URL. &gt; pub namespace: Option&lt;(Prefix, Namespace)&gt;, &gt; /// Attribute name &gt; pub attribute: Atom, &gt; } &gt; &gt;@@ -805,30 +821,33 @@ impl Attr { &gt; Token::Ident(ref second) =&gt; second, &gt; ref t =&gt; return Err(location.new_unexpected_token_error(t.clone())), &gt; }; &gt; &gt; let prefix_and_ns = if let Some(ns) = first { &gt; let prefix = Prefix::from(ns.as_ref()); &gt; let ns = match get_namespace_for_prefix(&amp;prefix, context) { &gt; Some(ns) =&gt; ns, &gt;- None =&gt; return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError)), &gt;+ None =&gt; { &gt;+ return Err(location &gt;+ .new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt;+ } &gt; }; &gt; Some((prefix, ns)) &gt; } else { &gt; None &gt; }; &gt; return Ok(Attr { &gt; namespace: prefix_and_ns, &gt; attribute: Atom::from(second_token.as_ref()), &gt; }); &gt;- }, &gt;+ } &gt; // In the case of attr(foobar ) we don't want to error out &gt; // because of the trailing whitespace &gt;- Token::WhiteSpace(..) =&gt; {}, &gt;+ Token::WhiteSpace(..) =&gt; {} &gt; ref t =&gt; return Err(input.new_unexpected_token_error(t.clone())), &gt; } &gt; } &gt; &gt; if let Some(first) = first { &gt; Ok(Attr { &gt; namespace: None, &gt; attribute: Atom::from(first.as_ref()), &gt;diff --git a/servo/components/style/values/specified/outline.rs b/servo/components/style/values/specified/outline.rs &gt;index c3357f87ec22..afe74dc39f39 100644 &gt;--- a/servo/components/style/values/specified/outline.rs &gt;+++ b/servo/components/style/values/specified/outline.rs &gt;@@ -5,18 +5,29 @@ &gt; //! Specified values for outline properties &gt; &gt; use cssparser::Parser; &gt; use parser::{Parse, ParserContext}; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use style_traits::ParseError; &gt; use values::specified::BorderStyle; &gt; &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Ord, PartialEq, PartialOrd, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Ord, &gt;+ PartialEq, &gt;+ PartialOrd, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; /// &lt;https://drafts.csswg.org/css-ui/#propdef-outline-style&gt; &gt; pub enum OutlineStyle { &gt; /// auto &gt; Auto, &gt; /// &lt;border-style&gt; &gt; Other(BorderStyle), &gt; } &gt; &gt;diff --git a/servo/components/style/values/specified/percentage.rs b/servo/components/style/values/specified/percentage.rs &gt;index 9f8fb1bfbf5b..33a99868941e 100644 &gt;--- a/servo/components/style/values/specified/percentage.rs &gt;+++ b/servo/components/style/values/specified/percentage.rs &gt;@@ -2,22 +2,22 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Specified percentages. &gt; &gt; use cssparser::{Parser, Token}; &gt; use parser::{Parse, ParserContext}; &gt; use std::fmt::{self, Write}; &gt;-use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss}; &gt; use style_traits::values::specified::AllowedNumericType; &gt;-use values::{serialize_percentage, CSSFloat}; &gt;-use values::computed::{Context, ToComputedValue}; &gt;+use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, ToCss}; &gt; use values::computed::percentage::Percentage as ComputedPercentage; &gt;+use values::computed::{Context, ToComputedValue}; &gt; use values::specified::calc::CalcNode; &gt;+use values::{serialize_percentage, CSSFloat}; &gt; &gt; /// A percentage value. &gt; #[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq)] &gt; pub struct Percentage { &gt; /// The percentage value as a float. &gt; /// &gt; /// [0 .. 100%] maps to [0.0 .. 1.0] &gt; value: CSSFloat, &gt;@@ -98,17 +98,17 @@ impl Percentage { &gt; let location = input.current_source_location(); &gt; // FIXME: remove early returns when lifetimes are non-lexical &gt; match *input.next()? { &gt; Token::Percentage { unit_value, .. } &gt; if num_context.is_ok(context.parsing_mode, unit_value) =&gt; &gt; { &gt; return Ok(Percentage::new(unit_value)); &gt; } &gt;- Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {}, &gt;+ Token::Function(ref name) if name.eq_ignore_ascii_case("calc") =&gt; {} &gt; ref t =&gt; return Err(location.new_unexpected_token_error(t.clone())), &gt; } &gt; &gt; let result = input.parse_nested_block(|i| CalcNode::parse_percentage(context, i))?; &gt; &gt; // TODO(emilio): -moz-image-rect is the only thing that uses &gt; // the clamping mode... I guess we could disallow it... &gt; Ok(Percentage { &gt;diff --git a/servo/components/style/values/specified/position.rs b/servo/components/style/values/specified/position.rs &gt;index fcfa07ae1d86..156f901d4ab5 100644 &gt;--- a/servo/components/style/values/specified/position.rs &gt;+++ b/servo/components/style/values/specified/position.rs &gt;@@ -11,23 +11,23 @@ use cssparser::Parser; &gt; use hash::FxHashMap; &gt; use parser::{Parse, ParserContext}; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use servo_arc::Arc; &gt; use std::fmt::{self, Write}; &gt; use std::ops::Range; &gt; use str::HTML_SPACE_CHARACTERS; &gt; use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt;-use values::{Either, None_}; &gt; use values::computed::{CalcLengthOrPercentage, LengthOrPercentage as ComputedLengthOrPercentage}; &gt; use values::computed::{Context, Percentage, ToComputedValue}; &gt; use values::generics::position::Position as GenericPosition; &gt; use values::generics::position::ZIndex as GenericZIndex; &gt;-use values::specified::{AllowQuirks, Integer, LengthOrPercentage}; &gt; use values::specified::transform::OriginComponent; &gt;+use values::specified::{AllowQuirks, Integer, LengthOrPercentage}; &gt;+use values::{Either, None_}; &gt; &gt; /// The specified value of a CSS `&lt;position&gt;` &gt; pub type Position = GenericPosition&lt;HorizontalPosition, VerticalPosition&gt;; &gt; &gt; /// The specified value of a horizontal position. &gt; pub type HorizontalPosition = PositionComponent&lt;X&gt;; &gt; &gt; /// The specified value of a vertical position. &gt;@@ -40,27 +40,49 @@ pub enum PositionComponent&lt;S&gt; { &gt; Center, &gt; /// `&lt;lop&gt;` &gt; Length(LengthOrPercentage), &gt; /// `&lt;side&gt; &lt;lop&gt;?` &gt; Side(S, Option&lt;LengthOrPercentage&gt;), &gt; } &gt; &gt; /// A keyword for the X direction. &gt;-#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ Hash, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; #[allow(missing_docs)] &gt; pub enum X { &gt; Left, &gt; Right, &gt; } &gt; &gt; /// A keyword for the Y direction. &gt;-#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ Hash, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; #[allow(missing_docs)] &gt; pub enum Y { &gt; Top, &gt; Bottom, &gt; } &gt; &gt; impl Parse for Position { &gt; fn parse&lt;'i, 't&gt;( &gt;@@ -85,17 +107,17 @@ impl Position { &gt; { &gt; return Ok(Self::new(x_pos, y_pos)); &gt; } &gt; let x_pos = input &gt; .try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) &gt; .unwrap_or(x_pos); &gt; let y_pos = PositionComponent::Center; &gt; return Ok(Self::new(x_pos, y_pos)); &gt;- }, &gt;+ } &gt; Ok(PositionComponent::Side(x_keyword, lop)) =&gt; { &gt; if input.try(|i| i.expect_ident_matching("center")).is_ok() { &gt; let x_pos = PositionComponent::Side(x_keyword, lop); &gt; let y_pos = PositionComponent::Center; &gt; return Ok(Self::new(x_pos, y_pos)); &gt; } &gt; if let Ok(y_keyword) = input.try(Y::parse) { &gt; let y_lop = input &gt;@@ -103,40 +125,42 @@ impl Position { &gt; .ok(); &gt; let x_pos = PositionComponent::Side(x_keyword, lop); &gt; let y_pos = PositionComponent::Side(y_keyword, y_lop); &gt; return Ok(Self::new(x_pos, y_pos)); &gt; } &gt; let x_pos = PositionComponent::Side(x_keyword, None); &gt; let y_pos = lop.map_or(PositionComponent::Center, PositionComponent::Length); &gt; return Ok(Self::new(x_pos, y_pos)); &gt;- }, &gt;+ } &gt; Ok(x_pos @ PositionComponent::Length(_)) =&gt; { &gt; if let Ok(y_keyword) = input.try(Y::parse) { &gt; let y_pos = PositionComponent::Side(y_keyword, None); &gt; return Ok(Self::new(x_pos, y_pos)); &gt; } &gt; if let Ok(y_lop) = &gt; input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) &gt; { &gt; let y_pos = PositionComponent::Length(y_lop); &gt; return Ok(Self::new(x_pos, y_pos)); &gt; } &gt; let y_pos = PositionComponent::Center; &gt; let _ = input.try(|i| i.expect_ident_matching("center")); &gt; return Ok(Self::new(x_pos, y_pos)); &gt;- }, &gt;- Err(_) =&gt; {}, &gt;+ } &gt;+ Err(_) =&gt; {} &gt; } &gt; let y_keyword = Y::parse(input)?; &gt; let lop_and_x_pos: Result&lt;_, ParseError&gt; = input.try(|i| { &gt;- let y_lop = i.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) &gt;+ let y_lop = i &gt;+ .try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) &gt; .ok(); &gt; if let Ok(x_keyword) = i.try(X::parse) { &gt;- let x_lop = i.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) &gt;+ let x_lop = i &gt;+ .try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) &gt; .ok(); &gt; let x_pos = PositionComponent::Side(x_keyword, x_lop); &gt; return Ok((y_lop, x_pos)); &gt; }; &gt; i.expect_ident_matching("center")?; &gt; let x_pos = PositionComponent::Center; &gt; Ok((y_lop, x_pos)) &gt; }); &gt;@@ -164,31 +188,31 @@ impl ToCss for Position { &gt; match (&amp;self.horizontal, &amp;self.vertical) { &gt; ( &gt; x_pos @ &amp;PositionComponent::Side(_, Some(_)), &gt; &amp;PositionComponent::Length(ref y_lop), &gt; ) =&gt; { &gt; x_pos.to_css(dest)?; &gt; dest.write_str(" top ")?; &gt; y_lop.to_css(dest) &gt;- }, &gt;+ } &gt; ( &gt; &amp;PositionComponent::Length(ref x_lop), &gt; y_pos @ &amp;PositionComponent::Side(_, Some(_)), &gt; ) =&gt; { &gt; dest.write_str("left ")?; &gt; x_lop.to_css(dest)?; &gt; dest.write_str(" ")?; &gt; y_pos.to_css(dest) &gt;- }, &gt;+ } &gt; (x_pos, y_pos) =&gt; { &gt; x_pos.to_css(dest)?; &gt; dest.write_str(" ")?; &gt; y_pos.to_css(dest) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl&lt;S: Parse&gt; Parse for PositionComponent&lt;S&gt; { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt;@@ -229,34 +253,34 @@ impl&lt;S: Side&gt; ToComputedValue for PositionComponent&lt;S&gt; { &gt; type ComputedValue = ComputedLengthOrPercentage; &gt; &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Self::ComputedValue { &gt; match *self { &gt; PositionComponent::Center =&gt; ComputedLengthOrPercentage::Percentage(Percentage(0.5)), &gt; PositionComponent::Side(ref keyword, None) =&gt; { &gt; let p = Percentage(if keyword.is_start() { 0. } else { 1. }); &gt; ComputedLengthOrPercentage::Percentage(p) &gt;- }, &gt;+ } &gt; PositionComponent::Side(ref keyword, Some(ref length)) if !keyword.is_start() =&gt; { &gt; match length.to_computed_value(context) { &gt; ComputedLengthOrPercentage::Length(length) =&gt; ComputedLengthOrPercentage::Calc( &gt; CalcLengthOrPercentage::new(-length, Some(Percentage::hundred())), &gt; ), &gt; ComputedLengthOrPercentage::Percentage(p) =&gt; { &gt; ComputedLengthOrPercentage::Percentage(Percentage(1.0 - p.0)) &gt;- }, &gt;+ } &gt; ComputedLengthOrPercentage::Calc(calc) =&gt; { &gt; let p = Percentage(1. - calc.percentage.map_or(0., |p| p.0)); &gt; let l = -calc.unclamped_length(); &gt; ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage::new(l, Some(p))) &gt;- }, &gt;+ } &gt; } &gt;- }, &gt;- PositionComponent::Side(_, Some(ref length)) | &gt;- PositionComponent::Length(ref length) =&gt; length.to_computed_value(context), &gt;+ } &gt;+ PositionComponent::Side(_, Some(ref length)) &gt;+ | PositionComponent::Length(ref length) =&gt; length.to_computed_value(context), &gt; } &gt; } &gt; &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; PositionComponent::Length(ToComputedValue::from_computed_value(computed)) &gt; } &gt; } &gt; &gt;@@ -338,47 +362,47 @@ impl LegacyPosition { &gt; if let Ok(y_pos) = input.try(|i| OriginComponent::parse(context, i)) { &gt; return Ok(Self::new(x_pos, y_pos)); &gt; } &gt; let x_pos = input &gt; .try(|i| OriginComponent::parse(context, i)) &gt; .unwrap_or(x_pos); &gt; let y_pos = OriginComponent::Center; &gt; return Ok(Self::new(x_pos, y_pos)); &gt;- }, &gt;+ } &gt; Ok(OriginComponent::Side(x_keyword)) =&gt; { &gt; if let Ok(y_keyword) = input.try(Y::parse) { &gt; let x_pos = OriginComponent::Side(x_keyword); &gt; let y_pos = OriginComponent::Side(y_keyword); &gt; return Ok(Self::new(x_pos, y_pos)); &gt; } &gt; let x_pos = OriginComponent::Side(x_keyword); &gt; if let Ok(y_lop) = &gt; input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) &gt; { &gt; return Ok(Self::new(x_pos, OriginComponent::Length(y_lop))); &gt; } &gt; let _ = input.try(|i| i.expect_ident_matching("center")); &gt; return Ok(Self::new(x_pos, OriginComponent::Center)); &gt;- }, &gt;+ } &gt; Ok(x_pos @ OriginComponent::Length(_)) =&gt; { &gt; if let Ok(y_keyword) = input.try(Y::parse) { &gt; let y_pos = OriginComponent::Side(y_keyword); &gt; return Ok(Self::new(x_pos, y_pos)); &gt; } &gt; if let Ok(y_lop) = &gt; input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) &gt; { &gt; let y_pos = OriginComponent::Length(y_lop); &gt; return Ok(Self::new(x_pos, y_pos)); &gt; } &gt; let _ = input.try(|i| i.expect_ident_matching("center")); &gt; return Ok(Self::new(x_pos, OriginComponent::Center)); &gt;- }, &gt;- Err(_) =&gt; {}, &gt;+ } &gt;+ Err(_) =&gt; {} &gt; } &gt; let y_keyword = Y::parse(input)?; &gt; let x_pos: Result&lt;_, ParseError&gt; = input.try(|i| { &gt; if let Ok(x_keyword) = i.try(X::parse) { &gt; let x_pos = OriginComponent::Side(x_keyword); &gt; return Ok(x_pos); &gt; } &gt; i.expect_ident_matching("center")?; &gt;@@ -406,30 +430,32 @@ impl ToCss for LegacyPosition { &gt; W: Write, &gt; { &gt; self.horizontal.to_css(dest)?; &gt; dest.write_str(" ")?; &gt; self.vertical.to_css(dest) &gt; } &gt; } &gt; &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; /// Auto-placement algorithm Option &gt; pub enum AutoFlow { &gt; /// The auto-placement algorithm places items by filling each row in turn, &gt; /// adding new rows as necessary. &gt; Row, &gt; /// The auto-placement algorithm places items by filling each column in turn, &gt; /// adding new columns as necessary. &gt; Column, &gt; } &gt; &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; /// Controls how the auto-placement algorithm works &gt; /// specifying exactly how auto-placed items get flowed into the grid &gt; pub struct GridAutoFlow { &gt; /// Specifiy how auto-placement algorithm fills each `row` or `column` in turn &gt; pub autoflow: AutoFlow, &gt; /// Specify use `dense` packing algorithm or not &gt; #[css(represents_keyword)] &gt; pub dense: bool, &gt;@@ -625,18 +651,17 @@ impl Parse for TemplateAreas { &gt; } &gt; &gt; TemplateAreas::from_vec(strings) &gt; .map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt; } &gt; } &gt; &gt; /// Arc type for `Arc&lt;TemplateAreas&gt;` &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub struct TemplateAreasArc(#[ignore_malloc_size_of = "Arc"] pub Arc&lt;TemplateAreas&gt;); &gt; &gt; impl Parse for TemplateAreasArc { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let parsed = TemplateAreas::parse(context, input)?; &gt;@@ -680,18 +705,22 @@ impl&lt;'a&gt; Iterator for TemplateAreasTokenizer&lt;'a&gt; { &gt; let token_len = rest.find(|c| !is_name_code_point(c)).unwrap_or(rest.len()); &gt; let token = &amp;rest[..token_len]; &gt; self.0 = &amp;rest[token_len..]; &gt; Some(Ok(Some(token))) &gt; } &gt; } &gt; &gt; fn is_name_code_point(c: char) -&gt; bool { &gt;- c &gt;= 'A' &amp;&amp; c &lt;= 'Z' || c &gt;= 'a' &amp;&amp; c &lt;= 'z' || c &gt;= '\u{80}' || c == '_' || &gt;- c &gt;= '0' &amp;&amp; c &lt;= '9' || c == '-' &gt;+ c &gt;= 'A' &amp;&amp; c &lt;= 'Z' &gt;+ || c &gt;= 'a' &amp;&amp; c &lt;= 'z' &gt;+ || c &gt;= '\u{80}' &gt;+ || c == '_' &gt;+ || c &gt;= '0' &amp;&amp; c &lt;= '9' &gt;+ || c == '-' &gt; } &gt; &gt; /// This property specifies named grid areas. &gt; /// The syntax of this property also provides a visualization of &gt; /// the structure of the grid, making the overall layout of &gt; /// the grid container easier to understand. &gt; pub type GridTemplateAreas = Either&lt;TemplateAreasArc, None_&gt;; &gt; &gt;diff --git a/servo/components/style/values/specified/resolution.rs b/servo/components/style/values/specified/resolution.rs &gt;index 77a269c251b7..0878c7762728 100644 &gt;--- a/servo/components/style/values/specified/resolution.rs &gt;+++ b/servo/components/style/values/specified/resolution.rs &gt;@@ -27,28 +27,26 @@ pub enum Resolution { &gt; #[css(dimension)] &gt; Dpcm(CSSFloat), &gt; } &gt; &gt; impl Resolution { &gt; /// Convert this resolution value to dppx units. &gt; pub fn to_dppx(&amp;self) -&gt; CSSFloat { &gt; match *self { &gt;- Resolution::X(f) | &gt;- Resolution::Dppx(f) =&gt; f, &gt;+ Resolution::X(f) | Resolution::Dppx(f) =&gt; f, &gt; _ =&gt; self.to_dpi() / 96.0, &gt; } &gt; } &gt; &gt; /// Convert this resolution value to dpi units. &gt; pub fn to_dpi(&amp;self) -&gt; CSSFloat { &gt; match *self { &gt; Resolution::Dpi(f) =&gt; f, &gt;- Resolution::X(f) | &gt;- Resolution::Dppx(f) =&gt; f * 96.0, &gt;+ Resolution::X(f) | Resolution::Dppx(f) =&gt; f * 96.0, &gt; Resolution::Dpcm(f) =&gt; f * 2.54, &gt; } &gt; } &gt; } &gt; &gt; impl Parse for Resolution { &gt; fn parse&lt;'i, 't&gt;( &gt; _: &amp;ParserContext, &gt;diff --git a/servo/components/style/values/specified/source_size_list.rs b/servo/components/style/values/specified/source_size_list.rs &gt;index 33078c064840..86a1f84ef56e 100644 &gt;--- a/servo/components/style/values/specified/source_size_list.rs &gt;+++ b/servo/components/style/values/specified/source_size_list.rs &gt;@@ -56,17 +56,18 @@ impl SourceSizeList { &gt; &gt; /// Set content of `value`, which can be used as fall-back during evaluate. &gt; pub fn set_fallback_value(&amp;mut self, width: Option&lt;Length&gt;) { &gt; self.value = width; &gt; } &gt; &gt; /// Evaluate this &lt;source-size-list&gt; to get the final viewport length. &gt; pub fn evaluate(&amp;self, device: &amp;Device, quirks_mode: QuirksMode) -&gt; Au { &gt;- let matching_source_size = self.source_sizes &gt;+ let matching_source_size = self &gt;+ .source_sizes &gt; .iter() &gt; .find(|source_size| source_size.condition.matches(device, quirks_mode)); &gt; &gt; computed::Context::for_media_query_evaluation(device, quirks_mode, |context| { &gt; match matching_source_size { &gt; Some(source_size) =&gt; source_size.value.to_computed_value(context), &gt; None =&gt; match self.value { &gt; Some(ref v) =&gt; v.to_computed_value(context), &gt;@@ -111,25 +112,25 @@ impl SourceSizeList { &gt; }); &gt; &gt; match result { &gt; Ok(SourceSizeOrLength::Length(value)) =&gt; { &gt; return Self { &gt; source_sizes, &gt; value: Some(value), &gt; } &gt;- }, &gt;+ } &gt; Ok(SourceSizeOrLength::SourceSize(source_size)) =&gt; { &gt; source_sizes.push(source_size); &gt;- }, &gt;- Err(..) =&gt; {}, &gt;+ } &gt;+ Err(..) =&gt; {} &gt; } &gt; &gt; match input.next() { &gt;- Ok(&amp;Token::Comma) =&gt; {}, &gt;+ Ok(&amp;Token::Comma) =&gt; {} &gt; Err(..) =&gt; break, &gt; _ =&gt; unreachable!(), &gt; } &gt; } &gt; &gt; SourceSizeList { &gt; source_sizes, &gt; value: None, &gt;diff --git a/servo/components/style/values/specified/svg.rs b/servo/components/style/values/specified/svg.rs &gt;index e55442d7da82..9e59231c78de 100644 &gt;--- a/servo/components/style/values/specified/svg.rs &gt;+++ b/servo/components/style/values/specified/svg.rs &gt;@@ -4,22 +4,22 @@ &gt; &gt; //! Specified types for SVG properties. &gt; &gt; use cssparser::Parser; &gt; use parser::{Parse, ParserContext}; &gt; use std::fmt::{self, Write}; &gt; use style_traits::{CommaWithSpace, CssWriter, ParseError, Separator}; &gt; use style_traits::{StyleParseErrorKind, ToCss}; &gt;-use values::CustomIdent; &gt; use values::generics::svg as generic; &gt;-use values::specified::{LengthOrPercentage, NonNegativeLengthOrPercentage, NonNegativeNumber}; &gt;-use values::specified::{Number, Opacity}; &gt; use values::specified::color::Color; &gt; use values::specified::url::SpecifiedUrl; &gt;+use values::specified::{LengthOrPercentage, NonNegativeLengthOrPercentage, NonNegativeNumber}; &gt;+use values::specified::{Number, Opacity}; &gt;+use values::CustomIdent; &gt; &gt; /// Specified SVG Paint value &gt; pub type SVGPaint = generic::SVGPaint&lt;Color, SpecifiedUrl&gt;; &gt; &gt; /// Specified SVG Paint Kind value &gt; pub type SVGPaintKind = generic::SVGPaintKind&lt;Color, SpecifiedUrl&gt;; &gt; &gt; #[cfg(feature = "gecko")] &gt;@@ -168,18 +168,17 @@ const PAINT_ORDER_MASK: u8 = 0b11; &gt; /// &gt; /// Each pair can be set to FILL, STROKE, or MARKERS &gt; /// Lowest significant bit pairs are highest priority. &gt; /// `normal` is the empty bitfield. The three pairs are &gt; /// never zero in any case other than `normal`. &gt; /// &gt; /// Higher priority values, i.e. the values specified first, &gt; /// will be painted first (and may be covered by paintings of lower priority) &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct SVGPaintOrder(pub u8); &gt; &gt; impl SVGPaintOrder { &gt; /// Get default `paint-order` with `0` &gt; pub fn normal() -&gt; Self { &gt; SVGPaintOrder(0) &gt; } &gt; &gt;@@ -219,17 +218,17 @@ impl Parse for SVGPaintOrder { &gt; if (seen &amp; (1 &lt;&lt; val as u8)) != 0 { &gt; // don't parse the same ident twice &gt; return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt; &gt; value |= (val as u8) &lt;&lt; (pos * PAINT_ORDER_SHIFT); &gt; seen |= 1 &lt;&lt; (val as u8); &gt; pos += 1; &gt;- }, &gt;+ } &gt; Err(_) =&gt; break, &gt; } &gt; } &gt; &gt; if value == 0 { &gt; // Couldn't find any keyword &gt; return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt;@@ -276,18 +275,17 @@ impl ToCss for SVGPaintOrder { &gt; self.order_at(pos).to_css(dest)?; &gt; } &gt; Ok(()) &gt; } &gt; } &gt; &gt; /// Specified MozContextProperties value. &gt; /// Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties) &gt;-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss)] &gt; pub struct MozContextProperties(pub CustomIdent); &gt; &gt; impl Parse for MozContextProperties { &gt; fn parse&lt;'i, 't&gt;( &gt; _context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;MozContextProperties, ParseError&lt;'i&gt;&gt; { &gt; let location = input.current_source_location(); &gt;diff --git a/servo/components/style/values/specified/table.rs b/servo/components/style/values/specified/table.rs &gt;index 085c9adc9d87..0dd0755f95a1 100644 &gt;--- a/servo/components/style/values/specified/table.rs &gt;+++ b/servo/components/style/values/specified/table.rs &gt;@@ -3,18 +3,19 @@ &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Specified types for table properties. &gt; &gt; use cssparser::Parser; &gt; use parser::{Parse, ParserContext}; &gt; use style_traits::{ParseError, StyleParseErrorKind}; &gt; &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; /// span. for `&lt;col span&gt;` pres attr &gt; pub struct XSpan(#[css(skip)] pub i32); &gt; &gt; impl Parse for XSpan { &gt; // never parse it, only set via presentation attribute &gt; fn parse&lt;'i, 't&gt;( &gt; _: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt;diff --git a/servo/components/style/values/specified/text.rs b/servo/components/style/values/specified/text.rs &gt;index ae01040e45f8..afdc1e97d359 100644 &gt;--- a/servo/components/style/values/specified/text.rs &gt;+++ b/servo/components/style/values/specified/text.rs &gt;@@ -4,32 +4,32 @@ &gt; &gt; //! Specified types for text properties. &gt; &gt; use cssparser::{Parser, Token}; &gt; use parser::{Parse, ParserContext}; &gt; use properties::longhands::writing_mode::computed_value::T as SpecifiedWritingMode; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use std::fmt::{self, Write}; &gt;+use style_traits::values::SequenceWriter; &gt; use style_traits::{CssWriter, KeywordsCollectFn, ParseError}; &gt; use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; &gt;-use style_traits::values::SequenceWriter; &gt; use unicode_segmentation::UnicodeSegmentation; &gt;-use values::computed::{Context, ToComputedValue}; &gt; use values::computed::text::LineHeight as ComputedLineHeight; &gt; use values::computed::text::TextEmphasisKeywordValue as ComputedTextEmphasisKeywordValue; &gt; use values::computed::text::TextEmphasisStyle as ComputedTextEmphasisStyle; &gt; use values::computed::text::TextOverflow as ComputedTextOverflow; &gt;+use values::computed::{Context, ToComputedValue}; &gt; use values::generics::text::InitialLetter as GenericInitialLetter; &gt; use values::generics::text::LineHeight as GenericLineHeight; &gt; use values::generics::text::MozTabSize as GenericMozTabSize; &gt; use values::generics::text::Spacing; &gt;-use values::specified::{AllowQuirks, Integer, NonNegativeNumber, Number}; &gt; use values::specified::length::{FontRelativeLength, Length, LengthOrPercentage, NoCalcLength}; &gt; use values::specified::length::{NonNegativeLength, NonNegativeLengthOrPercentage}; &gt;+use values::specified::{AllowQuirks, Integer, NonNegativeNumber, Number}; &gt; &gt; /// A specified type for the `initial-letter` property. &gt; pub type InitialLetter = GenericInitialLetter&lt;Number, Integer&gt;; &gt; &gt; /// A specified value for the `letter-spacing` property. &gt; pub type LetterSpacing = Spacing&lt;Length&gt;; &gt; &gt; /// A specified value for the `word-spacing` property. &gt;@@ -88,18 +88,21 @@ impl Parse for LineHeight { &gt; let location = input.current_source_location(); &gt; let ident = input.expect_ident()?; &gt; match ident { &gt; ref ident if ident.eq_ignore_ascii_case("normal") =&gt; Ok(GenericLineHeight::Normal), &gt; #[cfg(feature = "gecko")] &gt; ref ident if ident.eq_ignore_ascii_case("-moz-block-height") =&gt; &gt; { &gt; Ok(GenericLineHeight::MozBlockHeight) &gt;- }, &gt;- ident =&gt; Err(location.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))), &gt;+ } &gt;+ ident =&gt; { &gt;+ Err(location &gt;+ .new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone()))) &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl ToComputedValue for LineHeight { &gt; type ComputedValue = ComputedLineHeight; &gt; &gt; #[inline] &gt;@@ -107,59 +110,59 @@ impl ToComputedValue for LineHeight { &gt; use values::computed::Length as ComputedLength; &gt; use values::specified::length::FontBaseSize; &gt; match *self { &gt; GenericLineHeight::Normal =&gt; GenericLineHeight::Normal, &gt; #[cfg(feature = "gecko")] &gt; GenericLineHeight::MozBlockHeight =&gt; GenericLineHeight::MozBlockHeight, &gt; GenericLineHeight::Number(number) =&gt; { &gt; GenericLineHeight::Number(number.to_computed_value(context)) &gt;- }, &gt;+ } &gt; GenericLineHeight::Length(ref non_negative_lop) =&gt; { &gt; let result = match non_negative_lop.0 { &gt; LengthOrPercentage::Length(NoCalcLength::Absolute(ref abs)) =&gt; { &gt; context &gt; .maybe_zoom_text(abs.to_computed_value(context).into()) &gt; .0 &gt;- }, &gt;+ } &gt; LengthOrPercentage::Length(ref length) =&gt; length.to_computed_value(context), &gt; LengthOrPercentage::Percentage(ref p) =&gt; FontRelativeLength::Em(p.0) &gt; .to_computed_value(context, FontBaseSize::CurrentStyle), &gt; LengthOrPercentage::Calc(ref calc) =&gt; { &gt; let computed_calc = &gt; calc.to_computed_value_zoomed(context, FontBaseSize::CurrentStyle); &gt; let font_relative_length = &gt; FontRelativeLength::Em(computed_calc.percentage()) &gt; .to_computed_value(context, FontBaseSize::CurrentStyle) &gt; .px(); &gt; &gt; let absolute_length = computed_calc.unclamped_length().px(); &gt; let pixel = computed_calc &gt; .clamping_mode &gt; .clamp(absolute_length + font_relative_length); &gt; ComputedLength::new(pixel) &gt;- }, &gt;+ } &gt; }; &gt; GenericLineHeight::Length(result.into()) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; match *computed { &gt; GenericLineHeight::Normal =&gt; GenericLineHeight::Normal, &gt; #[cfg(feature = "gecko")] &gt; GenericLineHeight::MozBlockHeight =&gt; GenericLineHeight::MozBlockHeight, &gt; GenericLineHeight::Number(ref number) =&gt; { &gt; GenericLineHeight::Number(NonNegativeNumber::from_computed_value(number)) &gt;- }, &gt;+ } &gt; GenericLineHeight::Length(ref length) =&gt; { &gt; GenericLineHeight::Length(NoCalcLength::from_computed_value(&amp;length.0).into()) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// A generic value for the `text-overflow` property. &gt; #[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)] &gt; pub enum TextOverflowSide { &gt; /// Clip inline content. &gt;@@ -180,17 +183,17 @@ impl Parse for TextOverflowSide { &gt; Token::Ident(ref ident) =&gt; { &gt; match_ignore_ascii_case! { ident, &gt; "clip" =&gt; Ok(TextOverflowSide::Clip), &gt; "ellipsis" =&gt; Ok(TextOverflowSide::Ellipsis), &gt; _ =&gt; Err(location.new_custom_error( &gt; SelectorParseErrorKind::UnexpectedIdent(ident.clone()) &gt; )) &gt; } &gt;- }, &gt;+ } &gt; Token::QuotedString(ref v) =&gt; Ok(TextOverflowSide::String( &gt; v.as_ref().to_owned().into_boxed_str(), &gt; )), &gt; ref t =&gt; Err(location.new_unexpected_token_error(t.clone())), &gt; } &gt; } &gt; } &gt; &gt;@@ -519,29 +522,29 @@ impl ToComputedValue for TextAlign { &gt; let ltr = _context.builder.inherited_writing_mode().is_bidi_ltr(); &gt; match (parent, ltr) { &gt; (TextAlignKeyword::Start, true) =&gt; TextAlignKeyword::Left, &gt; (TextAlignKeyword::Start, false) =&gt; TextAlignKeyword::Right, &gt; (TextAlignKeyword::End, true) =&gt; TextAlignKeyword::Right, &gt; (TextAlignKeyword::End, false) =&gt; TextAlignKeyword::Left, &gt; _ =&gt; parent, &gt; } &gt;- }, &gt;+ } &gt; #[cfg(feature = "gecko")] &gt; TextAlign::MozCenterOrInherit =&gt; { &gt; let parent = _context &gt; .builder &gt; .get_parent_inherited_text() &gt; .clone_text_align(); &gt; if parent == TextAlignKeyword::Start { &gt; TextAlignKeyword::Center &gt; } else { &gt; parent &gt; } &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; TextAlign::Keyword(*computed) &gt; } &gt; } &gt;@@ -566,44 +569,42 @@ pub enum TextEmphasisKeywordValue { &gt; Shape(TextEmphasisShapeKeyword), &gt; /// &lt;fill&gt; &lt;shape&gt; &gt; FillAndShape(TextEmphasisFillMode, TextEmphasisShapeKeyword), &gt; } &gt; &gt; impl TextEmphasisKeywordValue { &gt; fn fill(&amp;self) -&gt; Option&lt;TextEmphasisFillMode&gt; { &gt; match *self { &gt;- TextEmphasisKeywordValue::Fill(fill) | &gt;- TextEmphasisKeywordValue::FillAndShape(fill, _) =&gt; Some(fill), &gt;+ TextEmphasisKeywordValue::Fill(fill) &gt;+ | TextEmphasisKeywordValue::FillAndShape(fill, _) =&gt; Some(fill), &gt; _ =&gt; None, &gt; } &gt; } &gt; &gt; fn shape(&amp;self) -&gt; Option&lt;TextEmphasisShapeKeyword&gt; { &gt; match *self { &gt;- TextEmphasisKeywordValue::Shape(shape) | &gt;- TextEmphasisKeywordValue::FillAndShape(_, shape) =&gt; Some(shape), &gt;+ TextEmphasisKeywordValue::Shape(shape) &gt;+ | TextEmphasisKeywordValue::FillAndShape(_, shape) =&gt; Some(shape), &gt; _ =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; /// Fill mode for the text-emphasis-style property &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, &gt;- ToCss)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)] &gt; pub enum TextEmphasisFillMode { &gt; /// `filled` &gt; Filled, &gt; /// `open` &gt; Open, &gt; } &gt; &gt; /// Shape keyword for the text-emphasis-style property &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToCss)] &gt;+#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss)] &gt; pub enum TextEmphasisShapeKeyword { &gt; /// `dot` &gt; Dot, &gt; /// `circle` &gt; Circle, &gt; /// `double-circle` &gt; DoubleCircle, &gt; /// `triangle` &gt;@@ -648,47 +649,47 @@ impl TextEmphasisShapeKeyword { &gt; &gt; impl ToComputedValue for TextEmphasisStyle { &gt; type ComputedValue = ComputedTextEmphasisStyle; &gt; &gt; #[inline] &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Self::ComputedValue { &gt; match *self { &gt; TextEmphasisStyle::Keyword(ref keyword) =&gt; { &gt;- let default_shape = if context.style().get_inherited_box().clone_writing_mode() == &gt;- SpecifiedWritingMode::HorizontalTb &gt;+ let default_shape = if context.style().get_inherited_box().clone_writing_mode() &gt;+ == SpecifiedWritingMode::HorizontalTb &gt; { &gt; TextEmphasisShapeKeyword::Circle &gt; } else { &gt; TextEmphasisShapeKeyword::Sesame &gt; }; &gt; ComputedTextEmphasisStyle::Keyword(ComputedTextEmphasisKeywordValue { &gt; fill: keyword.fill().unwrap_or(TextEmphasisFillMode::Filled), &gt; shape: keyword.shape().unwrap_or(default_shape), &gt; }) &gt;- }, &gt;+ } &gt; TextEmphasisStyle::None =&gt; ComputedTextEmphasisStyle::None, &gt; TextEmphasisStyle::String(ref s) =&gt; { &gt; // Passing `true` to iterate over extended grapheme clusters, following &gt; // recommendation at http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries &gt; let string = s.graphemes(true).next().unwrap_or("").to_string(); &gt; ComputedTextEmphasisStyle::String(string) &gt;- }, &gt;+ } &gt; } &gt; } &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; match *computed { &gt; ComputedTextEmphasisStyle::Keyword(ref keyword) =&gt; TextEmphasisStyle::Keyword( &gt; TextEmphasisKeywordValue::FillAndShape(keyword.fill, keyword.shape), &gt; ), &gt; ComputedTextEmphasisStyle::None =&gt; TextEmphasisStyle::None, &gt; ComputedTextEmphasisStyle::String(ref string) =&gt; { &gt; TextEmphasisStyle::String(string.clone()) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl Parse for TextEmphasisStyle { &gt; fn parse&lt;'i, 't&gt;( &gt; _context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt;@@ -719,38 +720,59 @@ impl Parse for TextEmphasisStyle { &gt; (None, Some(shape)) =&gt; TextEmphasisKeywordValue::Shape(shape), &gt; _ =&gt; return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)), &gt; }; &gt; Ok(TextEmphasisStyle::Keyword(keyword_value)) &gt; } &gt; } &gt; &gt; /// The allowed horizontal values for the `text-emphasis-position` property. &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum TextEmphasisHorizontalWritingModeValue { &gt; /// Draw marks over the text in horizontal writing mode. &gt; Over, &gt; /// Draw marks under the text in horizontal writing mode. &gt; Under, &gt; } &gt; &gt; /// The allowed vertical values for the `text-emphasis-position` property. &gt;-#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, &gt;- SpecifiedValueInfo, ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, &gt;+ Copy, &gt;+ Debug, &gt;+ Eq, &gt;+ MallocSizeOf, &gt;+ Parse, &gt;+ PartialEq, &gt;+ SpecifiedValueInfo, &gt;+ ToComputedValue, &gt;+ ToCss, &gt;+)] &gt; pub enum TextEmphasisVerticalWritingModeValue { &gt; /// Draws marks to the right of the text in vertical writing mode. &gt; Right, &gt; /// Draw marks to the left of the text in vertical writing mode. &gt; Left, &gt; } &gt; &gt; /// Specified value of `text-emphasis-position` property. &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue, ToCss)] &gt;+#[derive( &gt;+ Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, &gt;+)] &gt; pub struct TextEmphasisPosition( &gt; pub TextEmphasisHorizontalWritingModeValue, &gt; pub TextEmphasisVerticalWritingModeValue, &gt; ); &gt; &gt; impl TextEmphasisPosition { &gt; #[inline] &gt; /// Returns the initial value of `text-emphasis-position` &gt;@@ -810,28 +832,28 @@ impl From&lt;u8&gt; for TextEmphasisPosition { &gt; #[cfg(feature = "gecko")] &gt; impl From&lt;TextEmphasisPosition&gt; for u8 { &gt; fn from(v: TextEmphasisPosition) -&gt; u8 { &gt; use gecko_bindings::structs; &gt; &gt; let mut result = match v.0 { &gt; TextEmphasisHorizontalWritingModeValue::Over =&gt; { &gt; structs::NS_STYLE_TEXT_EMPHASIS_POSITION_OVER &gt;- }, &gt;+ } &gt; TextEmphasisHorizontalWritingModeValue::Under =&gt; { &gt; structs::NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER &gt;- }, &gt;+ } &gt; }; &gt; match v.1 { &gt; TextEmphasisVerticalWritingModeValue::Right =&gt; { &gt; result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT; &gt;- }, &gt;+ } &gt; TextEmphasisVerticalWritingModeValue::Left =&gt; { &gt; result |= structs::NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT; &gt;- }, &gt;+ } &gt; }; &gt; result as u8 &gt; } &gt; } &gt; &gt; /// A specified value for the `-moz-tab-size` property. &gt; pub type MozTabSize = GenericMozTabSize&lt;NonNegativeNumber, NonNegativeLength&gt;; &gt; &gt;@@ -841,13 +863,12 @@ impl Parse for MozTabSize { &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; if let Ok(number) = input.try(|i| NonNegativeNumber::parse(context, i)) { &gt; // Numbers need to be parsed first because `0` must be recognised &gt; // as the number `0` and not the length `0px`. &gt; return Ok(GenericMozTabSize::Number(number)); &gt; } &gt; Ok(GenericMozTabSize::Length(NonNegativeLength::parse( &gt;- context, &gt;- input, &gt;+ context, input, &gt; )?)) &gt; } &gt; } &gt;diff --git a/servo/components/style/values/specified/time.rs b/servo/components/style/values/specified/time.rs &gt;index 107c45b2d488..e8a790793ead 100644 &gt;--- a/servo/components/style/values/specified/time.rs &gt;+++ b/servo/components/style/values/specified/time.rs &gt;@@ -2,22 +2,22 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Specified time values. &gt; &gt; use cssparser::{Parser, Token}; &gt; use parser::{Parse, ParserContext}; &gt; use std::fmt::{self, Write}; &gt;-use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; &gt; use style_traits::values::specified::AllowedNumericType; &gt;-use values::CSSFloat; &gt;-use values::computed::{Context, ToComputedValue}; &gt;+use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss}; &gt; use values::computed::time::Time as ComputedTime; &gt;+use values::computed::{Context, ToComputedValue}; &gt; use values::specified::calc::CalcNode; &gt;+use values::CSSFloat; &gt; &gt; /// A time value according to CSS-VALUES § 6.2. &gt; #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)] &gt; pub struct Time { &gt; seconds: CSSFloat, &gt; unit: TimeUnit, &gt; was_calc: bool, &gt; } &gt;@@ -87,22 +87,23 @@ impl Time { &gt; match input.next() { &gt; // Note that we generally pass ParserContext to is_ok() to check &gt; // that the ParserMode of the ParserContext allows all numeric &gt; // values for SMIL regardless of clamping_mode, but in this Time &gt; // value case, the value does not animate for SMIL at all, so we use &gt; // ParsingMode::DEFAULT directly. &gt; Ok(&amp;Token::Dimension { &gt; value, ref unit, .. &gt;- }) if clamping_mode.is_ok(ParsingMode::DEFAULT, value) =&gt; &gt;+ }) &gt;+ if clamping_mode.is_ok(ParsingMode::DEFAULT, value) =&gt; &gt; { &gt; return Time::parse_dimension(value, unit, /* from_calc = */ false) &gt; .map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)); &gt; } &gt;- Ok(&amp;Token::Function(ref name)) if name.eq_ignore_ascii_case("calc") =&gt; {}, &gt;+ Ok(&amp;Token::Function(ref name)) if name.eq_ignore_ascii_case("calc") =&gt; {} &gt; Ok(t) =&gt; return Err(location.new_unexpected_token_error(t.clone())), &gt; Err(e) =&gt; return Err(e.into()), &gt; } &gt; match input.parse_nested_block(|i| CalcNode::parse_time(context, i)) { &gt; Ok(time) if clamping_mode.is_ok(ParsingMode::DEFAULT, time.seconds) =&gt; Ok(time), &gt; _ =&gt; Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)), &gt; } &gt; } &gt;@@ -148,21 +149,21 @@ impl ToCss for Time { &gt; { &gt; if self.was_calc { &gt; dest.write_str("calc(")?; &gt; } &gt; match self.unit { &gt; TimeUnit::Second =&gt; { &gt; self.seconds.to_css(dest)?; &gt; dest.write_str("s")?; &gt;- }, &gt;+ } &gt; TimeUnit::Millisecond =&gt; { &gt; (self.seconds * 1000.).to_css(dest)?; &gt; dest.write_str("ms")?; &gt;- }, &gt;+ } &gt; } &gt; if self.was_calc { &gt; dest.write_str(")")?; &gt; } &gt; Ok(()) &gt; } &gt; } &gt; &gt;diff --git a/servo/components/style/values/specified/transform.rs b/servo/components/style/values/specified/transform.rs &gt;index 835d505836c0..9e3d660f15ea 100644 &gt;--- a/servo/components/style/values/specified/transform.rs &gt;+++ b/servo/components/style/values/specified/transform.rs &gt;@@ -3,23 +3,23 @@ &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Specified types for CSS values that are related to transformations. &gt; &gt; use cssparser::Parser; &gt; use parser::{Parse, ParserContext}; &gt; use selectors::parser::SelectorParseErrorKind; &gt; use style_traits::{ParseError, StyleParseErrorKind}; &gt;+use values::computed::transform::TimingFunction as ComputedTimingFunction; &gt; use values::computed::{Context, LengthOrPercentage as ComputedLengthOrPercentage}; &gt; use values::computed::{Percentage as ComputedPercentage, ToComputedValue}; &gt;-use values::computed::transform::TimingFunction as ComputedTimingFunction; &gt; use values::generics::transform as generic; &gt; use values::generics::transform::{Matrix, Matrix3D, StepPosition, TimingKeyword}; &gt;-use values::specified::{self, Angle, Integer, Length, LengthOrPercentage, Number}; &gt; use values::specified::position::{Side, X, Y}; &gt;+use values::specified::{self, Angle, Integer, Length, LengthOrPercentage, Number}; &gt; &gt; pub use values::generics::transform::TransformStyle; &gt; &gt; /// A single operation in a specified CSS `transform` &gt; pub type TransformOperation = &gt; generic::TransformOperation&lt;Angle, Number, Length, Integer, LengthOrPercentage&gt;; &gt; &gt; /// A specified CSS `transform` &gt;@@ -265,27 +265,27 @@ impl Parse for TransformOrigin { &gt; let y_origin = OriginComponent::Center; &gt; if let Ok(x_keyword) = input.try(X::parse) { &gt; let x_origin = OriginComponent::Side(x_keyword); &gt; let depth = parse_depth(input); &gt; return Ok(Self::new(x_origin, y_origin, depth)); &gt; } &gt; let depth = Length::from_px(0.); &gt; return Ok(Self::new(x_origin, y_origin, depth)); &gt;- }, &gt;+ } &gt; Ok(x_origin) =&gt; { &gt; if let Ok(y_origin) = input.try(|i| OriginComponent::parse(context, i)) { &gt; let depth = parse_depth(input); &gt; return Ok(Self::new(x_origin, y_origin, depth)); &gt; } &gt; let y_origin = OriginComponent::Center; &gt; let depth = Length::from_px(0.); &gt; return Ok(Self::new(x_origin, y_origin, depth)); &gt;- }, &gt;- Err(_) =&gt; {}, &gt;+ } &gt;+ Err(_) =&gt; {} &gt; } &gt; let y_keyword = Y::parse(input)?; &gt; let y_origin = OriginComponent::Side(y_keyword); &gt; if let Ok(x_keyword) = input.try(X::parse) { &gt; let x_origin = OriginComponent::Side(x_keyword); &gt; let depth = parse_depth(input); &gt; return Ok(Self::new(x_origin, y_origin, depth)); &gt; } &gt;@@ -324,22 +324,22 @@ where &gt; S: Side, &gt; { &gt; type ComputedValue = ComputedLengthOrPercentage; &gt; &gt; fn to_computed_value(&amp;self, context: &amp;Context) -&gt; Self::ComputedValue { &gt; match *self { &gt; OriginComponent::Center =&gt; { &gt; ComputedLengthOrPercentage::Percentage(ComputedPercentage(0.5)) &gt;- }, &gt;+ } &gt; OriginComponent::Length(ref length) =&gt; length.to_computed_value(context), &gt; OriginComponent::Side(ref keyword) =&gt; { &gt; let p = ComputedPercentage(if keyword.is_start() { 0. } else { 1. }); &gt; ComputedLengthOrPercentage::Percentage(p) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; OriginComponent::Length(ToComputedValue::from_computed_value(computed)) &gt; } &gt; } &gt; &gt;@@ -431,23 +431,23 @@ impl ToComputedValue for TimingFunction { &gt; generic::TimingFunction::Keyword(keyword) =&gt; generic::TimingFunction::Keyword(keyword), &gt; generic::TimingFunction::CubicBezier { x1, y1, x2, y2 } =&gt; { &gt; generic::TimingFunction::CubicBezier { &gt; x1: x1.to_computed_value(context), &gt; y1: y1.to_computed_value(context), &gt; x2: x2.to_computed_value(context), &gt; y2: y2.to_computed_value(context), &gt; } &gt;- }, &gt;+ } &gt; generic::TimingFunction::Steps(steps, position) =&gt; { &gt; generic::TimingFunction::Steps(steps.to_computed_value(context) as u32, position) &gt;- }, &gt;+ } &gt; generic::TimingFunction::Frames(frames) =&gt; { &gt; generic::TimingFunction::Frames(frames.to_computed_value(context) as u32) &gt;- }, &gt;+ } &gt; } &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; match *computed { &gt; generic::TimingFunction::Keyword(keyword) =&gt; generic::TimingFunction::Keyword(keyword), &gt; generic::TimingFunction::CubicBezier { &gt;@@ -462,17 +462,17 @@ impl ToComputedValue for TimingFunction { &gt; y2: Number::from_computed_value(y2), &gt; }, &gt; generic::TimingFunction::Steps(steps, position) =&gt; generic::TimingFunction::Steps( &gt; Integer::from_computed_value(&amp;(steps as i32)), &gt; position, &gt; ), &gt; generic::TimingFunction::Frames(frames) =&gt; { &gt; generic::TimingFunction::Frames(Integer::from_computed_value(&amp;(frames as i32))) &gt;- }, &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; /// A specified CSS `rotate` &gt; pub type Rotate = generic::Rotate&lt;Number, Angle&gt;; &gt; &gt; impl Parse for Rotate { &gt;diff --git a/servo/components/style/values/specified/ui.rs b/servo/components/style/values/specified/ui.rs &gt;index e912c24b8080..46826f8d367a 100644 &gt;--- a/servo/components/style/values/specified/ui.rs &gt;+++ b/servo/components/style/values/specified/ui.rs &gt;@@ -2,23 +2,23 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Specified types for UI properties. &gt; &gt; use cssparser::Parser; &gt; use parser::{Parse, ParserContext}; &gt; use std::fmt::{self, Write}; &gt;-use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt; use style_traits::cursor::CursorKind; &gt;-use values::{Auto, Either}; &gt;+use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss}; &gt; use values::generics::ui as generics; &gt;-use values::specified::Number; &gt; use values::specified::color::Color; &gt; use values::specified::url::SpecifiedImageUrl; &gt;+use values::specified::Number; &gt;+use values::{Auto, Either}; &gt; &gt; /// auto | &lt;color&gt; &gt; pub type ColorOrAuto = Either&lt;Color, Auto&gt;; &gt; &gt; /// A specified value for the `cursor` property. &gt; pub type Cursor = generics::Cursor&lt;CursorImage&gt;; &gt; &gt; /// A specified value for item of `image cursors`. &gt;@@ -47,19 +47,18 @@ impl Parse for Cursor { &gt; &gt; impl Parse for CursorKind { &gt; fn parse&lt;'i, 't&gt;( &gt; _context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt; let location = input.current_source_location(); &gt; let ident = input.expect_ident()?; &gt;- CursorKind::from_css_keyword(&amp;ident).map_err(|_| { &gt;- location.new_custom_error(StyleParseErrorKind::UnspecifiedError) &gt;- }) &gt;+ CursorKind::from_css_keyword(&amp;ident) &gt;+ .map_err(|_| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)) &gt; } &gt; } &gt; &gt; impl Parse for CursorImage { &gt; fn parse&lt;'i, 't&gt;( &gt; context: &amp;ParserContext, &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ParseError&lt;'i&gt;&gt; { &gt;@@ -69,18 +68,17 @@ impl Parse for CursorImage { &gt; Ok(number) =&gt; Some((number, Number::parse(context, input)?)), &gt; Err(_) =&gt; None, &gt; }, &gt; }) &gt; } &gt; } &gt; &gt; /// Specified value of `-moz-force-broken-image-icon` &gt;-#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, &gt;- ToComputedValue)] &gt;+#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue)] &gt; pub struct MozForceBrokenImageIcon(pub bool); &gt; &gt; impl MozForceBrokenImageIcon { &gt; /// Return initial value of -moz-force-broken-image-icon which is false. &gt; #[inline] &gt; pub fn false_value() -&gt; MozForceBrokenImageIcon { &gt; MozForceBrokenImageIcon(false) &gt; } &gt;diff --git a/servo/components/style/values/specified/url.rs b/servo/components/style/values/specified/url.rs &gt;index d5a165f22d81..fe68c3143f5b 100644 &gt;--- a/servo/components/style/values/specified/url.rs &gt;+++ b/servo/components/style/values/specified/url.rs &gt;@@ -1,18 +1,18 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Common handling for the specified value CSS url() values. &gt; &gt; use values::generics::url::UrlOrNone as GenericUrlOrNone; &gt; &gt;-#[cfg(feature = "servo")] &gt;-pub use servo::url::{SpecifiedImageUrl, SpecifiedUrl}; &gt; #[cfg(feature = "gecko")] &gt; pub use gecko::url::{SpecifiedImageUrl, SpecifiedUrl}; &gt;+#[cfg(feature = "servo")] &gt;+pub use servo::url::{SpecifiedImageUrl, SpecifiedUrl}; &gt; &gt; /// Specified &lt;url&gt; | &lt;none&gt; &gt; pub type UrlOrNone = GenericUrlOrNone&lt;SpecifiedUrl&gt;; &gt; &gt; /// Specified image &lt;url&gt; | &lt;none&gt; &gt; pub type ImageUrlOrNone = GenericUrlOrNone&lt;SpecifiedImageUrl&gt;; &gt;diff --git a/servo/components/style_derive/cg.rs b/servo/components/style_derive/cg.rs &gt;index b370a5c55d4b..2a835b47abe3 100644 &gt;--- a/servo/components/style_derive/cg.rs &gt;+++ b/servo/components/style_derive/cg.rs &gt;@@ -4,171 +4,186 @@ &gt; &gt; use darling::{FromDeriveInput, FromField, FromVariant}; &gt; use quote::Tokens; &gt; use syn::{self, AngleBracketedGenericArguments, Binding, DeriveInput, Field}; &gt; use syn::{GenericArgument, GenericParam, Ident, Path}; &gt; use syn::{PathArguments, PathSegment, QSelf, Type, TypeArray}; &gt; use syn::{TypeParam, TypeParen, TypePath, TypeSlice, TypeTuple}; &gt; use syn::{Variant, WherePredicate}; &gt;-use synstructure::{self, BindingInfo, BindStyle, VariantAst, VariantInfo}; &gt;+use synstructure::{self, BindStyle, BindingInfo, VariantAst, VariantInfo}; &gt; &gt;-pub fn add_predicate( &gt;- where_clause: &amp;mut Option&lt;syn::WhereClause&gt;, &gt;- pred: WherePredicate, &gt;-) { &gt;- where_clause.get_or_insert(parse_quote!(where)).predicates.push(pred); &gt;+pub fn add_predicate(where_clause: &amp;mut Option&lt;syn::WhereClause&gt;, pred: WherePredicate) { &gt;+ where_clause &gt;+ .get_or_insert(parse_quote!(where)) &gt;+ .predicates &gt;+ .push(pred); &gt; } &gt; &gt;-pub fn fmap_match&lt;F&gt;( &gt;- input: &amp;DeriveInput, &gt;- bind_style: BindStyle, &gt;- mut f: F, &gt;-) -&gt; Tokens &gt;+pub fn fmap_match&lt;F&gt;(input: &amp;DeriveInput, bind_style: BindStyle, mut f: F) -&gt; Tokens &gt; where &gt; F: FnMut(BindingInfo) -&gt; Tokens, &gt; { &gt; let mut s = synstructure::Structure::new(input); &gt;- s.variants_mut().iter_mut().for_each(|v| { v.bind_with(|_| bind_style); }); &gt;+ s.variants_mut().iter_mut().for_each(|v| { &gt;+ v.bind_with(|_| bind_style); &gt;+ }); &gt; s.each_variant(|variant| { &gt; let (mapped, mapped_fields) = value(variant, "mapped"); &gt; let fields_pairs = variant.bindings().into_iter().zip(mapped_fields); &gt; let mut computations = quote!(); &gt; computations.append_all(fields_pairs.map(|(field, mapped_field)| { &gt; let expr = f(field.clone()); &gt; quote! { let #mapped_field = #expr; } &gt; })); &gt; computations.append_all(mapped); &gt; Some(computations) &gt; }) &gt; } &gt; &gt;-pub fn fmap_trait_output( &gt;- input: &amp;DeriveInput, &gt;- trait_path: &amp;Path, &gt;- trait_output: Ident, &gt;-) -&gt; Path { &gt;+pub fn fmap_trait_output(input: &amp;DeriveInput, trait_path: &amp;Path, trait_output: Ident) -&gt; Path { &gt; let segment = PathSegment { &gt; ident: input.ident.clone(), &gt; arguments: PathArguments::AngleBracketed(AngleBracketedGenericArguments { &gt;- args: input.generics.params.iter().map(|arg| { &gt;- match arg { &gt;- &amp;GenericParam::Lifetime(ref data) =&gt; GenericArgument::Lifetime(data.lifetime.clone()), &gt;+ args: input &gt;+ .generics &gt;+ .params &gt;+ .iter() &gt;+ .map(|arg| match arg { &gt;+ &amp;GenericParam::Lifetime(ref data) =&gt; { &gt;+ GenericArgument::Lifetime(data.lifetime.clone()) &gt;+ } &gt; &amp;GenericParam::Type(ref data) =&gt; { &gt; let ident = data.ident; &gt; GenericArgument::Type( &gt; parse_quote!(&lt;#ident as ::#trait_path&gt;::#trait_output), &gt; ) &gt;- }, &gt;- ref arg =&gt; panic!("arguments {:?} cannot be mapped yet", arg) &gt;- } &gt;- }).collect(), &gt;+ } &gt;+ ref arg =&gt; panic!("arguments {:?} cannot be mapped yet", arg), &gt;+ }).collect(), &gt; colon2_token: Default::default(), &gt; gt_token: Default::default(), &gt; lt_token: Default::default(), &gt;- &gt;- }) &gt;+ }), &gt; }; &gt; segment.into() &gt; } &gt; &gt; pub fn map_type_params&lt;F&gt;(ty: &amp;Type, params: &amp;[&amp;TypeParam], f: &amp;mut F) -&gt; Type &gt; where &gt; F: FnMut(&amp;Ident) -&gt; Type, &gt; { &gt; match *ty { &gt;- Type::Slice(ref inner) =&gt; { &gt;- Type::from(TypeSlice { elem: Box::new(map_type_params(&amp;inner.elem, params, f)), ..inner.clone() }) &gt;- }, &gt;- Type::Array(ref inner) =&gt; { //ref ty, ref expr) =&gt; { &gt;- Type::from(TypeArray { elem: Box::new(map_type_params(&amp;inner.elem, params, f)), ..inner.clone() }) &gt;- }, &gt;+ Type::Slice(ref inner) =&gt; Type::from(TypeSlice { &gt;+ elem: Box::new(map_type_params(&amp;inner.elem, params, f)), &gt;+ ..inner.clone() &gt;+ }), &gt;+ Type::Array(ref inner) =&gt; { &gt;+ //ref ty, ref expr) =&gt; { &gt;+ Type::from(TypeArray { &gt;+ elem: Box::new(map_type_params(&amp;inner.elem, params, f)), &gt;+ ..inner.clone() &gt;+ }) &gt;+ } &gt; ref ty @ Type::Never(_) =&gt; ty.clone(), &gt;- Type::Tuple(ref inner) =&gt; { &gt;- Type::from( &gt;- TypeTuple { &gt;- elems: inner.elems.iter().map(|ty| map_type_params(&amp;ty, params, f)).collect(), &gt;- ..inner.clone() &gt;- } &gt;- ) &gt;- }, &gt;- Type::Path(TypePath { qself: None, ref path }) =&gt; { &gt;+ Type::Tuple(ref inner) =&gt; Type::from(TypeTuple { &gt;+ elems: inner &gt;+ .elems &gt;+ .iter() &gt;+ .map(|ty| map_type_params(&amp;ty, params, f)) &gt;+ .collect(), &gt;+ ..inner.clone() &gt;+ }), &gt;+ Type::Path(TypePath { &gt;+ qself: None, &gt;+ ref path, &gt;+ }) =&gt; { &gt; if let Some(ident) = path_to_ident(path) { &gt; if params.iter().any(|param| param.ident == ident) { &gt; return f(ident); &gt; } &gt; } &gt;- Type::from(TypePath { qself: None, path: map_type_params_in_path(path, params, f) }) &gt;- } &gt;- Type::Path(TypePath { ref qself, ref path }) =&gt; { &gt; Type::from(TypePath { &gt;- qself: qself.as_ref().map(|qself| { &gt;- QSelf { &gt;- ty: Box::new(map_type_params(&amp;qself.ty, params, f)), &gt;- position: qself.position, &gt;- ..qself.clone() &gt;- } &gt;- }), &gt;+ qself: None, &gt; path: map_type_params_in_path(path, params, f), &gt; }) &gt;- }, &gt;- Type::Paren(ref inner) =&gt; { &gt;- Type::from(TypeParen { elem: Box::new(map_type_params(&amp;inner.elem, params, f)), ..inner.clone() }) &gt;- }, &gt;+ } &gt;+ Type::Path(TypePath { &gt;+ ref qself, &gt;+ ref path, &gt;+ }) =&gt; Type::from(TypePath { &gt;+ qself: qself.as_ref().map(|qself| QSelf { &gt;+ ty: Box::new(map_type_params(&amp;qself.ty, params, f)), &gt;+ position: qself.position, &gt;+ ..qself.clone() &gt;+ }), &gt;+ path: map_type_params_in_path(path, params, f), &gt;+ }), &gt;+ Type::Paren(ref inner) =&gt; Type::from(TypeParen { &gt;+ elem: Box::new(map_type_params(&amp;inner.elem, params, f)), &gt;+ ..inner.clone() &gt;+ }), &gt; ref ty =&gt; panic!("type {:?} cannot be mapped yet", ty), &gt; } &gt; } &gt; &gt; fn map_type_params_in_path&lt;F&gt;(path: &amp;Path, params: &amp;[&amp;TypeParam], f: &amp;mut F) -&gt; Path &gt; where &gt; F: FnMut(&amp;Ident) -&gt; Type, &gt; { &gt; Path { &gt; leading_colon: path.leading_colon, &gt;- segments: path.segments.iter().map(|segment| { &gt;- PathSegment { &gt;+ segments: path &gt;+ .segments &gt;+ .iter() &gt;+ .map(|segment| PathSegment { &gt; ident: segment.ident.clone(), &gt; arguments: match segment.arguments { &gt; PathArguments::AngleBracketed(ref data) =&gt; { &gt; PathArguments::AngleBracketed(AngleBracketedGenericArguments { &gt;- args: data.args.iter().map(|arg| { &gt;- match arg { &gt;+ args: data &gt;+ .args &gt;+ .iter() &gt;+ .map(|arg| match arg { &gt; ty @ &amp;GenericArgument::Lifetime(_) =&gt; ty.clone(), &gt; &amp;GenericArgument::Type(ref data) =&gt; { &gt; GenericArgument::Type(map_type_params(data, params, f)) &gt;- }, &gt;- &amp;GenericArgument::Binding(ref data) =&gt; GenericArgument::Binding(Binding { &gt;- ty: map_type_params(&amp;data.ty, params, f), &gt;- ..data.clone() &gt;- }), &gt;- ref arg =&gt; panic!("arguments {:?} cannot be mapped yet", arg) &gt;- } &gt;- }).collect(), &gt;+ } &gt;+ &amp;GenericArgument::Binding(ref data) =&gt; { &gt;+ GenericArgument::Binding(Binding { &gt;+ ty: map_type_params(&amp;data.ty, params, f), &gt;+ ..data.clone() &gt;+ }) &gt;+ } &gt;+ ref arg =&gt; panic!("arguments {:?} cannot be mapped yet", arg), &gt;+ }).collect(), &gt; ..data.clone() &gt; }) &gt;- }, &gt;+ } &gt; ref arg @ PathArguments::None =&gt; arg.clone(), &gt;- ref parameters =&gt; { &gt;- panic!("parameters {:?} cannot be mapped yet", parameters) &gt;- } &gt;+ ref parameters =&gt; panic!("parameters {:?} cannot be mapped yet", parameters), &gt; }, &gt;- } &gt;- }).collect(), &gt;+ }).collect(), &gt; } &gt; } &gt; &gt; fn path_to_ident(path: &amp;Path) -&gt; Option&lt;&amp;Ident&gt; { &gt; match *path { &gt;- Path { leading_colon: None, ref segments } if segments.len() == 1 =&gt; { &gt;+ Path { &gt;+ leading_colon: None, &gt;+ ref segments, &gt;+ } &gt;+ if segments.len() == 1 =&gt; &gt;+ { &gt; if segments[0].arguments.is_empty() { &gt; Some(&amp;segments[0].ident) &gt; } else { &gt; None &gt; } &gt;- }, &gt;+ } &gt; _ =&gt; None, &gt; } &gt; } &gt; &gt; pub fn parse_field_attrs&lt;A&gt;(field: &amp;Field) -&gt; A &gt; where &gt; A: FromField, &gt; { &gt;@@ -198,58 +213,55 @@ where &gt; fields: variant.fields.clone(), &gt; discriminant: variant.discriminant.clone(), &gt; }; &gt; parse_variant_attrs(&amp;v) &gt; } &gt; &gt; pub fn parse_variant_attrs&lt;A&gt;(variant: &amp;Variant) -&gt; A &gt; where &gt;- A: FromVariant &gt;+ A: FromVariant, &gt; { &gt; match A::from_variant(variant) { &gt; Ok(attrs) =&gt; attrs, &gt; Err(e) =&gt; panic!("failed to parse variant attributes: {}", e), &gt; } &gt; } &gt; &gt;- &gt;-pub fn ref_pattern&lt;'a&gt;( &gt;- variant: &amp;'a VariantInfo, &gt;- prefix: &amp;str, &gt;-) -&gt; (Tokens, Vec&lt;BindingInfo&lt;'a&gt;&gt;) { &gt;+pub fn ref_pattern&lt;'a&gt;(variant: &amp;'a VariantInfo, prefix: &amp;str) -&gt; (Tokens, Vec&lt;BindingInfo&lt;'a&gt;&gt;) { &gt; let mut v = variant.clone(); &gt; v.bind_with(|_| BindStyle::Ref); &gt;- v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) }); &gt;+ v.bindings_mut() &gt;+ .iter_mut() &gt;+ .for_each(|b| b.binding = Ident::from(format!("{}_{}", b.binding, prefix))); &gt; (v.pat(), v.bindings().iter().cloned().collect()) &gt; } &gt; &gt;-pub fn value&lt;'a&gt;( &gt;- variant: &amp;'a VariantInfo, &gt;- prefix: &amp;str, &gt;-) -&gt; (Tokens, Vec&lt;BindingInfo&lt;'a&gt;&gt;) { &gt;+pub fn value&lt;'a&gt;(variant: &amp;'a VariantInfo, prefix: &amp;str) -&gt; (Tokens, Vec&lt;BindingInfo&lt;'a&gt;&gt;) { &gt; let mut v = variant.clone(); &gt;- v.bindings_mut().iter_mut().for_each(|b| { b.binding = Ident::from(format!("{}_{}", b.binding, prefix)) }); &gt;+ v.bindings_mut() &gt;+ .iter_mut() &gt;+ .for_each(|b| b.binding = Ident::from(format!("{}_{}", b.binding, prefix))); &gt; v.bind_with(|_| BindStyle::Move); &gt; (v.pat(), v.bindings().iter().cloned().collect()) &gt; } &gt; &gt; /// Transforms "FooBar" to "foo-bar". &gt; /// &gt; /// If the first Camel segment is "Moz", "Webkit", or "Servo", the result string &gt; /// is prepended with "-". &gt; pub fn to_css_identifier(mut camel_case: &amp;str) -&gt; String { &gt; camel_case = camel_case.trim_right_matches('_'); &gt; let mut first = true; &gt; let mut result = String::with_capacity(camel_case.len()); &gt; while let Some(segment) = split_camel_segment(&amp;mut camel_case) { &gt; if first { &gt; match segment { &gt; "Moz" | "Webkit" | "Servo" =&gt; first = false, &gt;- _ =&gt; {}, &gt;+ _ =&gt; {} &gt; } &gt; } &gt; if !first { &gt; result.push_str("-"); &gt; } &gt; first = false; &gt; result.push_str(&amp;segment.to_lowercase()); &gt; } &gt;diff --git a/servo/components/style_derive/lib.rs b/servo/components/style_derive/lib.rs &gt;index 8c8c0705e8fd..d437fb19900f 100644 &gt;--- a/servo/components/style_derive/lib.rs &gt;+++ b/servo/components/style_derive/lib.rs &gt;@@ -1,18 +1,21 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; #![recursion_limit = "128"] &gt; &gt;-#[macro_use] extern crate darling; &gt;+#[macro_use] &gt;+extern crate darling; &gt; extern crate proc_macro; &gt;-#[macro_use] extern crate quote; &gt;-#[macro_use] extern crate syn; &gt;+#[macro_use] &gt;+extern crate quote; &gt;+#[macro_use] &gt;+extern crate syn; &gt; extern crate synstructure; &gt; &gt; use proc_macro::TokenStream; &gt; &gt; mod animate; &gt; mod cg; &gt; mod compute_squared_distance; &gt; mod parse; &gt;diff --git a/servo/components/style_derive/parse.rs b/servo/components/style_derive/parse.rs &gt;index 13d8aa6f48b9..76d2c8a82fc6 100644 &gt;--- a/servo/components/style_derive/parse.rs &gt;+++ b/servo/components/style_derive/parse.rs &gt;@@ -22,33 +22,33 @@ pub fn derive(input: DeriveInput) -&gt; Tokens { &gt; let mut saw_condition = false; &gt; let match_body = s.variants().iter().fold(quote!(), |match_body, variant| { &gt; let bindings = variant.bindings(); &gt; assert!( &gt; bindings.is_empty(), &gt; "Parse is only supported for single-variant enums for now" &gt; ); &gt; &gt;- let css_variant_attrs = &gt;- cg::parse_variant_attrs_from_ast::&lt;CssVariantAttrs&gt;(&amp;variant.ast()); &gt;- let parse_attrs = &gt;- cg::parse_variant_attrs_from_ast::&lt;ParseVariantAttrs&gt;(&amp;variant.ast()); &gt;+ let css_variant_attrs = cg::parse_variant_attrs_from_ast::&lt;CssVariantAttrs&gt;(&amp;variant.ast()); &gt;+ let parse_attrs = cg::parse_variant_attrs_from_ast::&lt;ParseVariantAttrs&gt;(&amp;variant.ast()); &gt; if css_variant_attrs.skip { &gt; return match_body; &gt; } &gt; &gt; let identifier = cg::to_css_identifier( &gt;- &amp;css_variant_attrs.keyword.unwrap_or(variant.ast().ident.as_ref().into()), &gt;+ &amp;css_variant_attrs &gt;+ .keyword &gt;+ .unwrap_or(variant.ast().ident.as_ref().into()), &gt; ); &gt; let ident = &amp;variant.ast().ident; &gt; &gt; saw_condition |= parse_attrs.condition.is_some(); &gt; let condition = match parse_attrs.condition { &gt; Some(ref p) =&gt; quote! { if #p(context) }, &gt;- None =&gt; quote! { }, &gt;+ None =&gt; quote!{}, &gt; }; &gt; &gt; let mut body = quote! { &gt; #match_body &gt; #identifier #condition =&gt; Ok(#name::#ident), &gt; }; &gt; &gt; let aliases = match parse_attrs.aliases { &gt;@@ -82,17 +82,16 @@ pub fn derive(input: DeriveInput) -&gt; Tokens { &gt; ::cssparser::Token::Ident(ident.clone()) &gt; )) &gt; } &gt; } &gt; } else { &gt; quote! { Self::parse(input) } &gt; }; &gt; &gt;- &gt; let parse_trait_impl = quote! { &gt; impl ::parser::Parse for #name { &gt; #[inline] &gt; fn parse&lt;'i, 't&gt;( &gt; #context_ident: &amp;::parser::ParserContext, &gt; input: &amp;mut ::cssparser::Parser&lt;'i, 't&gt;, &gt; ) -&gt; Result&lt;Self, ::style_traits::ParseError&lt;'i&gt;&gt; { &gt; #parse_body &gt;diff --git a/servo/components/style_derive/specified_value_info.rs b/servo/components/style_derive/specified_value_info.rs &gt;index b707ec2c69fc..186aadd2866e 100644 &gt;--- a/servo/components/style_derive/specified_value_info.rs &gt;+++ b/servo/components/style_derive/specified_value_info.rs &gt;@@ -12,18 +12,18 @@ pub fn derive(mut input: DeriveInput) -&gt; Tokens { &gt; let css_attrs = cg::parse_input_attrs::&lt;CssInputAttrs&gt;(&amp;input); &gt; let mut types = vec![]; &gt; let mut values = vec![]; &gt; &gt; let input_ident = input.ident; &gt; let input_name = || cg::to_css_identifier(input_ident.as_ref()); &gt; if let Some(function) = css_attrs.function { &gt; values.push(function.explicit().unwrap_or_else(input_name)); &gt;- // If the whole value is wrapped in a function, value types of &gt;- // its fields should not be propagated. &gt;+ // If the whole value is wrapped in a function, value types of &gt;+ // its fields should not be propagated. &gt; } else { &gt; let mut where_clause = input.generics.where_clause.take(); &gt; for param in input.generics.type_params() { &gt; cg::add_predicate( &gt; &amp;mut where_clause, &gt; parse_quote!(#param: ::style_traits::SpecifiedValueInfo), &gt; ); &gt; } &gt;@@ -79,23 +79,27 @@ pub fn derive(mut input: DeriveInput) -&gt; Tokens { &gt; let info_attrs = cg::parse_input_attrs::&lt;ValueInfoInputAttrs&gt;(&amp;input); &gt; if let Some(other_values) = info_attrs.other_values { &gt; for value in other_values.split(",") { &gt; values.push(value.to_string()); &gt; } &gt; } &gt; &gt; let mut types_value = quote!(0); &gt;- types_value.append_all(types.iter().map(|ty| quote! { &gt;- | &lt;#ty as ::style_traits::SpecifiedValueInfo&gt;::SUPPORTED_TYPES &gt;+ types_value.append_all(types.iter().map(|ty| { &gt;+ quote! { &gt;+ | &lt;#ty as ::style_traits::SpecifiedValueInfo&gt;::SUPPORTED_TYPES &gt;+ } &gt; })); &gt; &gt; let mut nested_collects = quote!(); &gt;- nested_collects.append_all(types.iter().map(|ty| quote! { &gt;- &lt;#ty as ::style_traits::SpecifiedValueInfo&gt;::collect_completion_keywords(_f); &gt;+ nested_collects.append_all(types.iter().map(|ty| { &gt;+ quote! { &gt;+ &lt;#ty as ::style_traits::SpecifiedValueInfo&gt;::collect_completion_keywords(_f); &gt;+ } &gt; })); &gt; &gt; if let Some(ty) = info_attrs.ty { &gt; types_value.append_all(quote! { &gt; | ::style_traits::CssType::#ty &gt; }); &gt; } &gt; &gt;@@ -139,17 +143,19 @@ fn derive_struct_fields&lt;'a&gt;( &gt; let info_attrs = cg::parse_field_attrs::&lt;ValueInfoFieldAttrs&gt;(field); &gt; if let Some(other_values) = info_attrs.other_values { &gt; for value in other_values.split(",") { &gt; values.push(value.to_string()); &gt; } &gt; } &gt; let css_attrs = cg::parse_field_attrs::&lt;CssFieldAttrs&gt;(field); &gt; if css_attrs.represents_keyword { &gt;- let ident = field.ident.as_ref() &gt;+ let ident = field &gt;+ .ident &gt;+ .as_ref() &gt; .expect("only named field should use represents_keyword"); &gt; values.push(cg::to_css_identifier(ident.as_ref())); &gt; return None; &gt; } &gt; if let Some(if_empty) = css_attrs.if_empty { &gt; values.push(if_empty); &gt; } &gt; if !css_attrs.skip { &gt;diff --git a/servo/components/style_derive/to_animated_value.rs b/servo/components/style_derive/to_animated_value.rs &gt;index a7378b70145e..f9be9391ef66 100644 &gt;--- a/servo/components/style_derive/to_animated_value.rs &gt;+++ b/servo/components/style_derive/to_animated_value.rs &gt;@@ -11,22 +11,26 @@ pub fn derive(mut input: DeriveInput) -&gt; quote::Tokens { &gt; let mut where_clause = input.generics.where_clause.take(); &gt; for param in input.generics.type_params() { &gt; cg::add_predicate( &gt; &amp;mut where_clause, &gt; parse_quote!(#param: ::values::animated::ToAnimatedValue), &gt; ); &gt; } &gt; &gt;- let to_body = cg::fmap_match(&amp;input, BindStyle::Move, |binding| { &gt;- quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding)) &gt;- }); &gt;- let from_body = cg::fmap_match(&amp;input, BindStyle::Move, |binding| { &gt;- quote!(::values::animated::ToAnimatedValue::from_animated_value(#binding)) &gt;- }); &gt;+ let to_body = cg::fmap_match( &gt;+ &amp;input, &gt;+ BindStyle::Move, &gt;+ |binding| quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding)), &gt;+ ); &gt;+ let from_body = cg::fmap_match( &gt;+ &amp;input, &gt;+ BindStyle::Move, &gt;+ |binding| quote!(::values::animated::ToAnimatedValue::from_animated_value(#binding)), &gt;+ ); &gt; &gt; input.generics.where_clause = where_clause; &gt; let name = &amp;input.ident; &gt; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); &gt; let animated_value_type = cg::fmap_trait_output( &gt; &amp;input, &gt; &amp;parse_quote!(values::animated::ToAnimatedValue), &gt; "AnimatedValue".into(), &gt;diff --git a/servo/components/style_derive/to_computed_value.rs b/servo/components/style_derive/to_computed_value.rs &gt;index 9b7544ffbb85..e34690bc999e 100644 &gt;--- a/servo/components/style_derive/to_computed_value.rs &gt;+++ b/servo/components/style_derive/to_computed_value.rs &gt;@@ -18,19 +18,21 @@ pub fn derive(mut input: DeriveInput) -&gt; Tokens { &gt; ); &gt; } &gt; &gt; let to_body = cg::fmap_match(&amp;input, BindStyle::Ref, |binding| { &gt; let attrs = cg::parse_field_attrs::&lt;ComputedValueAttrs&gt;(&amp;binding.ast()); &gt; if attrs.field_bound { &gt; let ty = &amp;binding.ast().ty; &gt; &gt;- let output_type = cg::map_type_params(ty, &amp;params, &amp;mut |ident| { &gt;- parse_quote!(&lt;#ident as ::values::computed::ToComputedValue&gt;::ComputedValue) &gt;- }); &gt;+ let output_type = cg::map_type_params( &gt;+ ty, &gt;+ &amp;params, &gt;+ &amp;mut |ident| parse_quote!(&lt;#ident as ::values::computed::ToComputedValue&gt;::ComputedValue), &gt;+ ); &gt; &gt; cg::add_predicate( &gt; &amp;mut where_clause, &gt; parse_quote!( &gt; #ty: ::values::computed::ToComputedValue&lt;ComputedValue = #output_type&gt; &gt; ), &gt; ); &gt; } &gt;@@ -66,17 +68,17 @@ pub fn derive(mut input: DeriveInput) -&gt; Tokens { &gt; ::std::clone::Clone::clone(self) &gt; } &gt; &gt; #[inline] &gt; fn from_computed_value(computed: &amp;Self::ComputedValue) -&gt; Self { &gt; ::std::clone::Clone::clone(computed) &gt; } &gt; } &gt;- } &gt;+ }; &gt; } &gt; &gt; let computed_value_type = cg::fmap_trait_output( &gt; &amp;input, &gt; &amp;parse_quote!(values::computed::ToComputedValue), &gt; "ComputedValue".into(), &gt; ); &gt; &gt;diff --git a/servo/components/style_derive/to_css.rs b/servo/components/style_derive/to_css.rs &gt;index 83177f3c89fb..a5811471cb1d 100644 &gt;--- a/servo/components/style_derive/to_css.rs &gt;+++ b/servo/components/style_derive/to_css.rs &gt;@@ -14,25 +14,26 @@ pub fn derive(mut input: syn::DeriveInput) -&gt; Tokens { &gt; cg::add_predicate( &gt; &amp;mut where_clause, &gt; parse_quote!(#param: ::style_traits::ToCss), &gt; ); &gt; } &gt; &gt; let input_attrs = cg::parse_input_attrs::&lt;CssInputAttrs&gt;(&amp;input); &gt; if let Data::Enum(_) = input.data { &gt;- assert!(input_attrs.function.is_none(), "#[css(function)] is not allowed on enums"); &gt;+ assert!( &gt;+ input_attrs.function.is_none(), &gt;+ "#[css(function)] is not allowed on enums" &gt;+ ); &gt; assert!(!input_attrs.comma, "#[css(comma)] is not allowed on enums"); &gt; } &gt; &gt; let match_body = { &gt; let s = Structure::new(&amp;input); &gt;- s.each_variant(|variant| { &gt;- derive_variant_arm(variant, &amp;mut where_clause) &gt;- }) &gt;+ s.each_variant(|variant| derive_variant_arm(variant, &amp;mut where_clause)) &gt; }; &gt; input.generics.where_clause = where_clause; &gt; &gt; let name = &amp;input.ident; &gt; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); &gt; &gt; let mut impls = quote! { &gt; impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause { &gt;@@ -63,20 +64,17 @@ pub fn derive(mut input: syn::DeriveInput) -&gt; Tokens { &gt; } &gt; } &gt; }); &gt; } &gt; &gt; impls &gt; } &gt; &gt;-fn derive_variant_arm( &gt;- variant: &amp;VariantInfo, &gt;- generics: &amp;mut Option&lt;WhereClause&gt;, &gt;-) -&gt; Tokens { &gt;+fn derive_variant_arm(variant: &amp;VariantInfo, generics: &amp;mut Option&lt;WhereClause&gt;) -&gt; Tokens { &gt; let bindings = variant.bindings(); &gt; let identifier = cg::to_css_identifier(variant.ast().ident.as_ref()); &gt; let ast = variant.ast(); &gt; let variant_attrs = cg::parse_variant_attrs_from_ast::&lt;CssVariantAttrs&gt;(&amp;ast); &gt; let separator = if variant_attrs.comma { ", " } else { " " }; &gt; &gt; if variant_attrs.skip { &gt; return quote!(Ok(())); &gt;@@ -119,23 +117,25 @@ fn derive_variant_arm( &gt; expr &gt; } &gt; &gt; fn derive_variant_fields_expr( &gt; bindings: &amp;[BindingInfo], &gt; where_clause: &amp;mut Option&lt;WhereClause&gt;, &gt; separator: &amp;str, &gt; ) -&gt; Tokens { &gt;- let mut iter = bindings.iter().filter_map(|binding| { &gt;- let attrs = cg::parse_field_attrs::&lt;CssFieldAttrs&gt;(&amp;binding.ast()); &gt;- if attrs.skip { &gt;- return None; &gt;- } &gt;- Some((binding, attrs)) &gt;- }).peekable(); &gt;+ let mut iter = bindings &gt;+ .iter() &gt;+ .filter_map(|binding| { &gt;+ let attrs = cg::parse_field_attrs::&lt;CssFieldAttrs&gt;(&amp;binding.ast()); &gt;+ if attrs.skip { &gt;+ return None; &gt;+ } &gt;+ Some((binding, attrs)) &gt;+ }).peekable(); &gt; &gt; let (first, attrs) = match iter.next() { &gt; Some(pair) =&gt; pair, &gt; None =&gt; return quote! { Ok(()) }, &gt; }; &gt; if !attrs.iterable &amp;&amp; iter.peek().is_none() { &gt; if attrs.field_bound { &gt; let ty = &amp;first.ast().ty; &gt;@@ -185,18 +185,21 @@ fn derive_single_field_expr( &gt; }; &gt; } &gt; quote! { &gt; for item in #field.iter() { &gt; writer.item(&amp;item)?; &gt; } &gt; } &gt; } else if attrs.represents_keyword { &gt;- let ident = &gt;- field.ast().ident.as_ref().expect("Unnamed field with represents_keyword?"); &gt;+ let ident = field &gt;+ .ast() &gt;+ .ident &gt;+ .as_ref() &gt;+ .expect("Unnamed field with represents_keyword?"); &gt; let ident = cg::to_css_identifier(ident.as_ref()); &gt; quote! { &gt; if *#field { &gt; writer.raw_item(#ident)?; &gt; } &gt; } &gt; } else { &gt; if attrs.field_bound { &gt;diff --git a/servo/components/style_traits/lib.rs b/servo/components/style_traits/lib.rs &gt;index 737450b5e059..8ec0ddb959c6 100644 &gt;--- a/servo/components/style_traits/lib.rs &gt;+++ b/servo/components/style_traits/lib.rs &gt;@@ -3,49 +3,61 @@ &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! This module contains shared types and messages for use by devtools/script. &gt; //! The traits are here instead of in script so that the devtools crate can be &gt; //! modified independently of the rest of Servo. &gt; &gt; #![crate_name = "style_traits"] &gt; #![crate_type = "rlib"] &gt;- &gt; #![deny(unsafe_code, missing_docs)] &gt; &gt; extern crate app_units; &gt;-#[macro_use] extern crate bitflags; &gt;-#[macro_use] extern crate cssparser; &gt;+#[macro_use] &gt;+extern crate bitflags; &gt;+#[macro_use] &gt;+extern crate cssparser; &gt; extern crate euclid; &gt; extern crate malloc_size_of; &gt;-#[macro_use] extern crate malloc_size_of_derive; &gt;+#[macro_use] &gt;+extern crate malloc_size_of_derive; &gt; extern crate selectors; &gt;-#[cfg(feature = "servo")] #[macro_use] extern crate serde; &gt;-#[cfg(feature = "servo")] extern crate webrender_api; &gt;+#[cfg(feature = "servo")] &gt;+#[macro_use] &gt;+extern crate serde; &gt; extern crate servo_arc; &gt;-#[cfg(feature = "servo")] extern crate servo_atoms; &gt;-#[cfg(feature = "servo")] extern crate servo_url; &gt;+#[cfg(feature = "servo")] &gt;+extern crate servo_atoms; &gt;+#[cfg(feature = "servo")] &gt;+extern crate servo_url; &gt;+#[cfg(feature = "servo")] &gt;+extern crate webrender_api; &gt; &gt;-#[cfg(feature = "servo")] pub use webrender_api::DevicePixel; &gt;+#[cfg(feature = "servo")] &gt;+pub use webrender_api::DevicePixel; &gt; &gt; use cssparser::{CowRcStr, Token}; &gt; use selectors::parser::SelectorParseErrorKind; &gt;-#[cfg(feature = "servo")] use servo_atoms::Atom; &gt;+#[cfg(feature = "servo")] &gt;+use servo_atoms::Atom; &gt; &gt; /// One hardware pixel. &gt; /// &gt; /// This unit corresponds to the smallest addressable element of the display hardware. &gt; #[cfg(not(feature = "servo"))] &gt; #[derive(Clone, Copy, Debug)] &gt; pub enum DevicePixel {} &gt; &gt; /// Represents a mobile style pinch zoom factor. &gt; /// TODO(gw): Once WR supports pinch zoom, use a type directly from webrender_api. &gt; #[derive(Clone, Copy, Debug, PartialEq)] &gt;-#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, MallocSizeOf))] &gt;+#[cfg_attr( &gt;+ feature = "servo", &gt;+ derive(Deserialize, Serialize, MallocSizeOf) &gt;+)] &gt; pub struct PinchZoomFactor(f32); &gt; &gt; impl PinchZoomFactor { &gt; /// Construct a new pinch zoom factor. &gt; pub fn new(scale: f32) -&gt; PinchZoomFactor { &gt; PinchZoomFactor(scale) &gt; } &gt; &gt;@@ -178,26 +190,24 @@ pub enum ValueParseErrorKind&lt;'i&gt; { &gt; impl&lt;'i&gt; StyleParseErrorKind&lt;'i&gt; { &gt; /// Create an InvalidValue parse error &gt; pub fn new_invalid&lt;S&gt;(name: S, value_error: ParseError&lt;'i&gt;) -&gt; ParseError&lt;'i&gt; &gt; where &gt; S: Into&lt;CowRcStr&lt;'i&gt;&gt;, &gt; { &gt; let name = name.into(); &gt; let variant = match value_error.kind { &gt;- cssparser::ParseErrorKind::Custom(StyleParseErrorKind::ValueError(e)) =&gt; { &gt;- match e { &gt;- ValueParseErrorKind::InvalidColor(token) =&gt; { &gt;- StyleParseErrorKind::InvalidColor(name, token) &gt;- } &gt;- ValueParseErrorKind::InvalidFilter(token) =&gt; { &gt;- StyleParseErrorKind::InvalidFilter(name, token) &gt;- } &gt;+ cssparser::ParseErrorKind::Custom(StyleParseErrorKind::ValueError(e)) =&gt; match e { &gt;+ ValueParseErrorKind::InvalidColor(token) =&gt; { &gt;+ StyleParseErrorKind::InvalidColor(name, token) &gt; } &gt;- } &gt;+ ValueParseErrorKind::InvalidFilter(token) =&gt; { &gt;+ StyleParseErrorKind::InvalidFilter(name, token) &gt;+ } &gt;+ }, &gt; _ =&gt; StyleParseErrorKind::OtherInvalidValue(name), &gt; }; &gt; cssparser::ParseError { &gt; kind: cssparser::ParseErrorKind::Custom(variant), &gt; location: value_error.location, &gt; } &gt; } &gt; } &gt;@@ -231,10 +241,14 @@ impl ParsingMode { &gt; self.intersects(ParsingMode::ALLOW_ALL_NUMERIC_VALUES) &gt; } &gt; } &gt; &gt; #[cfg(feature = "servo")] &gt; /// Speculatively execute paint code in the worklet thread pool. &gt; pub trait SpeculativePainter: Send + Sync { &gt; /// &lt;https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image&gt; &gt;- fn speculatively_draw_a_paint_image(&amp;self, properties: Vec&lt;(Atom, String)&gt;, arguments: Vec&lt;String&gt;); &gt;+ fn speculatively_draw_a_paint_image( &gt;+ &amp;self, &gt;+ properties: Vec&lt;(Atom, String)&gt;, &gt;+ arguments: Vec&lt;String&gt;, &gt;+ ); &gt; } &gt;diff --git a/servo/components/style_traits/specified_value_info.rs b/servo/components/style_traits/specified_value_info.rs &gt;index e0dd5544d0a3..d16d183a132f 100644 &gt;--- a/servo/components/style_traits/specified_value_info.rs &gt;+++ b/servo/components/style_traits/specified_value_info.rs &gt;@@ -105,17 +105,17 @@ impl&lt;T: SpecifiedValueInfo&gt; SpecifiedValueInfo for [T] { &gt; macro_rules! impl_generic_specified_value_info { &gt; ($ty:ident&lt;$param:ident&gt;) =&gt; { &gt; impl&lt;$param: SpecifiedValueInfo&gt; SpecifiedValueInfo for $ty&lt;$param&gt; { &gt; const SUPPORTED_TYPES: u8 = $param::SUPPORTED_TYPES; &gt; fn collect_completion_keywords(f: KeywordsCollectFn) { &gt; $param::collect_completion_keywords(f); &gt; } &gt; } &gt;- } &gt;+ }; &gt; } &gt; impl_generic_specified_value_info!(Option&lt;T&gt;); &gt; impl_generic_specified_value_info!(Vec&lt;T&gt;); &gt; impl_generic_specified_value_info!(Arc&lt;T&gt;); &gt; impl_generic_specified_value_info!(StdArc&lt;T&gt;); &gt; impl_generic_specified_value_info!(Range&lt;Idx&gt;); &gt; &gt; impl&lt;T1, T2&gt; SpecifiedValueInfo for (T1, T2) &gt;diff --git a/servo/components/style_traits/values.rs b/servo/components/style_traits/values.rs &gt;index 8b3bd13dc202..c1761bb11573 100644 &gt;--- a/servo/components/style_traits/values.rs &gt;+++ b/servo/components/style_traits/values.rs &gt;@@ -1,17 +1,17 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Helper types and traits for the handling of CSS values. &gt; &gt; use app_units::Au; &gt;-use cssparser::{ParseError, Parser, Token, UnicodeRange, serialize_string}; &gt; use cssparser::ToCss as CssparserToCss; &gt;+use cssparser::{serialize_string, ParseError, Parser, Token, UnicodeRange}; &gt; use servo_arc::Arc; &gt; use std::fmt::{self, Write}; &gt; &gt; /// Serialises a value according to its CSS representation. &gt; /// &gt; /// This trait is implemented for `str` and its friends, serialising the string &gt; /// contents as a CSS quoted string. &gt; /// &gt;@@ -39,55 +39,72 @@ use std::fmt::{self, Write}; &gt; /// provided the field as an argument; &gt; /// * `#[css(represents_keyword)]` can be used on bool fields in order to &gt; /// serialize the field name if the field is true, or nothing otherwise. It &gt; /// also collects those keywords for `SpecifiedValueInfo`. &gt; /// * finally, one can put `#[css(derive_debug)]` on the whole type, to &gt; /// implement `Debug` by a single call to `ToCss::to_css`. &gt; pub trait ToCss { &gt; /// Serialize `self` in CSS syntax, writing to `dest`. &gt;- fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result where W: Write; &gt;+ fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt;+ where &gt;+ W: Write; &gt; &gt; /// Serialize `self` in CSS syntax and return a string. &gt; /// &gt; /// (This is a convenience wrapper for `to_css` and probably should not be overridden.) &gt; #[inline] &gt; fn to_css_string(&amp;self) -&gt; String { &gt; let mut s = String::new(); &gt; self.to_css(&amp;mut CssWriter::new(&amp;mut s)).unwrap(); &gt; s &gt; } &gt; } &gt; &gt;-impl&lt;'a, T&gt; ToCss for &amp;'a T where T: ToCss + ?Sized { &gt;- fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result where W: Write { &gt;+impl&lt;'a, T&gt; ToCss for &amp;'a T &gt;+where &gt;+ T: ToCss + ?Sized, &gt;+{ &gt;+ fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt;+ where &gt;+ W: Write, &gt;+ { &gt; (*self).to_css(dest) &gt; } &gt; } &gt; &gt; impl ToCss for str { &gt; #[inline] &gt;- fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result where W: Write { &gt;+ fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt;+ where &gt;+ W: Write, &gt;+ { &gt; serialize_string(self, dest) &gt; } &gt; } &gt; &gt; impl ToCss for String { &gt; #[inline] &gt;- fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result where W: Write { &gt;+ fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt;+ where &gt;+ W: Write, &gt;+ { &gt; serialize_string(self, dest) &gt; } &gt; } &gt; &gt; impl&lt;T&gt; ToCss for Option&lt;T&gt; &gt; where &gt; T: ToCss, &gt; { &gt; #[inline] &gt;- fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result where W: Write { &gt;+ fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt;+ where &gt;+ W: Write, &gt;+ { &gt; self.as_ref().map_or(Ok(()), |value| value.to_css(dest)) &gt; } &gt; } &gt; &gt; /// A writer tailored for serialising CSS. &gt; /// &gt; /// Coupled with SequenceWriter, this allows callers to transparently handle &gt; /// things like comma-separated values etc. &gt;@@ -98,17 +115,20 @@ pub struct CssWriter&lt;'w, W: 'w&gt; { &gt; &gt; impl&lt;'w, W&gt; CssWriter&lt;'w, W&gt; &gt; where &gt; W: Write, &gt; { &gt; /// Creates a new `CssWriter`. &gt; #[inline] &gt; pub fn new(inner: &amp;'w mut W) -&gt; Self { &gt;- Self { inner, prefix: Some("") } &gt;+ Self { &gt;+ inner, &gt;+ prefix: Some(""), &gt;+ } &gt; } &gt; } &gt; &gt; impl&lt;'w, W&gt; Write for CssWriter&lt;'w, W&gt; &gt; where &gt; W: Write, &gt; { &gt; #[inline] &gt;@@ -174,17 +194,17 @@ where &gt; inner.prefix = Some(""); &gt; } &gt; Self { inner, separator } &gt; } &gt; &gt; #[inline] &gt; fn write_item&lt;F&gt;(&amp;mut self, f: F) -&gt; fmt::Result &gt; where &gt;- F: FnOnce(&amp;mut CssWriter&lt;'b, W&gt;) -&gt; fmt::Result &gt;+ F: FnOnce(&amp;mut CssWriter&lt;'b, W&gt;) -&gt; fmt::Result, &gt; { &gt; let old_prefix = self.inner.prefix; &gt; if old_prefix.is_none() { &gt; // If there is no prefix in the inner writer, a previous &gt; // call to this method produced output, which means we need &gt; // to write the separator next time we produce output again. &gt; self.inner.prefix = Some(self.separator); &gt; } &gt;@@ -277,66 +297,66 @@ impl Separator for Comma { &gt; ", " &gt; } &gt; &gt; fn parse&lt;'i, 't, F, T, E&gt;( &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; parse_one: F, &gt; ) -&gt; Result&lt;Vec&lt;T&gt;, ParseError&lt;'i, E&gt;&gt; &gt; where &gt;- F: for&lt;'tt&gt; FnMut(&amp;mut Parser&lt;'i, 'tt&gt;) -&gt; Result&lt;T, ParseError&lt;'i, E&gt;&gt; &gt;+ F: for&lt;'tt&gt; FnMut(&amp;mut Parser&lt;'i, 'tt&gt;) -&gt; Result&lt;T, ParseError&lt;'i, E&gt;&gt;, &gt; { &gt; input.parse_comma_separated(parse_one) &gt; } &gt; } &gt; &gt; impl Separator for Space { &gt; fn separator() -&gt; &amp;'static str { &gt; " " &gt; } &gt; &gt; fn parse&lt;'i, 't, F, T, E&gt;( &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; mut parse_one: F, &gt; ) -&gt; Result&lt;Vec&lt;T&gt;, ParseError&lt;'i, E&gt;&gt; &gt; where &gt;- F: for&lt;'tt&gt; FnMut(&amp;mut Parser&lt;'i, 'tt&gt;) -&gt; Result&lt;T, ParseError&lt;'i, E&gt;&gt; &gt;+ F: for&lt;'tt&gt; FnMut(&amp;mut Parser&lt;'i, 'tt&gt;) -&gt; Result&lt;T, ParseError&lt;'i, E&gt;&gt;, &gt; { &gt;- input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. &gt;+ input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. &gt; let mut results = vec![parse_one(input)?]; &gt; loop { &gt;- input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. &gt;+ input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. &gt; if let Ok(item) = input.try(&amp;mut parse_one) { &gt; results.push(item); &gt; } else { &gt;- return Ok(results) &gt;+ return Ok(results); &gt; } &gt; } &gt; } &gt; } &gt; &gt; impl Separator for CommaWithSpace { &gt; fn separator() -&gt; &amp;'static str { &gt; ", " &gt; } &gt; &gt; fn parse&lt;'i, 't, F, T, E&gt;( &gt; input: &amp;mut Parser&lt;'i, 't&gt;, &gt; mut parse_one: F, &gt; ) -&gt; Result&lt;Vec&lt;T&gt;, ParseError&lt;'i, E&gt;&gt; &gt; where &gt;- F: for&lt;'tt&gt; FnMut(&amp;mut Parser&lt;'i, 'tt&gt;) -&gt; Result&lt;T, ParseError&lt;'i, E&gt;&gt; &gt;+ F: for&lt;'tt&gt; FnMut(&amp;mut Parser&lt;'i, 'tt&gt;) -&gt; Result&lt;T, ParseError&lt;'i, E&gt;&gt;, &gt; { &gt;- input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. &gt;+ input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. &gt; let mut results = vec![parse_one(input)?]; &gt; loop { &gt;- input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. &gt;+ input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. &gt; let comma_location = input.current_source_location(); &gt; let comma = input.try(|i| i.expect_comma()).is_ok(); &gt;- input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. &gt;+ input.skip_whitespace(); // Unnecessary for correctness, but may help try() rewind less. &gt; if let Ok(item) = input.try(&amp;mut parse_one) { &gt; results.push(item); &gt; } else if comma { &gt; return Err(comma_location.new_unexpected_token_error(Token::Comma)); &gt; } else { &gt; break; &gt; } &gt; } &gt;@@ -350,55 +370,75 @@ pub trait OneOrMoreSeparated { &gt; /// Associated type indicating which separator is used. &gt; type S: Separator; &gt; } &gt; &gt; impl OneOrMoreSeparated for UnicodeRange { &gt; type S = Comma; &gt; } &gt; &gt;-impl&lt;T&gt; ToCss for Vec&lt;T&gt; where T: ToCss + OneOrMoreSeparated { &gt;- fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result where W: Write { &gt;+impl&lt;T&gt; ToCss for Vec&lt;T&gt; &gt;+where &gt;+ T: ToCss + OneOrMoreSeparated, &gt;+{ &gt;+ fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt;+ where &gt;+ W: Write, &gt;+ { &gt; let mut iter = self.iter(); &gt; iter.next().unwrap().to_css(dest)?; &gt; for item in iter { &gt; dest.write_str(&lt;T as OneOrMoreSeparated&gt;::S::separator())?; &gt; item.to_css(dest)?; &gt; } &gt; Ok(()) &gt; } &gt; } &gt; &gt;-impl&lt;T&gt; ToCss for Box&lt;T&gt; where T: ?Sized + ToCss { &gt;+impl&lt;T&gt; ToCss for Box&lt;T&gt; &gt;+where &gt;+ T: ?Sized + ToCss, &gt;+{ &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt;- where W: Write, &gt;+ where &gt;+ W: Write, &gt; { &gt; (**self).to_css(dest) &gt; } &gt; } &gt; &gt;-impl&lt;T&gt; ToCss for Arc&lt;T&gt; where T: ?Sized + ToCss { &gt;+impl&lt;T&gt; ToCss for Arc&lt;T&gt; &gt;+where &gt;+ T: ?Sized + ToCss, &gt;+{ &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt;- where W: Write, &gt;+ where &gt;+ W: Write, &gt; { &gt; (**self).to_css(dest) &gt; } &gt; } &gt; &gt; impl ToCss for Au { &gt;- fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result where W: Write { &gt;+ fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt;+ where &gt;+ W: Write, &gt;+ { &gt; self.to_f64_px().to_css(dest)?; &gt; dest.write_str("px") &gt; } &gt; } &gt; &gt; macro_rules! impl_to_css_for_predefined_type { &gt; ($name: ty) =&gt; { &gt; impl&lt;'a&gt; ToCss for $name { &gt;- fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result where W: Write { &gt;+ fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt;+ where &gt;+ W: Write, &gt;+ { &gt; ::cssparser::ToCss::to_css(self, dest) &gt; } &gt; } &gt; }; &gt; } &gt; &gt; impl_to_css_for_predefined_type!(f32); &gt; impl_to_css_for_predefined_type!(i8); &gt;diff --git a/servo/components/style_traits/viewport.rs b/servo/components/style_traits/viewport.rs &gt;index d961fa9e62ed..aeb4a75d53de 100644 &gt;--- a/servo/components/style_traits/viewport.rs &gt;+++ b/servo/components/style_traits/viewport.rs &gt;@@ -1,18 +1,18 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; //! Helper types for the `@viewport` rule. &gt; &gt;-use {CSSPixel, CssWriter, ParseError, PinchZoomFactor, ToCss}; &gt; use cssparser::Parser; &gt; use euclid::TypedSize2D; &gt; use std::fmt::{self, Write}; &gt;+use {CSSPixel, CssWriter, ParseError, PinchZoomFactor, ToCss}; &gt; &gt; define_css_keyword_enum! { &gt; pub enum UserZoom { &gt; Zoom = "zoom", &gt; Fixed = "fixed", &gt; } &gt; } &gt; &gt;@@ -23,32 +23,35 @@ define_css_keyword_enum! { &gt; Landscape = "landscape", &gt; } &gt; } &gt; &gt; /// A set of viewport descriptors: &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-device-adapt/#viewport-desc&gt; &gt; #[derive(Clone, Debug, PartialEq)] &gt;-#[cfg_attr(feature = "servo", derive(Deserialize, Serialize, MallocSizeOf))] &gt;+#[cfg_attr( &gt;+ feature = "servo", &gt;+ derive(Deserialize, Serialize, MallocSizeOf) &gt;+)] &gt; pub struct ViewportConstraints { &gt; /// Width and height: &gt; /// * https://drafts.csswg.org/css-device-adapt/#width-desc &gt; /// * https://drafts.csswg.org/css-device-adapt/#height-desc &gt; pub size: TypedSize2D&lt;f32, CSSPixel&gt;, &gt; /// &lt;https://drafts.csswg.org/css-device-adapt/#zoom-desc&gt; &gt; pub initial_zoom: PinchZoomFactor, &gt; /// &lt;https://drafts.csswg.org/css-device-adapt/#min-max-width-desc&gt; &gt; pub min_zoom: Option&lt;PinchZoomFactor&gt;, &gt; /// &lt;https://drafts.csswg.org/css-device-adapt/#min-max-width-desc&gt; &gt; pub max_zoom: Option&lt;PinchZoomFactor&gt;, &gt; /// &lt;https://drafts.csswg.org/css-device-adapt/#user-zoom-desc&gt; &gt; pub user_zoom: UserZoom, &gt; /// &lt;https://drafts.csswg.org/css-device-adapt/#orientation-desc&gt; &gt;- pub orientation: Orientation &gt;+ pub orientation: Orientation, &gt; } &gt; &gt; impl ToCss for ViewportConstraints { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt; where &gt; W: Write, &gt; { &gt; dest.write_str("@viewport { width: ")?; &gt;@@ -88,17 +91,18 @@ pub enum Zoom { &gt; /// A percentage value. &gt; Percentage(f32), &gt; /// The `auto` keyword. &gt; Auto, &gt; } &gt; &gt; impl ToCss for Zoom { &gt; fn to_css&lt;W&gt;(&amp;self, dest: &amp;mut CssWriter&lt;W&gt;) -&gt; fmt::Result &gt;- where W: fmt::Write, &gt;+ where &gt;+ W: fmt::Write, &gt; { &gt; match *self { &gt; Zoom::Number(number) =&gt; number.to_css(dest), &gt; Zoom::Auto =&gt; dest.write_str("auto"), &gt; Zoom::Percentage(percentage) =&gt; { &gt; (percentage * 100.).to_css(dest)?; &gt; dest.write_char('%') &gt; } &gt;@@ -106,42 +110,42 @@ impl ToCss for Zoom { &gt; } &gt; } &gt; &gt; impl Zoom { &gt; /// Parse a zoom value per: &gt; /// &gt; /// &lt;https://drafts.csswg.org/css-device-adapt/#descdef-viewport-zoom&gt; &gt; pub fn parse&lt;'i, 't&gt;(input: &amp;mut Parser&lt;'i, 't&gt;) -&gt; Result&lt;Zoom, ParseError&lt;'i&gt;&gt; { &gt;- use ParsingMode; &gt; use cssparser::Token; &gt; use values::specified::AllowedNumericType::NonNegative; &gt;+ use ParsingMode; &gt; &gt; let location = input.current_source_location(); &gt; match *input.next()? { &gt; // TODO: This parse() method should take ParserContext as an &gt; // argument, and pass ParsingMode owned by the ParserContext to &gt; // is_ok() instead of using ParsingMode::DEFAULT directly. &gt; // In order to do so, we might want to move these stuff into style::stylesheets::viewport_rule. &gt;- Token::Percentage { unit_value, .. } if NonNegative.is_ok(ParsingMode::DEFAULT, unit_value) =&gt; { &gt;+ Token::Percentage { unit_value, .. } &gt;+ if NonNegative.is_ok(ParsingMode::DEFAULT, unit_value) =&gt; &gt;+ { &gt; Ok(Zoom::Percentage(unit_value)) &gt; } &gt; Token::Number { value, .. } if NonNegative.is_ok(ParsingMode::DEFAULT, value) =&gt; { &gt; Ok(Zoom::Number(value)) &gt; } &gt;- Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") =&gt; { &gt;- Ok(Zoom::Auto) &gt;- } &gt;- ref t =&gt; Err(location.new_unexpected_token_error(t.clone())) &gt;+ Token::Ident(ref value) if value.eq_ignore_ascii_case("auto") =&gt; Ok(Zoom::Auto), &gt;+ ref t =&gt; Err(location.new_unexpected_token_error(t.clone())), &gt; } &gt; } &gt; &gt; /// Get this zoom value as a float value. Returns `None` if the value is the &gt; /// `auto` keyword. &gt; #[inline] &gt; pub fn to_f32(&amp;self) -&gt; Option&lt;f32&gt; { &gt; match *self { &gt; Zoom::Number(number) =&gt; Some(number as f32), &gt; Zoom::Percentage(percentage) =&gt; Some(percentage as f32), &gt;- Zoom::Auto =&gt; None &gt;+ Zoom::Auto =&gt; None, &gt; } &gt; } &gt; } &gt;diff --git a/testing/geckodriver/build.rs b/testing/geckodriver/build.rs &gt;index 667e4559451e..82bc64df1dc1 100644 &gt;--- a/testing/geckodriver/build.rs &gt;+++ b/testing/geckodriver/build.rs &gt;@@ -3,17 +3,16 @@ &gt; /// &gt; /// ```no_run &gt; /// const COMMIT_HASH: Option&lt;&amp;'static str&gt; = Some("c31a366"); &gt; /// const COMMIT_DATE: Option&lt;&amp;'static str&gt; = Some("1988-05-10"); &gt; /// ``` &gt; /// &gt; /// The values are `None` if running hg failed, e.g. if it is not installed or &gt; /// if we are not in an hg repo. &gt;- &gt; use std::env; &gt; use std::ffi::OsStr; &gt; use std::fs::File; &gt; use std::io::Write; &gt; use std::path::PathBuf; &gt; use std::process::Command; &gt; &gt; fn main() { &gt;@@ -27,21 +26,18 @@ fn main() { &gt; writeln!( &gt; fh, &gt; "const COMMIT_DATE: Option&lt;&amp;'static str&gt; = {:?};", &gt; commit_date() &gt; ).unwrap(); &gt; } &gt; &gt; fn commit_hash() -&gt; Option&lt;String&gt; { &gt;- exec(&amp;"hg", &amp;["log", "-r.", "-T{node|short}"]).or_else( &gt;- || { &gt;- exec(&amp;"git", &amp;["rev-parse", "HEAD"]).and_then(hg2git_sha) &gt;- }, &gt;- ) &gt;+ exec(&amp;"hg", &amp;["log", "-r.", "-T{node|short}"]) &gt;+ .or_else(|| exec(&amp;"git", &amp;["rev-parse", "HEAD"]).and_then(hg2git_sha)) &gt; } &gt; &gt; fn commit_date() -&gt; Option&lt;String&gt; { &gt; exec(&amp;"hg", &amp;["log", "-r.", "-T{date|isodate}"]).or_else(|| { &gt; exec( &gt; &amp;"git", &gt; &amp;["log", "-1", "--date=short", "--pretty=format:%cd"], &gt; ) &gt;@@ -54,20 +50,21 @@ where &gt; I: IntoIterator&lt;Item = S&gt;, &gt; { &gt; let mut cmd = Command::new(program); &gt; for arg in args { &gt; cmd.arg(arg.as_ref()); &gt; } &gt; cmd.output() &gt; .ok() &gt;- .and_then(|r| if r.status.success() { &gt;- Some(r.stdout) &gt;- } else { &gt;- None &gt;- }) &gt;- .and_then(|o| String::from_utf8(o).ok()) &gt;+ .and_then(|r| { &gt;+ if r.status.success() { &gt;+ Some(r.stdout) &gt;+ } else { &gt;+ None &gt;+ } &gt;+ }).and_then(|o| String::from_utf8(o).ok()) &gt; .map(|s| s.trim_right().into()) &gt; } &gt; &gt; fn hg2git_sha(hg_sha: String) -&gt; Option&lt;String&gt; { &gt; exec(&amp;"git", &amp;["cinnabar", "git2hg", &amp;hg_sha]) &gt; } &gt;diff --git a/testing/geckodriver/src/build.rs b/testing/geckodriver/src/build.rs &gt;index 3cefa4b770ca..2ece9258729b 100644 &gt;--- a/testing/geckodriver/src/build.rs &gt;+++ b/testing/geckodriver/src/build.rs &gt;@@ -1,11 +1,11 @@ &gt; use std::fmt; &gt; &gt;-use rustc_serialize::json::{Json}; &gt;+use rustc_serialize::json::Json; &gt; &gt; include!(concat!(env!("OUT_DIR"), "/build-info.rs")); &gt; &gt; pub struct BuildInfo; &gt; &gt; impl BuildInfo { &gt; pub fn version() -&gt; &amp;'static str { &gt; crate_version!() &gt;diff --git a/testing/geckodriver/src/capabilities.rs b/testing/geckodriver/src/capabilities.rs &gt;index 0c4cd7314b6c..75954d4f3569 100644 &gt;--- a/testing/geckodriver/src/capabilities.rs &gt;+++ b/testing/geckodriver/src/capabilities.rs &gt;@@ -6,19 +6,19 @@ use mozrunner::runner::platform::firefox_default_path; &gt; use mozversion::{self, firefox_version, Version}; &gt; use regex::bytes::Regex; &gt; use rustc_serialize::base64::FromBase64; &gt; use rustc_serialize::json::Json; &gt; use std::collections::BTreeMap; &gt; use std::default::Default; &gt; use std::error::Error; &gt; use std::fs; &gt;+use std::io; &gt; use std::io::BufWriter; &gt; use std::io::Cursor; &gt;-use std::io; &gt; use std::path::{Path, PathBuf}; &gt; use std::process::{Command, Stdio}; &gt; use std::str::{self, FromStr}; &gt; use webdriver::capabilities::{BrowserCapabilities, Capabilities}; &gt; use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult}; &gt; use zip; &gt; &gt; /// Provides matching of `moz:firefoxOptions` and resolution of which Firefox &gt;@@ -29,17 +29,16 @@ use zip; &gt; /// system Firefox installation or an override, for example given to the &gt; /// `--binary` flag of geckodriver. &gt; pub struct FirefoxCapabilities&lt;'a&gt; { &gt; pub chosen_binary: Option&lt;PathBuf&gt;, &gt; fallback_binary: Option&lt;&amp;'a PathBuf&gt;, &gt; version_cache: BTreeMap&lt;PathBuf, String&gt;, &gt; } &gt; &gt;- &gt; impl&lt;'a&gt; FirefoxCapabilities&lt;'a&gt; { &gt; pub fn new(fallback_binary: Option&lt;&amp;'a PathBuf&gt;) -&gt; FirefoxCapabilities&lt;'a&gt; { &gt; FirefoxCapabilities { &gt; chosen_binary: None, &gt; fallback_binary: fallback_binary, &gt; version_cache: BTreeMap::new(), &gt; } &gt; } &gt;@@ -64,52 +63,54 @@ impl&lt;'a&gt; FirefoxCapabilities&lt;'a&gt; { &gt; .ok() &gt; .and_then(|x| x.version_string) &gt; .or_else(|| { &gt; debug!("Trying to read firefox version from binary"); &gt; self.version_from_binary(binary) &gt; }); &gt; if let Some(ref version) = rv { &gt; debug!("Found version {}", version); &gt;- self.version_cache &gt;- .insert(binary.clone(), version.clone()); &gt;+ self.version_cache.insert(binary.clone(), version.clone()); &gt; } else { &gt; debug!("Failed to get binary version"); &gt; } &gt; rv &gt; } else { &gt; None &gt; } &gt; } &gt; &gt; fn version_from_binary(&amp;self, binary: &amp;PathBuf) -&gt; Option&lt;String&gt; { &gt;- let version_regexp = Regex::new(r#"\d+\.\d+(?:[a-z]\d+)?"#).expect("Error parsing version regexp"); &gt;+ let version_regexp = &gt;+ Regex::new(r#"\d+\.\d+(?:[a-z]\d+)?"#).expect("Error parsing version regexp"); &gt; let output = Command::new(binary) &gt; .args(&amp;["-version"]) &gt; .stdout(Stdio::piped()) &gt; .spawn() &gt; .and_then(|child| child.wait_with_output()) &gt; .ok(); &gt; &gt; if let Some(x) = output { &gt;- version_regexp.captures(&amp;*x.stdout) &gt;+ version_regexp &gt;+ .captures(&amp;*x.stdout) &gt; .and_then(|captures| captures.get(0)) &gt; .and_then(|m| str::from_utf8(m.as_bytes()).ok()) &gt; .map(|x| x.into()) &gt; } else { &gt; None &gt; } &gt; } &gt; } &gt; &gt; // TODO: put this in webdriver-rust &gt; fn convert_version_error(err: mozversion::Error) -&gt; WebDriverError { &gt; WebDriverError::new( &gt; ErrorStatus::SessionNotCreated, &gt;- err.description().to_string()) &gt;+ err.description().to_string(), &gt;+ ) &gt; } &gt; &gt; impl&lt;'a&gt; BrowserCapabilities for FirefoxCapabilities&lt;'a&gt; { &gt; fn init(&amp;mut self, capabilities: &amp;Capabilities) { &gt; self.set_binary(capabilities); &gt; } &gt; &gt; fn browser_name(&amp;mut self, _: &amp;Capabilities) -&gt; WebDriverResult&lt;Option&lt;String&gt;&gt; { &gt;@@ -117,18 +118,18 @@ impl&lt;'a&gt; BrowserCapabilities for FirefoxCapabilities&lt;'a&gt; { &gt; } &gt; &gt; fn browser_version(&amp;mut self, _: &amp;Capabilities) -&gt; WebDriverResult&lt;Option&lt;String&gt;&gt; { &gt; Ok(self.version()) &gt; } &gt; &gt; fn platform_name(&amp;mut self, _: &amp;Capabilities) -&gt; WebDriverResult&lt;Option&lt;String&gt;&gt; { &gt; Ok(if cfg!(target_os = "windows") { &gt;- Some("windows".into()) &gt;- } else if cfg!(target_os = "macos") { &gt;+ Some("windows".into()) &gt;+ } else if cfg!(target_os = "macos") { &gt; Some("mac".into()) &gt; } else if cfg!(target_os = "linux") { &gt; Some("linux".into()) &gt; } else { &gt; None &gt; }) &gt; } &gt; &gt;@@ -140,120 +141,149 @@ impl&lt;'a&gt; BrowserCapabilities for FirefoxCapabilities&lt;'a&gt; { &gt; Ok(false) &gt; } &gt; } &gt; &gt; fn set_window_rect(&amp;mut self, _: &amp;Capabilities) -&gt; WebDriverResult&lt;bool&gt; { &gt; Ok(true) &gt; } &gt; &gt;- fn compare_browser_version(&amp;mut self, &gt;- version: &amp;str, &gt;- comparison: &amp;str) &gt;- -&gt; WebDriverResult&lt;bool&gt; { &gt;+ fn compare_browser_version( &gt;+ &amp;mut self, &gt;+ version: &amp;str, &gt;+ comparison: &amp;str, &gt;+ ) -&gt; WebDriverResult&lt;bool&gt; { &gt; try!(Version::from_str(version).or_else(|x| Err(convert_version_error(x)))) &gt; .matches(comparison) &gt; .or_else(|x| Err(convert_version_error(x))) &gt; } &gt; &gt; fn accept_proxy(&amp;mut self, _: &amp;Capabilities, _: &amp;Capabilities) -&gt; WebDriverResult&lt;bool&gt; { &gt; Ok(true) &gt; } &gt; &gt;- fn validate_custom(&amp;self, name: &amp;str, value: &amp;Json) -&gt; WebDriverResult&lt;()&gt; { &gt;+ fn validate_custom(&amp;self, name: &amp;str, value: &amp;Json) -&gt; WebDriverResult&lt;()&gt; { &gt; if !name.starts_with("moz:") { &gt;- return Ok(()) &gt;+ return Ok(()); &gt; } &gt; match name { &gt; "moz:firefoxOptions" =&gt; { &gt;- let data = try_opt!(value.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "moz:firefoxOptions is not an object"); &gt;+ let data = try_opt!( &gt;+ value.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "moz:firefoxOptions is not an object" &gt;+ ); &gt; for (key, value) in data.iter() { &gt; match &amp;**key { &gt; "binary" =&gt; { &gt; if !value.is_string() { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- "binary path is not a string")); &gt;+ "binary path is not a string", &gt;+ )); &gt; } &gt;- }, &gt;+ } &gt; "args" =&gt; { &gt;- if !try_opt!(value.as_array(), &gt;- ErrorStatus::InvalidArgument, &gt;- "args is not an array") &gt;- .iter() &gt;- .all(|value| value.is_string()) { &gt;+ if !try_opt!( &gt;+ value.as_array(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "args is not an array" &gt;+ ).iter() &gt;+ .all(|value| value.is_string()) &gt;+ { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- "args entry is not a string")); &gt;- } &gt;- }, &gt;+ "args entry is not a string", &gt;+ )); &gt;+ } &gt;+ } &gt; "profile" =&gt; { &gt; if !value.is_string() { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- "profile is not a string")); &gt;+ "profile is not a string", &gt;+ )); &gt; } &gt;- }, &gt;+ } &gt; "log" =&gt; { &gt;- let log_data = try_opt!(value.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "log value is not an object"); &gt;+ let log_data = try_opt!( &gt;+ value.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "log value is not an object" &gt;+ ); &gt; for (log_key, log_value) in log_data.iter() { &gt; match &amp;**log_key { &gt; "level" =&gt; { &gt;- let level = try_opt!(log_value.as_string(), &gt;- ErrorStatus::InvalidArgument, &gt;- "log level is not a string"); &gt;+ let level = try_opt!( &gt;+ log_value.as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "log level is not a string" &gt;+ ); &gt; if Level::from_str(level).is_err() { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- format!("Not a valid log level: {}", level))) &gt;+ format!("Not a valid log level: {}", level), &gt;+ )); &gt; } &gt; } &gt;- x =&gt; return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- format!("Invalid log field {}", x))) &gt;+ x =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("Invalid log field {}", x), &gt;+ )) &gt;+ } &gt; } &gt; } &gt;- }, &gt;+ } &gt; "prefs" =&gt; { &gt;- let prefs_data = try_opt!(value.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "prefs value is not an object"); &gt;- if !prefs_data.values() &gt;- .all(|x| x.is_string() || x.is_i64() || x.is_u64() || x.is_boolean()) { &gt;- return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- "Preference values not all string or integer or boolean")); &gt;- } &gt;+ let prefs_data = try_opt!( &gt;+ value.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "prefs value is not an object" &gt;+ ); &gt;+ if !prefs_data.values().all(|x| { &gt;+ x.is_string() || x.is_i64() || x.is_u64() || x.is_boolean() &gt;+ }) { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Preference values not all string or integer or boolean", &gt;+ )); &gt;+ } &gt;+ } &gt;+ x =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("Invalid moz:firefoxOptions field {}", x), &gt;+ )) &gt; } &gt;- x =&gt; return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- format!("Invalid moz:firefoxOptions field {}", x))) &gt; } &gt; } &gt; } &gt; "moz:useNonSpecCompliantPointerOrigin" =&gt; { &gt; if !value.is_boolean() { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- "moz:useNonSpecCompliantPointerOrigin is not a boolean")); &gt;+ "moz:useNonSpecCompliantPointerOrigin is not a boolean", &gt;+ )); &gt; } &gt; } &gt; "moz:webdriverClick" =&gt; { &gt; if !value.is_boolean() { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- "moz:webdriverClick is not a boolean")); &gt;+ "moz:webdriverClick is not a boolean", &gt;+ )); &gt; } &gt; } &gt;- _ =&gt; return Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- format!("Unrecognised option {}", name))) &gt;+ _ =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("Unrecognised option {}", name), &gt;+ )) &gt;+ } &gt; } &gt; Ok(()) &gt; } &gt; &gt; fn accept_custom(&amp;mut self, _: &amp;str, _: &amp;Json, _: &amp;Capabilities) -&gt; WebDriverResult&lt;bool&gt; { &gt; Ok(true) &gt; } &gt; } &gt;@@ -273,75 +303,82 @@ pub struct FirefoxOptions { &gt; pub prefs: Vec&lt;(String, Pref)&gt;, &gt; } &gt; &gt; impl FirefoxOptions { &gt; pub fn new() -&gt; FirefoxOptions { &gt; Default::default() &gt; } &gt; &gt;- pub fn from_capabilities(binary_path: Option&lt;PathBuf&gt;, &gt;- matched: &amp;mut Capabilities) &gt;- -&gt; WebDriverResult&lt;FirefoxOptions&gt; { &gt;+ pub fn from_capabilities( &gt;+ binary_path: Option&lt;PathBuf&gt;, &gt;+ matched: &amp;mut Capabilities, &gt;+ ) -&gt; WebDriverResult&lt;FirefoxOptions&gt; { &gt; let mut rv = FirefoxOptions::new(); &gt; rv.binary = binary_path; &gt; &gt; if let Some(json) = matched.remove("moz:firefoxOptions") { &gt;- let options = try!(json.as_object() &gt;- .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "'moz:firefoxOptions' \ &gt;- capability is not an object"))); &gt;+ let options = try!(json.as_object().ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "'moz:firefoxOptions' \ &gt;+ capability is not an object" &gt;+ ))); &gt; &gt; rv.profile = try!(FirefoxOptions::load_profile(&amp;options)); &gt; rv.args = try!(FirefoxOptions::load_args(&amp;options)); &gt; rv.log = try!(FirefoxOptions::load_log(&amp;options)); &gt; rv.prefs = try!(FirefoxOptions::load_prefs(&amp;options)); &gt; } &gt; &gt; Ok(rv) &gt; } &gt; &gt; fn load_profile(options: &amp;Capabilities) -&gt; WebDriverResult&lt;Option&lt;Profile&gt;&gt; { &gt; if let Some(profile_json) = options.get("profile") { &gt;- let profile_base64 = &gt;- try!(profile_json &gt;- .as_string() &gt;- .ok_or(WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Profile is not a string"))); &gt;+ let profile_base64 = try!(profile_json.as_string().ok_or(WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Profile is not a string" &gt;+ ))); &gt; let profile_zip = &amp;*try!(profile_base64.from_base64()); &gt; &gt; // Create an emtpy profile directory &gt; let profile = try!(Profile::new(None)); &gt;- try!(unzip_buffer(profile_zip, &gt;- profile &gt;- .temp_dir &gt;- .as_ref() &gt;- .expect("Profile doesn't have a path") &gt;- .path())); &gt;+ try!(unzip_buffer( &gt;+ profile_zip, &gt;+ profile &gt;+ .temp_dir &gt;+ .as_ref() &gt;+ .expect("Profile doesn't have a path") &gt;+ .path() &gt;+ )); &gt; &gt; Ok(Some(profile)) &gt; } else { &gt; Ok(None) &gt; } &gt; } &gt; &gt; fn load_args(options: &amp;Capabilities) -&gt; WebDriverResult&lt;Option&lt;Vec&lt;String&gt;&gt;&gt; { &gt; if let Some(args_json) = options.get("args") { &gt;- let args_array = try!(args_json &gt;- .as_array() &gt;- .ok_or(WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Arguments were not an \ &gt;- array"))); &gt;- let args = try!(args_array &gt;- .iter() &gt;- .map(|x| x.as_string().map(|x| x.to_owned())) &gt;- .collect::&lt;Option&lt;Vec&lt;String&gt;&gt;&gt;() &gt;- .ok_or(WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Arguments entries were not all \ &gt;- strings"))); &gt;+ let args_array = try!(args_json.as_array().ok_or(WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Arguments were not an \ &gt;+ array" &gt;+ ))); &gt;+ let args = try!( &gt;+ args_array &gt;+ .iter() &gt;+ .map(|x| x.as_string().map(|x| x.to_owned())) &gt;+ .collect::&lt;Option&lt;Vec&lt;String&gt;&gt;&gt;() &gt;+ .ok_or(WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Arguments entries were not all \ &gt;+ strings" &gt;+ )) &gt;+ ); &gt; Ok(Some(args)) &gt; } else { &gt; Ok(None) &gt; } &gt; } &gt; &gt; fn load_log(options: &amp;Capabilities) -&gt; WebDriverResult&lt;LogOptions&gt; { &gt; if let Some(json) = options.get("log") { &gt;@@ -367,20 +404,20 @@ impl FirefoxOptions { &gt; Ok(LogOptions { level }) &gt; } else { &gt; Ok(Default::default()) &gt; } &gt; } &gt; &gt; pub fn load_prefs(options: &amp;Capabilities) -&gt; WebDriverResult&lt;Vec&lt;(String, Pref)&gt;&gt; { &gt; if let Some(prefs_data) = options.get("prefs") { &gt;- let prefs = try!(prefs_data &gt;- .as_object() &gt;- .ok_or(WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Prefs were not an object"))); &gt;+ let prefs = try!(prefs_data.as_object().ok_or(WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Prefs were not an object" &gt;+ ))); &gt; let mut rv = Vec::with_capacity(prefs.len()); &gt; for (key, value) in prefs.iter() { &gt; rv.push((key.clone(), try!(pref_from_json(value)))); &gt; } &gt; Ok(rv) &gt; } else { &gt; Ok(vec![]) &gt; } &gt;@@ -388,31 +425,35 @@ impl FirefoxOptions { &gt; } &gt; &gt; fn pref_from_json(value: &amp;Json) -&gt; WebDriverResult&lt;Pref&gt; { &gt; match value { &gt; &amp;Json::String(ref x) =&gt; Ok(Pref::new(x.clone())), &gt; &amp;Json::I64(x) =&gt; Ok(Pref::new(x)), &gt; &amp;Json::U64(x) =&gt; Ok(Pref::new(x as i64)), &gt; &amp;Json::Boolean(x) =&gt; Ok(Pref::new(x)), &gt;- _ =&gt; Err(WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Could not convert pref value to string, boolean, or integer")) &gt;+ _ =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Could not convert pref value to string, boolean, or integer", &gt;+ )), &gt; } &gt; } &gt; &gt; fn unzip_buffer(buf: &amp;[u8], dest_dir: &amp;Path) -&gt; WebDriverResult&lt;()&gt; { &gt; let reader = Cursor::new(buf); &gt;- let mut zip = try!(zip::ZipArchive::new(reader).map_err(|_| { &gt;- WebDriverError::new(ErrorStatus::UnknownError, "Failed to unzip profile") &gt;- })); &gt;+ let mut zip = try!( &gt;+ zip::ZipArchive::new(reader) &gt;+ .map_err(|_| WebDriverError::new(ErrorStatus::UnknownError, "Failed to unzip profile")) &gt;+ ); &gt; &gt; for i in 0..zip.len() { &gt;- let mut file = try!(zip.by_index(i).map_err(|_| { &gt;- WebDriverError::new(ErrorStatus::UnknownError, "Processing profile zip file failed") &gt;- })); &gt;+ let mut file = try!(zip.by_index(i).map_err(|_| WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Processing profile zip file failed" &gt;+ ))); &gt; let unzip_path = { &gt; let name = file.name(); &gt; let is_dir = name.ends_with("/"); &gt; let rel_path = Path::new(name); &gt; let dest_path = dest_dir.join(rel_path); &gt; &gt; { &gt; let create_dir = if is_dir { &gt;@@ -492,18 +533,20 @@ mod tests { &gt; firefox_opts.insert("profile".into(), encoded_profile); &gt; &gt; let opts = make_options(firefox_opts); &gt; let mut profile = opts.profile.unwrap(); &gt; let prefs = profile.user_prefs().unwrap(); &gt; &gt; println!("{:#?}", prefs.prefs); &gt; &gt;- assert_eq!(prefs.get("startup.homepage_welcome_url"), &gt;- Some(&amp;Pref::new("data:text/html,PASS"))); &gt;+ assert_eq!( &gt;+ prefs.get("startup.homepage_welcome_url"), &gt;+ Some(&amp;Pref::new("data:text/html,PASS")) &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn test_prefs() { &gt; let encoded_profile = example_profile(); &gt; let mut prefs: BTreeMap&lt;String, Json&gt; = BTreeMap::new(); &gt; prefs.insert( &gt; "browser.display.background_color".into(), &gt;diff --git a/testing/geckodriver/src/logging.rs b/testing/geckodriver/src/logging.rs &gt;index 4a4faa86923c..a8bda4da5c43 100644 &gt;--- a/testing/geckodriver/src/logging.rs &gt;+++ b/testing/geckodriver/src/logging.rs &gt;@@ -274,17 +274,20 @@ mod tests { &gt; (Level::Warn, "Warn"), &gt; (Level::Info, "Info"), &gt; (Level::Config, "Config"), &gt; (Level::Debug, "Debug"), &gt; (Level::Trace, "Trace"), &gt; ]; &gt; &gt; for &amp;(lvl, s) in tests.iter() { &gt;- let expected = Pref { value: PrefValue::String(s.to_string()), sticky: false }; &gt;+ let expected = Pref { &gt;+ value: PrefValue::String(s.to_string()), &gt;+ sticky: false, &gt;+ }; &gt; assert_eq!(Into::&lt;Pref&gt;::into(lvl), expected); &gt; } &gt; } &gt; &gt; #[test] &gt; fn test_level_from_str() { &gt; assert_eq!(Level::from_str("fatal"), Ok(Level::Fatal)); &gt; assert_eq!(Level::from_str("error"), Ok(Level::Error)); &gt;diff --git a/testing/geckodriver/src/main.rs b/testing/geckodriver/src/main.rs &gt;index 934855cc55ae..55aac7ec7819 100644 &gt;--- a/testing/geckodriver/src/main.rs &gt;+++ b/testing/geckodriver/src/main.rs &gt;@@ -5,46 +5,46 @@ extern crate clap; &gt; extern crate lazy_static; &gt; extern crate hyper; &gt; extern crate mozprofile; &gt; extern crate mozrunner; &gt; extern crate mozversion; &gt; extern crate regex; &gt; extern crate rustc_serialize; &gt; extern crate uuid; &gt;-extern crate zip; &gt; extern crate webdriver; &gt;+extern crate zip; &gt; &gt; #[macro_use] &gt; extern crate log; &gt; &gt; use std::io::Write; &gt; use std::net::{IpAddr, SocketAddr}; &gt; use std::path::PathBuf; &gt; use std::str::FromStr; &gt; &gt; use clap::{App, Arg}; &gt; &gt; macro_rules! try_opt { &gt;- ($expr:expr, $err_type:expr, $err_msg:expr) =&gt; ({ &gt;+ ($expr:expr, $err_type:expr, $err_msg:expr) =&gt; {{ &gt; match $expr { &gt; Some(x) =&gt; x, &gt;- None =&gt; return Err(WebDriverError::new($err_type, $err_msg)) &gt;+ None =&gt; return Err(WebDriverError::new($err_type, $err_msg)), &gt; } &gt;- }) &gt;+ }}; &gt; } &gt; &gt; mod build; &gt;+mod capabilities; &gt; mod logging; &gt;-mod prefs; &gt; mod marionette; &gt;-mod capabilities; &gt;+mod prefs; &gt; &gt; use build::BuildInfo; &gt;-use marionette::{MarionetteHandler, MarionetteSettings, extension_routes}; &gt;+use marionette::{extension_routes, MarionetteHandler, MarionetteSettings}; &gt; &gt; type ProgramResult = std::result::Result&lt;(), (ExitCode, String)&gt;; &gt; &gt; enum ExitCode { &gt; Ok = 0, &gt; Usage = 64, &gt; Unavailable = 69, &gt; } &gt;@@ -57,62 +57,72 @@ fn print_version() { &gt; println!(""); &gt; println!("This program is subject to the terms of the Mozilla Public License 2.0."); &gt; println!("You can obtain a copy of the license at https://mozilla.org/MPL/2.0/."); &gt; } &gt; &gt; fn app&lt;'a, 'b&gt;() -&gt; App&lt;'a, 'b&gt; { &gt; App::new(format!("geckodriver {}", crate_version!())) &gt; .about("WebDriver implementation for Firefox.") &gt;- .arg(Arg::with_name("webdriver_host") &gt;- .long("host") &gt;- .value_name("HOST") &gt;- .help("Host ip to use for WebDriver server (default: 127.0.0.1)") &gt;- .takes_value(true)) &gt;- .arg(Arg::with_name("webdriver_port") &gt;- .short("p") &gt;- .long("port") &gt;- .value_name("PORT") &gt;- .help("Port to use for WebDriver server (default: 4444)") &gt;- .takes_value(true) &gt;- .alias("webdriver-port")) &gt;- .arg(Arg::with_name("binary") &gt;- .short("b") &gt;- .long("binary") &gt;- .value_name("BINARY") &gt;- .help("Path to the Firefox binary") &gt;- .takes_value(true)) &gt;- .arg(Arg::with_name("marionette_port") &gt;- .long("marionette-port") &gt;- .value_name("PORT") &gt;- .help("Port to use to connect to Gecko (default: random free port)") &gt;- .takes_value(true)) &gt;- .arg(Arg::with_name("connect_existing") &gt;- .long("connect-existing") &gt;- .requires("marionette_port") &gt;- .help("Connect to an existing Firefox instance")) &gt;- .arg(Arg::with_name("jsdebugger") &gt;- .long("jsdebugger") &gt;- .takes_value(false) &gt;- .help("Attach browser toolbox debugger for Firefox")) &gt;- .arg(Arg::with_name("verbosity") &gt;- .short("v") &gt;- .multiple(true) &gt;- .conflicts_with("log_level") &gt;- .help("Log level verbosity (-v for debug and -vv for trace level)")) &gt;- .arg(Arg::with_name("log_level") &gt;- .long("log") &gt;- .takes_value(true) &gt;- .value_name("LEVEL") &gt;- .possible_values(&amp;["fatal", "error", "warn", "info", "config", "debug", "trace"]) &gt;- .help("Set Gecko log level")) &gt;- .arg(Arg::with_name("version") &gt;- .short("V") &gt;- .long("version") &gt;- .help("Prints version and copying information")) &gt;+ .arg( &gt;+ Arg::with_name("webdriver_host") &gt;+ .long("host") &gt;+ .value_name("HOST") &gt;+ .help("Host ip to use for WebDriver server (default: 127.0.0.1)") &gt;+ .takes_value(true), &gt;+ ).arg( &gt;+ Arg::with_name("webdriver_port") &gt;+ .short("p") &gt;+ .long("port") &gt;+ .value_name("PORT") &gt;+ .help("Port to use for WebDriver server (default: 4444)") &gt;+ .takes_value(true) &gt;+ .alias("webdriver-port"), &gt;+ ).arg( &gt;+ Arg::with_name("binary") &gt;+ .short("b") &gt;+ .long("binary") &gt;+ .value_name("BINARY") &gt;+ .help("Path to the Firefox binary") &gt;+ .takes_value(true), &gt;+ ).arg( &gt;+ Arg::with_name("marionette_port") &gt;+ .long("marionette-port") &gt;+ .value_name("PORT") &gt;+ .help("Port to use to connect to Gecko (default: random free port)") &gt;+ .takes_value(true), &gt;+ ).arg( &gt;+ Arg::with_name("connect_existing") &gt;+ .long("connect-existing") &gt;+ .requires("marionette_port") &gt;+ .help("Connect to an existing Firefox instance"), &gt;+ ).arg( &gt;+ Arg::with_name("jsdebugger") &gt;+ .long("jsdebugger") &gt;+ .takes_value(false) &gt;+ .help("Attach browser toolbox debugger for Firefox"), &gt;+ ).arg( &gt;+ Arg::with_name("verbosity") &gt;+ .short("v") &gt;+ .multiple(true) &gt;+ .conflicts_with("log_level") &gt;+ .help("Log level verbosity (-v for debug and -vv for trace level)"), &gt;+ ).arg( &gt;+ Arg::with_name("log_level") &gt;+ .long("log") &gt;+ .takes_value(true) &gt;+ .value_name("LEVEL") &gt;+ .possible_values(&amp;["fatal", "error", "warn", "info", "config", "debug", "trace"]) &gt;+ .help("Set Gecko log level"), &gt;+ ).arg( &gt;+ Arg::with_name("version") &gt;+ .short("V") &gt;+ .long("version") &gt;+ .help("Prints version and copying information"), &gt;+ ) &gt; } &gt; &gt; fn run() -&gt; ProgramResult { &gt; let matches = app().get_matches(); &gt; &gt; if matches.is_present("version") { &gt; print_version(); &gt; return Ok(()); &gt;@@ -131,22 +141,20 @@ fn run() -&gt; ProgramResult { &gt; let addr = match IpAddr::from_str(host) { &gt; Ok(addr) =&gt; SocketAddr::new(addr, port), &gt; Err(_) =&gt; return Err((ExitCode::Usage, "invalid host address".into())), &gt; }; &gt; &gt; let binary = matches.value_of("binary").map(|x| PathBuf::from(x)); &gt; &gt; let marionette_port = match matches.value_of("marionette_port") { &gt;- Some(x) =&gt; { &gt;- match u16::from_str(x) { &gt;- Ok(x) =&gt; Some(x), &gt;- Err(_) =&gt; return Err((ExitCode::Usage, "invalid Marionette port".into())), &gt;- } &gt;- } &gt;+ Some(x) =&gt; match u16::from_str(x) { &gt;+ Ok(x) =&gt; Some(x), &gt;+ Err(_) =&gt; return Err((ExitCode::Usage, "invalid Marionette port".into())), &gt;+ }, &gt; None =&gt; None, &gt; }; &gt; &gt; let log_level = if matches.is_present("log_level") { &gt; logging::Level::from_str(matches.value_of("log_level").unwrap()).ok() &gt; } else { &gt; match matches.occurrences_of("verbosity") { &gt; 0 =&gt; Some(logging::Level::Info), &gt;diff --git a/testing/geckodriver/src/marionette.rs b/testing/geckodriver/src/marionette.rs &gt;index 695ca34df5de..0bd29ce217e2 100644 &gt;--- a/testing/geckodriver/src/marionette.rs &gt;+++ b/testing/geckodriver/src/marionette.rs &gt;@@ -1,123 +1,148 @@ &gt; use hyper::method::Method; &gt; use mozprofile::preferences::Pref; &gt; use mozprofile::profile::Profile; &gt;-use mozrunner::runner::{FirefoxRunner, FirefoxProcess, Runner, RunnerProcess}; &gt;+use mozrunner::runner::{FirefoxProcess, FirefoxRunner, Runner, RunnerProcess}; &gt; use regex::Captures; &gt; use rustc_serialize::base64::FromBase64; &gt; use rustc_serialize::json; &gt; use rustc_serialize::json::{Json, ToJson}; &gt; use std::collections::BTreeMap; &gt; use std::env; &gt; use std::error::Error; &gt; use std::fs::File; &gt;+use std::io::prelude::*; &gt; use std::io::Error as IoError; &gt; use std::io::ErrorKind; &gt;-use std::io::prelude::*; &gt;-use std::path::PathBuf; &gt; use std::io::Result as IoResult; &gt; use std::net::{TcpListener, TcpStream}; &gt;+use std::path::PathBuf; &gt; use std::sync::Mutex; &gt; use std::thread; &gt; use std::time; &gt; use uuid::Uuid; &gt; use webdriver::capabilities::CapabilitiesMatching; &gt;-use webdriver::command::{WebDriverCommand, WebDriverMessage, Parameters, &gt;- WebDriverExtensionCommand}; &gt; use webdriver::command::WebDriverCommand::{ &gt;- NewSession, DeleteSession, Status, Get, GetCurrentUrl, &gt;- GoBack, GoForward, Refresh, GetTitle, GetPageSource, GetWindowHandle, &gt;- GetWindowHandles, CloseWindow, SetWindowRect, GetWindowRect, &gt;- MinimizeWindow, MaximizeWindow, FullscreenWindow, SwitchToWindow, SwitchToFrame, &gt;- SwitchToParentFrame, FindElement, FindElements, &gt;- FindElementElement, FindElementElements, GetActiveElement, &gt;- IsDisplayed, IsSelected, GetElementAttribute, GetElementProperty, GetCSSValue, &gt;- GetElementText, GetElementTagName, GetElementRect, IsEnabled, &gt;- ElementClick, ElementTap, ElementClear, ElementSendKeys, &gt;- ExecuteScript, ExecuteAsyncScript, GetCookies, GetNamedCookie, AddCookie, &gt;- DeleteCookies, DeleteCookie, GetTimeouts, SetTimeouts, DismissAlert, &gt;- AcceptAlert, GetAlertText, SendAlertText, TakeScreenshot, TakeElementScreenshot, &gt;- Extension, PerformActions, ReleaseActions}; &gt;+ AcceptAlert, AddCookie, CloseWindow, DeleteCookie, DeleteCookies, DeleteSession, DismissAlert, &gt;+ ElementClear, ElementClick, ElementSendKeys, ElementTap, ExecuteAsyncScript, ExecuteScript, &gt;+ Extension, FindElement, FindElementElement, FindElementElements, FindElements, &gt;+ FullscreenWindow, Get, GetActiveElement, GetAlertText, GetCSSValue, GetCookies, GetCurrentUrl, &gt;+ GetElementAttribute, GetElementProperty, GetElementRect, GetElementTagName, GetElementText, &gt;+ GetNamedCookie, GetPageSource, GetTimeouts, GetTitle, GetWindowHandle, GetWindowHandles, &gt;+ GetWindowRect, GoBack, GoForward, IsDisplayed, IsEnabled, IsSelected, MaximizeWindow, &gt;+ MinimizeWindow, NewSession, PerformActions, Refresh, ReleaseActions, SendAlertText, &gt;+ SetTimeouts, SetWindowRect, Status, SwitchToFrame, SwitchToParentFrame, SwitchToWindow, &gt;+ TakeElementScreenshot, TakeScreenshot, &gt;+}; &gt; use webdriver::command::{ &gt;- NewSessionParameters, GetParameters, WindowRectParameters, SwitchToWindowParameters, &gt;- SwitchToFrameParameters, LocatorParameters, JavascriptCommandParameters, &gt;- GetNamedCookieParameters, AddCookieParameters, TimeoutsParameters, &gt;- ActionsParameters, TakeScreenshotParameters}; &gt;-use webdriver::response::{CloseWindowResponse, Cookie, CookieResponse, CookiesResponse, &gt;- ElementRectResponse, NewSessionResponse, TimeoutsResponse, &gt;- ValueResponse, WebDriverResponse, WindowRectResponse}; &gt;-use webdriver::common::{Date, ELEMENT_KEY, FrameId, FRAME_KEY, Nullable, WebElement, WINDOW_KEY}; &gt;+ ActionsParameters, AddCookieParameters, GetNamedCookieParameters, GetParameters, &gt;+ JavascriptCommandParameters, LocatorParameters, NewSessionParameters, SwitchToFrameParameters, &gt;+ SwitchToWindowParameters, TakeScreenshotParameters, TimeoutsParameters, WindowRectParameters, &gt;+}; &gt;+use webdriver::command::{ &gt;+ Parameters, WebDriverCommand, WebDriverExtensionCommand, WebDriverMessage, &gt;+}; &gt;+use webdriver::common::{Date, FrameId, Nullable, WebElement, ELEMENT_KEY, FRAME_KEY, WINDOW_KEY}; &gt; use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult}; &gt;-use webdriver::server::{WebDriverHandler, Session}; &gt;-use webdriver::httpapi::{WebDriverExtensionRoute}; &gt;+use webdriver::httpapi::WebDriverExtensionRoute; &gt;+use webdriver::response::{ &gt;+ CloseWindowResponse, Cookie, CookieResponse, CookiesResponse, ElementRectResponse, &gt;+ NewSessionResponse, TimeoutsResponse, ValueResponse, WebDriverResponse, WindowRectResponse, &gt;+}; &gt;+use webdriver::server::{Session, WebDriverHandler}; &gt; &gt; use build::BuildInfo; &gt; use capabilities::{FirefoxCapabilities, FirefoxOptions}; &gt; use logging; &gt; use prefs; &gt; &gt; // localhost may be routed to the IPv6 stack on certain systems, &gt; // and nsIServerSocket in Marionette only supports IPv4 &gt; const DEFAULT_HOST: &amp;'static str = "127.0.0.1"; &gt; &gt; const CHROME_ELEMENT_KEY: &amp;'static str = "chromeelement-9fc5-4b51-a3c8-01716eedeb04"; &gt; const LEGACY_ELEMENT_KEY: &amp;'static str = "ELEMENT"; &gt; &gt; pub fn extension_routes() -&gt; Vec&lt;(Method, &amp;'static str, GeckoExtensionRoute)&gt; { &gt;- return vec![(Method::Get, "/session/{sessionId}/moz/context", GeckoExtensionRoute::GetContext), &gt;- (Method::Post, "/session/{sessionId}/moz/context", GeckoExtensionRoute::SetContext), &gt;- (Method::Post, &gt;- "/session/{sessionId}/moz/xbl/{elementId}/anonymous_children", &gt;- GeckoExtensionRoute::XblAnonymousChildren), &gt;- (Method::Post, &gt;- "/session/{sessionId}/moz/xbl/{elementId}/anonymous_by_attribute", &gt;- GeckoExtensionRoute::XblAnonymousByAttribute), &gt;- (Method::Post, "/session/{sessionId}/moz/addon/install", &gt;- GeckoExtensionRoute::InstallAddon), &gt;- (Method::Post, "/session/{sessionId}/moz/addon/uninstall", &gt;- GeckoExtensionRoute::UninstallAddon)]; &gt;+ return vec![ &gt;+ ( &gt;+ Method::Get, &gt;+ "/session/{sessionId}/moz/context", &gt;+ GeckoExtensionRoute::GetContext, &gt;+ ), &gt;+ ( &gt;+ Method::Post, &gt;+ "/session/{sessionId}/moz/context", &gt;+ GeckoExtensionRoute::SetContext, &gt;+ ), &gt;+ ( &gt;+ Method::Post, &gt;+ "/session/{sessionId}/moz/xbl/{elementId}/anonymous_children", &gt;+ GeckoExtensionRoute::XblAnonymousChildren, &gt;+ ), &gt;+ ( &gt;+ Method::Post, &gt;+ "/session/{sessionId}/moz/xbl/{elementId}/anonymous_by_attribute", &gt;+ GeckoExtensionRoute::XblAnonymousByAttribute, &gt;+ ), &gt;+ ( &gt;+ Method::Post, &gt;+ "/session/{sessionId}/moz/addon/install", &gt;+ GeckoExtensionRoute::InstallAddon, &gt;+ ), &gt;+ ( &gt;+ Method::Post, &gt;+ "/session/{sessionId}/moz/addon/uninstall", &gt;+ GeckoExtensionRoute::UninstallAddon, &gt;+ ), &gt;+ ]; &gt; } &gt; &gt; #[derive(Clone, PartialEq)] &gt; pub enum GeckoExtensionRoute { &gt; GetContext, &gt; SetContext, &gt; XblAnonymousChildren, &gt; XblAnonymousByAttribute, &gt; InstallAddon, &gt; UninstallAddon, &gt; } &gt; &gt; impl WebDriverExtensionRoute for GeckoExtensionRoute { &gt; type Command = GeckoExtensionCommand; &gt; &gt;- fn command(&amp;self, &gt;- captures: &amp;Captures, &gt;- body_data: &amp;Json) &gt;- -&gt; WebDriverResult&lt;WebDriverCommand&lt;GeckoExtensionCommand&gt;&gt; { &gt;+ fn command( &gt;+ &amp;self, &gt;+ captures: &amp;Captures, &gt;+ body_data: &amp;Json, &gt;+ ) -&gt; WebDriverResult&lt;WebDriverCommand&lt;GeckoExtensionCommand&gt;&gt; { &gt; let command = match self { &gt; &amp;GeckoExtensionRoute::GetContext =&gt; GeckoExtensionCommand::GetContext, &gt; &amp;GeckoExtensionRoute::SetContext =&gt; { &gt; let parameters: GeckoContextParameters = try!(Parameters::from_json(&amp;body_data)); &gt; GeckoExtensionCommand::SetContext(parameters) &gt; } &gt; &amp;GeckoExtensionRoute::XblAnonymousChildren =&gt; { &gt;- let element_id = try!(captures.name("elementId") &gt;- .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"))); &gt;+ let element_id = try!(captures.name("elementId").ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ))); &gt; GeckoExtensionCommand::XblAnonymousChildren(element_id.as_str().into()) &gt; } &gt; &amp;GeckoExtensionRoute::XblAnonymousByAttribute =&gt; { &gt;- let element_id = try!(captures.name("elementId") &gt;- .ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"))); &gt;+ let element_id = try!(captures.name("elementId").ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ))); &gt; let parameters: AttributeParameters = try!(Parameters::from_json(&amp;body_data)); &gt;- GeckoExtensionCommand::XblAnonymousByAttribute(element_id.as_str().into(), &gt;- parameters) &gt;+ GeckoExtensionCommand::XblAnonymousByAttribute( &gt;+ element_id.as_str().into(), &gt;+ parameters, &gt;+ ) &gt; } &gt; &amp;GeckoExtensionRoute::InstallAddon =&gt; { &gt; let parameters: AddonInstallParameters = try!(Parameters::from_json(&amp;body_data)); &gt; GeckoExtensionCommand::InstallAddon(parameters) &gt; } &gt; &amp;GeckoExtensionRoute::UninstallAddon =&gt; { &gt; let parameters: AddonUninstallParameters = try!(Parameters::from_json(&amp;body_data)); &gt; GeckoExtensionCommand::UninstallAddon(parameters) &gt;@@ -129,17 +154,17 @@ impl WebDriverExtensionRoute for GeckoExtensionRoute { &gt; &gt; #[derive(Clone, PartialEq)] &gt; pub enum GeckoExtensionCommand { &gt; GetContext, &gt; SetContext(GeckoContextParameters), &gt; XblAnonymousChildren(WebElement), &gt; XblAnonymousByAttribute(WebElement, AttributeParameters), &gt; InstallAddon(AddonInstallParameters), &gt;- UninstallAddon(AddonUninstallParameters) &gt;+ UninstallAddon(AddonUninstallParameters), &gt; } &gt; &gt; impl WebDriverExtensionCommand for GeckoExtensionCommand { &gt; fn parameters_json(&amp;self) -&gt; Option&lt;Json&gt; { &gt; match self { &gt; &amp;GeckoExtensionCommand::GetContext =&gt; None, &gt; &amp;GeckoExtensionCommand::SetContext(ref x) =&gt; Some(x.to_json()), &gt; &amp;GeckoExtensionCommand::XblAnonymousChildren(_) =&gt; None, &gt;@@ -162,41 +187,42 @@ impl ToJson for GeckoContext { &gt; &amp;GeckoContext::Content =&gt; Json::String("content".to_owned()), &gt; &amp;GeckoContext::Chrome =&gt; Json::String("chrome".to_owned()), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Clone, Debug, PartialEq)] &gt; pub struct GeckoContextParameters { &gt;- context: GeckoContext &gt;+ context: GeckoContext, &gt; } &gt; &gt; impl Parameters for GeckoContextParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;GeckoContextParameters&gt; { &gt;- let data = try!(body.as_object().ok_or( &gt;- WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Message body was not an object"))); &gt;- let context_value = try!(data.get("context").ok_or( &gt;- WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Missing context key"))); &gt;- let value = try!(context_value.as_string().ok_or( &gt;- WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- "context was not a string"))); &gt;+ let data = try!(body.as_object().ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Message body was not an object" &gt;+ ))); &gt;+ let context_value = try!(data.get("context").ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing context key" &gt;+ ))); &gt;+ let value = try!(context_value.as_string().ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "context was not a string" &gt;+ ))); &gt; let context = try!(match value { &gt; "chrome" =&gt; Ok(GeckoContext::Chrome), &gt; "content" =&gt; Ok(GeckoContext::Content), &gt;- _ =&gt; Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- format!("{} is not a valid context", &gt;- value))) &gt;+ _ =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("{} is not a valid context", value) &gt;+ )), &gt; }); &gt;- Ok(GeckoContextParameters { &gt;- context: context &gt;- }) &gt;+ Ok(GeckoContextParameters { context: context }) &gt; } &gt; } &gt; &gt; impl ToMarionette for GeckoContextParameters { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt; let mut data = BTreeMap::new(); &gt; data.insert("value".to_owned(), self.context.to_json()); &gt; Ok(data) &gt;@@ -206,38 +232,48 @@ impl ToMarionette for GeckoContextParameters { &gt; impl ToJson for GeckoContextParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("context".to_owned(), self.context.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt;- &gt; #[derive(Clone, Debug, PartialEq)] &gt; pub struct AttributeParameters { &gt; name: String, &gt;- value: String &gt;+ value: String, &gt; } &gt; &gt; impl Parameters for AttributeParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;AttributeParameters&gt; { &gt;- let data = try!(body.as_object().ok_or( &gt;- WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Message body was not an object"))); &gt;- let name = try!(try!(data.get("name").ok_or( &gt;- WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Missing 'name' parameter"))).as_string(). &gt;- ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "'name' parameter is not a string"))); &gt;- let value = try!(try!(data.get("value").ok_or( &gt;- WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Missing 'value' parameter"))).as_string(). &gt;- ok_or(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "'value' parameter is not a string"))); &gt;+ let data = try!(body.as_object().ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Message body was not an object" &gt;+ ))); &gt;+ let name = try!( &gt;+ try!(data.get("name").ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'name' parameter" &gt;+ ))).as_string() &gt;+ .ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "'name' parameter is not a string" &gt;+ )) &gt;+ ); &gt;+ let value = try!( &gt;+ try!(data.get("value").ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'value' parameter" &gt;+ ))).as_string() &gt;+ .ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "'value' parameter is not a string" &gt;+ )) &gt;+ ); &gt; Ok(AttributeParameters { &gt; name: name.to_owned(), &gt; value: value.to_owned(), &gt; }) &gt; } &gt; } &gt; &gt; impl ToJson for AttributeParameters { &gt;@@ -258,66 +294,81 @@ impl ToMarionette for AttributeParameters { &gt; data.insert("value".to_owned(), Json::Object(value)); &gt; Ok(data) &gt; } &gt; } &gt; &gt; #[derive(Clone, Debug, PartialEq)] &gt; pub struct AddonInstallParameters { &gt; pub path: String, &gt;- pub temporary: bool &gt;+ pub temporary: bool, &gt; } &gt; &gt; impl Parameters for AddonInstallParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;AddonInstallParameters&gt; { &gt;- let data = try!(body.as_object().ok_or( &gt;- WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Message body was not an object"))); &gt;+ let data = try!(body.as_object().ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Message body was not an object" &gt;+ ))); &gt; &gt; let base64 = match data.get("addon") { &gt; Some(x) =&gt; { &gt;- let s = try_opt!(x.as_string(), &gt;- ErrorStatus::InvalidArgument, &gt;- "'addon' is not a string").to_string(); &gt;+ let s = try_opt!( &gt;+ x.as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "'addon' is not a string" &gt;+ ).to_string(); &gt; &gt;- let addon_path = env::temp_dir().as_path() &gt;+ let addon_path = env::temp_dir() &gt;+ .as_path() &gt; .join(format!("addon-{}.xpi", Uuid::new_v4())); &gt; let mut addon_file = try!(File::create(&amp;addon_path)); &gt; let addon_buf = try!(s.from_base64()); &gt; try!(addon_file.write(addon_buf.as_slice())); &gt; &gt;- Some(try_opt!(addon_path.to_str(), &gt;- ErrorStatus::UnknownError, &gt;- "could not write addon to file").to_string()) &gt;- }, &gt;+ Some( &gt;+ try_opt!( &gt;+ addon_path.to_str(), &gt;+ ErrorStatus::UnknownError, &gt;+ "could not write addon to file" &gt;+ ).to_string(), &gt;+ ) &gt;+ } &gt; None =&gt; None, &gt; }; &gt; let path = match data.get("path") { &gt;- Some(x) =&gt; Some(try_opt!(x.as_string(), &gt;- ErrorStatus::InvalidArgument, &gt;- "'path' is not a string").to_string()), &gt;+ Some(x) =&gt; Some( &gt;+ try_opt!( &gt;+ x.as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "'path' is not a string" &gt;+ ).to_string(), &gt;+ ), &gt; None =&gt; None, &gt; }; &gt; if (base64.is_none() &amp;&amp; path.is_none()) || (base64.is_some() &amp;&amp; path.is_some()) { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- "Must specify exactly one of 'path' and 'addon'")); &gt;+ "Must specify exactly one of 'path' and 'addon'", &gt;+ )); &gt; } &gt; &gt; let temporary = match data.get("temporary") { &gt;- Some(x) =&gt; try_opt!(x.as_boolean(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Failed to convert 'temporary' to boolean"), &gt;- None =&gt; false &gt;+ Some(x) =&gt; try_opt!( &gt;+ x.as_boolean(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Failed to convert 'temporary' to boolean" &gt;+ ), &gt;+ None =&gt; false, &gt; }; &gt; &gt; return Ok(AddonInstallParameters { &gt; path: base64.or(path).unwrap(), &gt; temporary: temporary, &gt;- }) &gt;+ }); &gt; } &gt; } &gt; &gt; impl ToJson for AddonInstallParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("path".to_string(), self.path.to_json()); &gt; data.insert("temporary".to_string(), self.temporary.to_json()); &gt;@@ -331,33 +382,37 @@ impl ToMarionette for AddonInstallParameters { &gt; data.insert("path".to_string(), self.path.to_json()); &gt; data.insert("temporary".to_string(), self.temporary.to_json()); &gt; Ok(data) &gt; } &gt; } &gt; &gt; #[derive(Clone, Debug, PartialEq)] &gt; pub struct AddonUninstallParameters { &gt;- pub id: String &gt;+ pub id: String, &gt; } &gt; &gt; impl Parameters for AddonUninstallParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;AddonUninstallParameters&gt; { &gt;- let data = try!(body.as_object().ok_or( &gt;- WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Message body was not an object"))); &gt;+ let data = try!(body.as_object().ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Message body was not an object" &gt;+ ))); &gt; &gt; let id = try_opt!( &gt;- try_opt!(data.get("id"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'id' parameter").as_string(), &gt;+ try_opt!( &gt;+ data.get("id"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'id' parameter" &gt;+ ).as_string(), &gt; ErrorStatus::InvalidArgument, &gt;- "'id' is not a string").to_string(); &gt;+ "'id' is not a string" &gt;+ ).to_string(); &gt; &gt;- return Ok(AddonUninstallParameters {id: id}) &gt;+ return Ok(AddonUninstallParameters { id: id }); &gt; } &gt; } &gt; &gt; impl ToJson for AddonUninstallParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("id".to_string(), self.id.to_json()); &gt; Json::Object(data) &gt;@@ -398,31 +453,36 @@ impl MarionetteHandler { &gt; pub fn new(settings: MarionetteSettings) -&gt; MarionetteHandler { &gt; MarionetteHandler { &gt; connection: Mutex::new(None), &gt; settings, &gt; browser: None, &gt; } &gt; } &gt; &gt;- fn create_connection(&amp;mut self, &gt;- session_id: &amp;Option&lt;String&gt;, &gt;- new_session_parameters: &amp;NewSessionParameters) &gt;- -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt;+ fn create_connection( &gt;+ &amp;mut self, &gt;+ session_id: &amp;Option&lt;String&gt;, &gt;+ new_session_parameters: &amp;NewSessionParameters, &gt;+ ) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt; let (options, capabilities) = { &gt; let mut fx_capabilities = FirefoxCapabilities::new(self.settings.binary.as_ref()); &gt; let mut capabilities = try!( &gt;- try!(new_session_parameters &gt;- .match_browser(&amp;mut fx_capabilities)) &gt;- .ok_or(WebDriverError::new( &gt;+ try!(new_session_parameters.match_browser(&amp;mut fx_capabilities)).ok_or( &gt;+ WebDriverError::new( &gt; ErrorStatus::SessionNotCreated, &gt;- "Unable to find a matching set of capabilities"))); &gt;+ "Unable to find a matching set of capabilities" &gt;+ ) &gt;+ ) &gt;+ ); &gt; &gt;- let options = try!(FirefoxOptions::from_capabilities(fx_capabilities.chosen_binary, &gt;- &amp;mut capabilities)); &gt;+ let options = try!(FirefoxOptions::from_capabilities( &gt;+ fx_capabilities.chosen_binary, &gt;+ &amp;mut capabilities &gt;+ )); &gt; (options, capabilities) &gt; }; &gt; &gt; if let Some(l) = options.log.level { &gt; logging::set_max_level(l); &gt; } &gt; &gt; let port = self.settings.port.unwrap_or(get_free_port()?); &gt;@@ -433,34 +493,37 @@ impl MarionetteHandler { &gt; let mut connection = MarionetteConnection::new(port, session_id.clone()); &gt; try!(connection.connect(&amp;mut self.browser)); &gt; self.connection = Mutex::new(Some(connection)); &gt; &gt; Ok(capabilities) &gt; } &gt; &gt; fn start_browser(&amp;mut self, port: u16, options: FirefoxOptions) -&gt; WebDriverResult&lt;()&gt; { &gt;- let binary = options.binary &gt;- .ok_or(WebDriverError::new(ErrorStatus::SessionNotCreated, &gt;- "Expected browser binary location, but unable to find \ &gt;- binary in default location, no \ &gt;- 'moz:firefoxOptions.binary' capability provided, and \ &gt;- no binary flag set on the command line"))?; &gt;+ let binary = options.binary.ok_or(WebDriverError::new( &gt;+ ErrorStatus::SessionNotCreated, &gt;+ "Expected browser binary location, but unable to find \ &gt;+ binary in default location, no \ &gt;+ 'moz:firefoxOptions.binary' capability provided, and \ &gt;+ no binary flag set on the command line", &gt;+ ))?; &gt; &gt; let is_custom_profile = options.profile.is_some(); &gt; &gt; let mut profile = match options.profile { &gt; Some(x) =&gt; x, &gt;- None =&gt; Profile::new(None)? &gt;+ None =&gt; Profile::new(None)?, &gt; }; &gt; &gt; self.set_prefs(port, &amp;mut profile, is_custom_profile, options.prefs) &gt; .map_err(|e| { &gt;- WebDriverError::new(ErrorStatus::SessionNotCreated, &gt;- format!("Failed to set preferences: {}", e)) &gt;+ WebDriverError::new( &gt;+ ErrorStatus::SessionNotCreated, &gt;+ format!("Failed to set preferences: {}", e), &gt;+ ) &gt; })?; &gt; &gt; let mut runner = FirefoxRunner::new(&amp;binary, profile); &gt; &gt; // https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting &gt; runner &gt; .env("MOZ_CRASHREPORTER", "1") &gt; .env("MOZ_CRASHREPORTER_NO_REPORT", "1") &gt;@@ -470,22 +533,22 @@ impl MarionetteHandler { &gt; runner.arg("-marionette"); &gt; if self.settings.jsdebugger { &gt; runner.arg("-jsdebugger"); &gt; } &gt; if let Some(args) = options.args.as_ref() { &gt; runner.args(args); &gt; } &gt; &gt;- let browser_proc = runner.start() &gt;- .map_err(|e| { &gt;- WebDriverError::new(ErrorStatus::SessionNotCreated, &gt;- format!("Failed to start browser {}: {}", &gt;- binary.display(), e)) &gt;- })?; &gt;+ let browser_proc = runner.start().map_err(|e| { &gt;+ WebDriverError::new( &gt;+ ErrorStatus::SessionNotCreated, &gt;+ format!("Failed to start browser {}: {}", binary.display(), e), &gt;+ ) &gt;+ })?; &gt; self.browser = Some(browser_proc); &gt; &gt; Ok(()) &gt; } &gt; &gt; pub fn set_prefs( &gt; &amp;self, &gt; port: u16, &gt;@@ -504,100 +567,113 @@ impl MarionetteHandler { &gt; if !custom_profile || !prefs.contains_key(name) { &gt; prefs.insert((*name).clone(), (*value).clone()); &gt; } &gt; } &gt; &gt; prefs.insert_slice(&amp;extra_prefs[..]); &gt; &gt; if self.settings.jsdebugger { &gt;- prefs.insert("devtools.browsertoolbox.panel", Pref::new("jsdebugger".to_owned())); &gt;+ prefs.insert( &gt;+ "devtools.browsertoolbox.panel", &gt;+ Pref::new("jsdebugger".to_owned()), &gt;+ ); &gt; prefs.insert("devtools.debugger.remote-enabled", Pref::new(true)); &gt; prefs.insert("devtools.chrome.enabled", Pref::new(true)); &gt; prefs.insert("devtools.debugger.prompt-connection", Pref::new(false)); &gt; prefs.insert("marionette.debugging.clicktostart", Pref::new(true)); &gt; } &gt; &gt; prefs.insert("marionette.log.level", logging::max_level().into()); &gt; prefs.insert("marionette.port", Pref::new(port)); &gt; &gt; prefs.write().map_err(|_| { &gt; WebDriverError::new(ErrorStatus::UnknownError, "Unable to write Firefox profile") &gt; }) &gt; } &gt; } &gt; &gt; impl WebDriverHandler&lt;GeckoExtensionRoute&gt; for MarionetteHandler { &gt;- fn handle_command(&amp;mut self, _: &amp;Option&lt;Session&gt;, &gt;- msg: WebDriverMessage&lt;GeckoExtensionRoute&gt;) -&gt; WebDriverResult&lt;WebDriverResponse&gt; { &gt;+ fn handle_command( &gt;+ &amp;mut self, &gt;+ _: &amp;Option&lt;Session&gt;, &gt;+ msg: WebDriverMessage&lt;GeckoExtensionRoute&gt;, &gt;+ ) -&gt; WebDriverResult&lt;WebDriverResponse&gt; { &gt; let mut resolved_capabilities = None; &gt; { &gt; let mut capabilities_options = None; &gt; // First handle the status message which doesn't actually require a marionette &gt; // connection or message &gt; if msg.command == Status { &gt;- let (ready, message) = self.connection.lock() &gt;- .map(|ref connection| connection &gt;- .as_ref() &gt;- .map(|_| (false, "Session already started")) &gt;- .unwrap_or((true, ""))) &gt;- .unwrap_or((false, "geckodriver internal error")); &gt;+ let (ready, message) = self &gt;+ .connection &gt;+ .lock() &gt;+ .map(|ref connection| { &gt;+ connection &gt;+ .as_ref() &gt;+ .map(|_| (false, "Session already started")) &gt;+ .unwrap_or((true, "")) &gt;+ }).unwrap_or((false, "geckodriver internal error")); &gt; let mut value = BTreeMap::new(); &gt; value.insert("ready".to_string(), Json::Boolean(ready)); &gt; value.insert("message".to_string(), Json::String(message.into())); &gt;- return Ok(WebDriverResponse::Generic(ValueResponse::new(Json::Object(value)))); &gt;+ return Ok(WebDriverResponse::Generic(ValueResponse::new( &gt;+ Json::Object(value), &gt;+ ))); &gt; } &gt; match self.connection.lock() { &gt; Ok(ref connection) =&gt; { &gt; if connection.is_none() { &gt; match msg.command { &gt; NewSession(ref capabilities) =&gt; { &gt; capabilities_options = Some(capabilities); &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::SessionNotCreated, &gt;- "Tried to run command without establishing a connection")); &gt;+ "Tried to run command without establishing a connection", &gt;+ )); &gt; } &gt; } &gt; } &gt;- }, &gt;+ } &gt; Err(_) =&gt; { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::UnknownError, &gt;- "Failed to aquire Marionette connection")) &gt;+ "Failed to aquire Marionette connection", &gt;+ )) &gt; } &gt; } &gt; if let Some(capabilities) = capabilities_options { &gt;- resolved_capabilities = Some(try!( &gt;- self.create_connection(&amp;msg.session_id, &amp;capabilities))); &gt;+ resolved_capabilities = &gt;+ Some(try!(self.create_connection(&amp;msg.session_id, &amp;capabilities))); &gt; } &gt; } &gt; &gt; match self.connection.lock() { &gt; Ok(ref mut connection) =&gt; { &gt; match connection.as_mut() { &gt; Some(conn) =&gt; { &gt; conn.send_command(resolved_capabilities, &amp;msg) &gt; .map_err(|mut err| { &gt; // Shutdown the browser if no session can &gt; // be established due to errors. &gt; if let NewSession(_) = msg.command { &gt; err.delete_session = true; &gt; } &gt;- err}) &gt;- }, &gt;- None =&gt; panic!("Connection missing") &gt;+ err &gt;+ }) &gt;+ } &gt;+ None =&gt; panic!("Connection missing"), &gt; } &gt;- }, &gt;- Err(_) =&gt; { &gt;- Err(WebDriverError::new( &gt;- ErrorStatus::UnknownError, &gt;- "Failed to aquire Marionette connection")) &gt; } &gt;+ Err(_) =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to aquire Marionette connection", &gt;+ )), &gt; } &gt; } &gt; &gt; fn delete_session(&amp;mut self, session: &amp;Option&lt;Session&gt;) { &gt; if let Some(ref s) = *session { &gt; let delete_session = WebDriverMessage { &gt; session_id: Some(s.id.clone()), &gt; command: WebDriverCommand::DeleteSession, &gt;@@ -624,42 +700,48 @@ impl WebDriverHandler&lt;GeckoExtensionRoute&gt; for MarionetteHandler { &gt; self.browser = None; &gt; } &gt; } &gt; &gt; pub struct MarionetteSession { &gt; pub session_id: String, &gt; protocol: Option&lt;String&gt;, &gt; application_type: Option&lt;String&gt;, &gt;- command_id: u64 &gt;+ command_id: u64, &gt; } &gt; &gt; impl MarionetteSession { &gt; pub fn new(session_id: Option&lt;String&gt;) -&gt; MarionetteSession { &gt; let initital_id = session_id.unwrap_or("".to_string()); &gt; MarionetteSession { &gt; session_id: initital_id, &gt; protocol: None, &gt; application_type: None, &gt;- command_id: 0 &gt;+ command_id: 0, &gt; } &gt; } &gt; &gt;- pub fn update(&amp;mut self, msg: &amp;WebDriverMessage&lt;GeckoExtensionRoute&gt;, &gt;- resp: &amp;MarionetteResponse) -&gt; WebDriverResult&lt;()&gt; { &gt;+ pub fn update( &gt;+ &amp;mut self, &gt;+ msg: &amp;WebDriverMessage&lt;GeckoExtensionRoute&gt;, &gt;+ resp: &amp;MarionetteResponse, &gt;+ ) -&gt; WebDriverResult&lt;()&gt; { &gt; match msg.command { &gt; NewSession(_) =&gt; { &gt; let session_id = try_opt!( &gt;- try_opt!(resp.result.find("sessionId"), &gt;- ErrorStatus::SessionNotCreated, &gt;- "Unable to get session id").as_string(), &gt;+ try_opt!( &gt;+ resp.result.find("sessionId"), &gt; ErrorStatus::SessionNotCreated, &gt;- "Unable to convert session id to string"); &gt;+ "Unable to get session id" &gt;+ ).as_string(), &gt;+ ErrorStatus::SessionNotCreated, &gt;+ "Unable to convert session id to string" &gt;+ ); &gt; self.session_id = session_id.to_string().clone(); &gt;- }, &gt;+ } &gt; _ =&gt; {} &gt; } &gt; Ok(()) &gt; } &gt; &gt; /// Converts a Marionette JSON response into a `WebElement`. &gt; /// &gt; /// Note that it currently coerces all chrome elements, web frames, and web &gt;@@ -694,347 +776,461 @@ impl MarionetteSession { &gt; Ok(WebElement::new(id)) &gt; } &gt; &gt; pub fn next_command_id(&amp;mut self) -&gt; u64 { &gt; self.command_id = self.command_id + 1; &gt; self.command_id &gt; } &gt; &gt;- pub fn response(&amp;mut self, msg: &amp;WebDriverMessage&lt;GeckoExtensionRoute&gt;, &gt;- resp: MarionetteResponse) -&gt; WebDriverResult&lt;WebDriverResponse&gt; { &gt;- &gt;+ pub fn response( &gt;+ &amp;mut self, &gt;+ msg: &amp;WebDriverMessage&lt;GeckoExtensionRoute&gt;, &gt;+ resp: MarionetteResponse, &gt;+ ) -&gt; WebDriverResult&lt;WebDriverResponse&gt; { &gt; if resp.id != self.command_id { &gt;- return Err(WebDriverError::new(ErrorStatus::UnknownError, &gt;- format!("Marionette responses arrived out of sequence, expected {}, got {}", &gt;- self.command_id, resp.id))); &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ format!( &gt;+ "Marionette responses arrived out of sequence, expected {}, got {}", &gt;+ self.command_id, resp.id &gt;+ ), &gt;+ )); &gt; } &gt; &gt; if let Some(error) = resp.error { &gt; return Err(error.into()); &gt; } &gt; &gt; try!(self.update(msg, &amp;resp)); &gt; &gt; Ok(match msg.command { &gt; // Everything that doesn't have a response value &gt;- Get(_) | GoBack | GoForward | Refresh | SetTimeouts(_) | &gt;- SwitchToWindow(_) | SwitchToFrame(_) | &gt;- SwitchToParentFrame | AddCookie(_) | DeleteCookies | DeleteCookie(_) | &gt;- DismissAlert | AcceptAlert | SendAlertText(_) | ElementClick(_) | &gt;- ElementTap(_) | ElementClear(_) | ElementSendKeys(_, _) | &gt;- PerformActions(_) | ReleaseActions =&gt; { &gt;- WebDriverResponse::Void &gt;- }, &gt;+ Get(_) &gt;+ | GoBack &gt;+ | GoForward &gt;+ | Refresh &gt;+ | SetTimeouts(_) &gt;+ | SwitchToWindow(_) &gt;+ | SwitchToFrame(_) &gt;+ | SwitchToParentFrame &gt;+ | AddCookie(_) &gt;+ | DeleteCookies &gt;+ | DeleteCookie(_) &gt;+ | DismissAlert &gt;+ | AcceptAlert &gt;+ | SendAlertText(_) &gt;+ | ElementClick(_) &gt;+ | ElementTap(_) &gt;+ | ElementClear(_) &gt;+ | ElementSendKeys(_, _) &gt;+ | PerformActions(_) &gt;+ | ReleaseActions =&gt; WebDriverResponse::Void, &gt; // Things that simply return the contents of the marionette "value" property &gt;- GetCurrentUrl | GetTitle | GetPageSource | GetWindowHandle | IsDisplayed(_) | &gt;- IsSelected(_) | GetElementAttribute(_, _) | GetElementProperty(_, _) | &gt;- GetCSSValue(_, _) | GetElementText(_) | &gt;- GetElementTagName(_) | IsEnabled(_) | ExecuteScript(_) | ExecuteAsyncScript(_) | &gt;- GetAlertText | TakeScreenshot | TakeElementScreenshot(_) =&gt; { &gt;- let value = try_opt!(resp.result.find("value"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find value field"); &gt;+ GetCurrentUrl &gt;+ | GetTitle &gt;+ | GetPageSource &gt;+ | GetWindowHandle &gt;+ | IsDisplayed(_) &gt;+ | IsSelected(_) &gt;+ | GetElementAttribute(_, _) &gt;+ | GetElementProperty(_, _) &gt;+ | GetCSSValue(_, _) &gt;+ | GetElementText(_) &gt;+ | GetElementTagName(_) &gt;+ | IsEnabled(_) &gt;+ | ExecuteScript(_) &gt;+ | ExecuteAsyncScript(_) &gt;+ | GetAlertText &gt;+ | TakeScreenshot &gt;+ | TakeElementScreenshot(_) =&gt; { &gt;+ let value = try_opt!( &gt;+ resp.result.find("value"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find value field" &gt;+ ); &gt; //TODO: Convert webelement keys &gt; WebDriverResponse::Generic(ValueResponse::new(value.clone())) &gt;- }, &gt;+ } &gt; GetTimeouts =&gt; { &gt;- let script = try_opt!(try_opt!(resp.result &gt;- .find("script"), &gt;- ErrorStatus::UnknownError, &gt;- "Missing field: script") &gt;- .as_u64(), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to interpret script timeout duration as u64"); &gt;+ let script = try_opt!( &gt;+ try_opt!( &gt;+ resp.result.find("script"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Missing field: script" &gt;+ ).as_u64(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to interpret script timeout duration as u64" &gt;+ ); &gt; // Check for the spec-compliant "pageLoad", but also for "page load", &gt; // which was sent by Firefox 52 and earlier. &gt;- let page_load = try_opt!(try_opt!(resp.result.find("pageLoad") &gt;- .or(resp.result.find("page load")), &gt;- ErrorStatus::UnknownError, &gt;- "Missing field: pageLoad") &gt;- .as_u64(), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to interpret page load duration as u64"); &gt;- let implicit = try_opt!(try_opt!(resp.result &gt;- .find("implicit"), &gt;- ErrorStatus::UnknownError, &gt;- "Missing field: implicit") &gt;- .as_u64(), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to interpret implicit search duration as u64"); &gt;+ let page_load = try_opt!( &gt;+ try_opt!( &gt;+ resp.result &gt;+ .find("pageLoad") &gt;+ .or(resp.result.find("page load")), &gt;+ ErrorStatus::UnknownError, &gt;+ "Missing field: pageLoad" &gt;+ ).as_u64(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to interpret page load duration as u64" &gt;+ ); &gt;+ let implicit = try_opt!( &gt;+ try_opt!( &gt;+ resp.result.find("implicit"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Missing field: implicit" &gt;+ ).as_u64(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to interpret implicit search duration as u64" &gt;+ ); &gt; &gt; WebDriverResponse::Timeouts(TimeoutsResponse { &gt; script: script, &gt; pageLoad: page_load, &gt; implicit: implicit, &gt; }) &gt;- }, &gt;+ } &gt; Status =&gt; panic!("Got status command that should already have been handled"), &gt;- GetWindowHandles =&gt; { &gt;- WebDriverResponse::Generic(ValueResponse::new(resp.result.clone())) &gt;- }, &gt;+ GetWindowHandles =&gt; WebDriverResponse::Generic(ValueResponse::new(resp.result.clone())), &gt; CloseWindow =&gt; { &gt;- let data = try_opt!(resp.result.as_array(), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to interpret value as array"); &gt;- let handles = try!(data.iter() &gt;- .map(|x| { &gt;- Ok(try_opt!(x.as_string(), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to interpret window handle as string") &gt;- .to_owned()) &gt;- }) &gt;- .collect()); &gt;- WebDriverResponse::CloseWindow(CloseWindowResponse { window_handles: handles }) &gt;- }, &gt;+ let data = try_opt!( &gt;+ resp.result.as_array(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to interpret value as array" &gt;+ ); &gt;+ let handles = try!( &gt;+ data.iter() &gt;+ .map(|x| Ok(try_opt!( &gt;+ x.as_string(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to interpret window handle as string" &gt;+ ).to_owned())).collect() &gt;+ ); &gt;+ WebDriverResponse::CloseWindow(CloseWindowResponse { &gt;+ window_handles: handles, &gt;+ }) &gt;+ } &gt; GetElementRect(_) =&gt; { &gt; let x = try_opt!( &gt;- try_opt!(resp.result.find("x"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find x field").as_f64(), &gt;+ try_opt!( &gt;+ resp.result.find("x"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find x field" &gt;+ ).as_f64(), &gt; ErrorStatus::UnknownError, &gt;- "Failed to interpret x as float"); &gt;+ "Failed to interpret x as float" &gt;+ ); &gt; &gt; let y = try_opt!( &gt;- try_opt!(resp.result.find("y"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find y field").as_f64(), &gt;+ try_opt!( &gt;+ resp.result.find("y"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find y field" &gt;+ ).as_f64(), &gt; ErrorStatus::UnknownError, &gt;- "Failed to interpret y as float"); &gt;+ "Failed to interpret y as float" &gt;+ ); &gt; &gt; let width = try_opt!( &gt;- try_opt!(resp.result.find("width"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find width field").as_f64(), &gt;+ try_opt!( &gt;+ resp.result.find("width"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find width field" &gt;+ ).as_f64(), &gt; ErrorStatus::UnknownError, &gt;- "Failed to interpret width as float"); &gt;+ "Failed to interpret width as float" &gt;+ ); &gt; &gt; let height = try_opt!( &gt;- try_opt!(resp.result.find("height"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find height field").as_f64(), &gt;+ try_opt!( &gt;+ resp.result.find("height"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find height field" &gt;+ ).as_f64(), &gt; ErrorStatus::UnknownError, &gt;- "Failed to interpret width as float"); &gt;+ "Failed to interpret width as float" &gt;+ ); &gt; &gt;- let rect = ElementRectResponse { x, y, width, height }; &gt;+ let rect = ElementRectResponse { &gt;+ x, &gt;+ y, &gt;+ width, &gt;+ height, &gt;+ }; &gt; WebDriverResponse::ElementRect(rect) &gt;- }, &gt;- FullscreenWindow | MinimizeWindow | MaximizeWindow | GetWindowRect | &gt;- SetWindowRect(_) =&gt; { &gt;+ } &gt;+ FullscreenWindow | MinimizeWindow | MaximizeWindow | GetWindowRect &gt;+ | SetWindowRect(_) =&gt; { &gt; let width = try_opt!( &gt;- try_opt!(resp.result.find("width"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find width field").as_u64(), &gt;+ try_opt!( &gt;+ resp.result.find("width"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find width field" &gt;+ ).as_u64(), &gt; ErrorStatus::UnknownError, &gt;- "Failed to interpret width as positive integer"); &gt;+ "Failed to interpret width as positive integer" &gt;+ ); &gt; &gt; let height = try_opt!( &gt;- try_opt!(resp.result.find("height"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find heigenht field").as_u64(), &gt;+ try_opt!( &gt;+ resp.result.find("height"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find heigenht field" &gt;+ ).as_u64(), &gt; ErrorStatus::UnknownError, &gt;- "Failed to interpret height as positive integer"); &gt;+ "Failed to interpret height as positive integer" &gt;+ ); &gt; &gt; let x = try_opt!( &gt;- try_opt!(resp.result.find("x"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find x field").as_i64(), &gt;+ try_opt!( &gt;+ resp.result.find("x"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find x field" &gt;+ ).as_i64(), &gt; ErrorStatus::UnknownError, &gt;- "Failed to interpret x as integer"); &gt;+ "Failed to interpret x as integer" &gt;+ ); &gt; &gt; let y = try_opt!( &gt;- try_opt!(resp.result.find("y"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find y field").as_i64(), &gt;+ try_opt!( &gt;+ resp.result.find("y"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find y field" &gt;+ ).as_i64(), &gt; ErrorStatus::UnknownError, &gt;- "Failed to interpret y as integer"); &gt;+ "Failed to interpret y as integer" &gt;+ ); &gt; &gt; let rect = WindowRectResponse { &gt; x: x as i32, &gt; y: y as i32, &gt; width: width as i32, &gt; height: height as i32, &gt; }; &gt; WebDriverResponse::WindowRect(rect) &gt;- }, &gt;+ } &gt; GetCookies =&gt; { &gt; let cookies = try!(self.process_cookies(&amp;resp.result)); &gt; WebDriverResponse::Cookies(CookiesResponse { value: cookies }) &gt;- }, &gt;+ } &gt; GetNamedCookie(ref name) =&gt; { &gt; let mut cookies = try!(self.process_cookies(&amp;resp.result)); &gt; cookies.retain(|x| x.name == *name); &gt;- let cookie = try_opt!(cookies.pop(), &gt;- ErrorStatus::NoSuchCookie, &gt;- format!("No cookie with name {}", name)); &gt;+ let cookie = try_opt!( &gt;+ cookies.pop(), &gt;+ ErrorStatus::NoSuchCookie, &gt;+ format!("No cookie with name {}", name) &gt;+ ); &gt; WebDriverResponse::Cookie(CookieResponse { value: cookie }) &gt; } &gt; FindElement(_) | FindElementElement(_, _) =&gt; { &gt;- let element = try!(self.to_web_element( &gt;- try_opt!(resp.result.find("value"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find value field"))); &gt;+ let element = try!(self.to_web_element(try_opt!( &gt;+ resp.result.find("value"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find value field" &gt;+ ))); &gt; WebDriverResponse::Generic(ValueResponse::new(element.to_json())) &gt;- }, &gt;+ } &gt; FindElements(_) | FindElementElements(_, _) =&gt; { &gt;- let element_vec = try_opt!(resp.result.as_array(), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to interpret value as array"); &gt;- let elements = try!(element_vec.iter().map( &gt;- |x| { &gt;- self.to_web_element(x) &gt;- }).collect::&lt;Result&lt;Vec&lt;_&gt;, _&gt;&gt;()); &gt;- WebDriverResponse::Generic(ValueResponse::new( &gt;- Json::Array(elements.iter().map(|x| {x.to_json()}).collect()))) &gt;- }, &gt;+ let element_vec = try_opt!( &gt;+ resp.result.as_array(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to interpret value as array" &gt;+ ); &gt;+ let elements = try!( &gt;+ element_vec &gt;+ .iter() &gt;+ .map(|x| self.to_web_element(x)) &gt;+ .collect::&lt;Result&lt;Vec&lt;_&gt;, _&gt;&gt;() &gt;+ ); &gt;+ WebDriverResponse::Generic(ValueResponse::new(Json::Array( &gt;+ elements.iter().map(|x| x.to_json()).collect(), &gt;+ ))) &gt;+ } &gt; GetActiveElement =&gt; { &gt;- let element = try!(self.to_web_element( &gt;- try_opt!(resp.result.find("value"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find value field"))); &gt;+ let element = try!(self.to_web_element(try_opt!( &gt;+ resp.result.find("value"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find value field" &gt;+ ))); &gt; WebDriverResponse::Generic(ValueResponse::new(element.to_json())) &gt;- }, &gt;+ } &gt; NewSession(_) =&gt; { &gt; let session_id = try_opt!( &gt;- try_opt!(resp.result.find("sessionId"), &gt;- ErrorStatus::InvalidSessionId, &gt;- "Failed to find sessionId field").as_string(), &gt;+ try_opt!( &gt;+ resp.result.find("sessionId"), &gt;+ ErrorStatus::InvalidSessionId, &gt;+ "Failed to find sessionId field" &gt;+ ).as_string(), &gt; ErrorStatus::InvalidSessionId, &gt;- "sessionId is not a string"); &gt;+ "sessionId is not a string" &gt;+ ); &gt; &gt; let mut capabilities = try_opt!( &gt;- try_opt!(resp.result.find("capabilities"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find capabilities field").as_object(), &gt;+ try_opt!( &gt;+ resp.result.find("capabilities"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find capabilities field" &gt;+ ).as_object(), &gt; ErrorStatus::UnknownError, &gt;- "capabilities field is not an object").clone(); &gt;+ "capabilities field is not an object" &gt;+ ).clone(); &gt; &gt; capabilities.insert("moz:geckodriverVersion".into(), BuildInfo.into()); &gt; &gt; WebDriverResponse::NewSession(NewSessionResponse::new( &gt;- session_id.to_string(), Json::Object(capabilities))) &gt;- }, &gt;- DeleteSession =&gt; { &gt;- WebDriverResponse::DeleteSession &gt;- }, &gt;- Extension(ref extension) =&gt; { &gt;- match extension { &gt;- &amp;GeckoExtensionCommand::GetContext =&gt; { &gt;- let value = try_opt!(resp.result.find("value"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find value field"); &gt;- WebDriverResponse::Generic(ValueResponse::new(value.clone())) &gt;- }, &gt;- &amp;GeckoExtensionCommand::SetContext(_) =&gt; WebDriverResponse::Void, &gt;- &amp;GeckoExtensionCommand::XblAnonymousChildren(_) =&gt; { &gt;- let els_vec = try_opt!(resp.result.as_array(), &gt;- ErrorStatus::UnknownError, "Failed to interpret body as array"); &gt;- let els = try!(els_vec.iter().map(|x| self.to_web_element(x)) &gt;- .collect::&lt;Result&lt;Vec&lt;_&gt;, _&gt;&gt;()); &gt;- WebDriverResponse::Generic(ValueResponse::new( &gt;- Json::Array(els.iter().map(|el| el.to_json()).collect()))) &gt;- }, &gt;- &amp;GeckoExtensionCommand::XblAnonymousByAttribute(_, _) =&gt; { &gt;- let el = try!(self.to_web_element(try_opt!(resp.result.find("value"), &gt;- ErrorStatus::UnknownError, "Failed to find value field"))); &gt;- WebDriverResponse::Generic(ValueResponse::new(el.to_json())) &gt;- }, &gt;- &amp;GeckoExtensionCommand::InstallAddon(_) =&gt; { &gt;- let value = try_opt!(resp.result.find("value"), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to find value field"); &gt;- WebDriverResponse::Generic(ValueResponse::new(value.clone())) &gt;- }, &gt;- &amp;GeckoExtensionCommand::UninstallAddon(_) =&gt; WebDriverResponse::Void &gt;- } &gt;+ session_id.to_string(), &gt;+ Json::Object(capabilities), &gt;+ )) &gt; } &gt;+ DeleteSession =&gt; WebDriverResponse::DeleteSession, &gt;+ Extension(ref extension) =&gt; match extension { &gt;+ &amp;GeckoExtensionCommand::GetContext =&gt; { &gt;+ let value = try_opt!( &gt;+ resp.result.find("value"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find value field" &gt;+ ); &gt;+ WebDriverResponse::Generic(ValueResponse::new(value.clone())) &gt;+ } &gt;+ &amp;GeckoExtensionCommand::SetContext(_) =&gt; WebDriverResponse::Void, &gt;+ &amp;GeckoExtensionCommand::XblAnonymousChildren(_) =&gt; { &gt;+ let els_vec = try_opt!( &gt;+ resp.result.as_array(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to interpret body as array" &gt;+ ); &gt;+ let els = try!( &gt;+ els_vec &gt;+ .iter() &gt;+ .map(|x| self.to_web_element(x)) &gt;+ .collect::&lt;Result&lt;Vec&lt;_&gt;, _&gt;&gt;() &gt;+ ); &gt;+ WebDriverResponse::Generic(ValueResponse::new(Json::Array( &gt;+ els.iter().map(|el| el.to_json()).collect(), &gt;+ ))) &gt;+ } &gt;+ &amp;GeckoExtensionCommand::XblAnonymousByAttribute(_, _) =&gt; { &gt;+ let el = try!(self.to_web_element(try_opt!( &gt;+ resp.result.find("value"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find value field" &gt;+ ))); &gt;+ WebDriverResponse::Generic(ValueResponse::new(el.to_json())) &gt;+ } &gt;+ &amp;GeckoExtensionCommand::InstallAddon(_) =&gt; { &gt;+ let value = try_opt!( &gt;+ resp.result.find("value"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to find value field" &gt;+ ); &gt;+ WebDriverResponse::Generic(ValueResponse::new(value.clone())) &gt;+ } &gt;+ &amp;GeckoExtensionCommand::UninstallAddon(_) =&gt; WebDriverResponse::Void, &gt;+ }, &gt; }) &gt; } &gt; &gt; fn process_cookies(&amp;self, json_data: &amp;Json) -&gt; WebDriverResult&lt;Vec&lt;Cookie&gt;&gt; { &gt;- let value = try_opt!(json_data.as_array(), &gt;- ErrorStatus::UnknownError, &gt;- "Failed to interpret value as array"); &gt;- value.iter().map(|x| { &gt;- let name = try_opt!( &gt;- try_opt!(x.find("name"), &gt;- ErrorStatus::UnknownError, &gt;- "Cookie must have a name field").as_string(), &gt;- ErrorStatus::UnknownError, &gt;- "Cookie must have string name").to_string(); &gt;- let value = try_opt!( &gt;- try_opt!(x.find("value"), &gt;- ErrorStatus::UnknownError, &gt;- "Cookie must have a value field").as_string(), &gt;- ErrorStatus::UnknownError, &gt;- "Cookie must have a string value").to_string(); &gt;- let path = try!( &gt;- Nullable::from_json(x.find("path").unwrap_or(&amp;Json::Null), &gt;- |x| { &gt;- Ok((try_opt!(x.as_string(), &gt;- ErrorStatus::UnknownError, &gt;- "Cookie path must be string")).to_string()) &gt;- })); &gt;- let domain = try!( &gt;- Nullable::from_json(x.find("domain").unwrap_or(&amp;Json::Null), &gt;- |x| { &gt;- Ok((try_opt!(x.as_string(), &gt;- ErrorStatus::UnknownError, &gt;- "Cookie domain must be string")).to_string()) &gt;- })); &gt;- let expiry = try!( &gt;- Nullable::from_json(x.find("expiry").unwrap_or(&amp;Json::Null), &gt;- |x| { &gt;- Ok(Date::new(try_opt!( &gt;- x.as_u64(), &gt;- ErrorStatus::UnknownError, &gt;- "Cookie expiry must be a positive integer"))) &gt;- })); &gt;- let secure = try_opt!( &gt;- x.find("secure").map_or(Some(false), |x| x.as_boolean()), &gt;- ErrorStatus::UnknownError, &gt;- "Cookie secure flag must be boolean"); &gt;- let http_only = try_opt!( &gt;- x.find("httpOnly").map_or(Some(false), |x| x.as_boolean()), &gt;- ErrorStatus::UnknownError, &gt;- "Cookie httpOnly flag must be boolean"); &gt;+ let value = try_opt!( &gt;+ json_data.as_array(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to interpret value as array" &gt;+ ); &gt;+ value &gt;+ .iter() &gt;+ .map(|x| { &gt;+ let name = try_opt!( &gt;+ try_opt!( &gt;+ x.find("name"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Cookie must have a name field" &gt;+ ).as_string(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Cookie must have string name" &gt;+ ).to_string(); &gt;+ let value = try_opt!( &gt;+ try_opt!( &gt;+ x.find("value"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Cookie must have a value field" &gt;+ ).as_string(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Cookie must have a string value" &gt;+ ).to_string(); &gt;+ let path = try!(Nullable::from_json( &gt;+ x.find("path").unwrap_or(&amp;Json::Null), &gt;+ |x| Ok((try_opt!( &gt;+ x.as_string(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Cookie path must be string" &gt;+ )).to_string()) &gt;+ )); &gt;+ let domain = try!(Nullable::from_json( &gt;+ x.find("domain").unwrap_or(&amp;Json::Null), &gt;+ |x| Ok((try_opt!( &gt;+ x.as_string(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Cookie domain must be string" &gt;+ )).to_string()) &gt;+ )); &gt;+ let expiry = try!(Nullable::from_json( &gt;+ x.find("expiry").unwrap_or(&amp;Json::Null), &gt;+ |x| Ok(Date::new(try_opt!( &gt;+ x.as_u64(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Cookie expiry must be a positive integer" &gt;+ ))) &gt;+ )); &gt;+ let secure = try_opt!( &gt;+ x.find("secure").map_or(Some(false), |x| x.as_boolean()), &gt;+ ErrorStatus::UnknownError, &gt;+ "Cookie secure flag must be boolean" &gt;+ ); &gt;+ let http_only = try_opt!( &gt;+ x.find("httpOnly").map_or(Some(false), |x| x.as_boolean()), &gt;+ ErrorStatus::UnknownError, &gt;+ "Cookie httpOnly flag must be boolean" &gt;+ ); &gt; &gt;- let new_cookie = Cookie { &gt;- name: name, &gt;- value: value, &gt;- path: path, &gt;- domain: domain, &gt;- expiry: expiry, &gt;- secure: secure, &gt;- httpOnly: http_only, &gt;- }; &gt;- Ok(new_cookie) &gt;- }).collect::&lt;Result&lt;Vec&lt;_&gt;, _&gt;&gt;() &gt;+ let new_cookie = Cookie { &gt;+ name: name, &gt;+ value: value, &gt;+ path: path, &gt;+ domain: domain, &gt;+ expiry: expiry, &gt;+ secure: secure, &gt;+ httpOnly: http_only, &gt;+ }; &gt;+ Ok(new_cookie) &gt;+ }).collect::&lt;Result&lt;Vec&lt;_&gt;, _&gt;&gt;() &gt; } &gt; } &gt; &gt; pub struct MarionetteCommand { &gt; pub id: u64, &gt; pub name: String, &gt;- pub params: BTreeMap&lt;String, Json&gt; &gt;+ pub params: BTreeMap&lt;String, Json&gt;, &gt; } &gt; &gt; impl MarionetteCommand { &gt; fn new(id: u64, name: String, params: BTreeMap&lt;String, Json&gt;) -&gt; MarionetteCommand { &gt; MarionetteCommand { &gt; id: id, &gt; name: name, &gt; params: params, &gt; } &gt; } &gt; &gt;- fn from_webdriver_message(id: u64, &gt;- capabilities: Option&lt;BTreeMap&lt;String, Json&gt;&gt;, &gt;- msg: &amp;WebDriverMessage&lt;GeckoExtensionRoute&gt;) &gt;- -&gt; WebDriverResult&lt;MarionetteCommand&gt; { &gt;+ fn from_webdriver_message( &gt;+ id: u64, &gt;+ capabilities: Option&lt;BTreeMap&lt;String, Json&gt;&gt;, &gt;+ msg: &amp;WebDriverMessage&lt;GeckoExtensionRoute&gt;, &gt;+ ) -&gt; WebDriverResult&lt;MarionetteCommand&gt; { &gt; let (opt_name, opt_parameters) = match msg.command { &gt; Status =&gt; panic!("Got status command that should already have been handled"), &gt; AcceptAlert =&gt; { &gt; // Needs to be updated to "WebDriver:AcceptAlert" for Firefox 63 &gt; (Some("WebDriver:AcceptDialog"), None) &gt; } &gt; AddCookie(ref x) =&gt; (Some("WebDriver:AddCookie"), Some(x.to_marionette())), &gt; CloseWindow =&gt; (Some("WebDriver:CloseWindow"), None), &gt;@@ -1196,120 +1392,159 @@ impl MarionetteCommand { &gt; data.insert("using".to_owned(), "anon".to_json()); &gt; data.insert("value".to_owned(), Json::Null); &gt; data.insert("element".to_string(), e.id.to_json()); &gt; (Some("WebDriver:FindElements"), Some(Ok(data))) &gt; } &gt; }, &gt; }; &gt; &gt;- let name = try_opt!(opt_name, &gt;- ErrorStatus::UnsupportedOperation, &gt;- "Operation not supported"); &gt;+ let name = try_opt!( &gt;+ opt_name, &gt;+ ErrorStatus::UnsupportedOperation, &gt;+ "Operation not supported" &gt;+ ); &gt; let parameters = try!(opt_parameters.unwrap_or(Ok(BTreeMap::new()))); &gt; &gt; Ok(MarionetteCommand::new(id, name.into(), parameters)) &gt; } &gt; } &gt; &gt; impl ToJson for MarionetteCommand { &gt; fn to_json(&amp;self) -&gt; Json { &gt;- Json::Array(vec![Json::U64(0), self.id.to_json(), self.name.to_json(), &gt;- self.params.to_json()]) &gt;+ Json::Array(vec![ &gt;+ Json::U64(0), &gt;+ self.id.to_json(), &gt;+ self.name.to_json(), &gt;+ self.params.to_json(), &gt;+ ]) &gt; } &gt; } &gt; &gt; pub struct MarionetteResponse { &gt; pub id: u64, &gt; pub error: Option&lt;MarionetteError&gt;, &gt; pub result: Json, &gt; } &gt; &gt; impl MarionetteResponse { &gt; fn from_json(data: &amp;Json) -&gt; WebDriverResult&lt;MarionetteResponse&gt; { &gt;- let data_array = try_opt!(data.as_array(), &gt;- ErrorStatus::UnknownError, &gt;- "Expected a json array"); &gt;+ let data_array = try_opt!( &gt;+ data.as_array(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected a json array" &gt;+ ); &gt; &gt; if data_array.len() != 4 { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::UnknownError, &gt;- "Expected an array of length 4")); &gt;+ "Expected an array of length 4", &gt;+ )); &gt; } &gt; &gt; if data_array[0].as_u64() != Some(1) { &gt;- return Err(WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Expected 1 in first element of response")); &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected 1 in first element of response", &gt;+ )); &gt; }; &gt;- let id = try_opt!(data[1].as_u64(), &gt;- ErrorStatus::UnknownError, &gt;- "Expected an integer id"); &gt;+ let id = try_opt!( &gt;+ data[1].as_u64(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected an integer id" &gt;+ ); &gt; let error = if data[2].is_object() { &gt; Some(try!(MarionetteError::from_json(&amp;data[2]))) &gt; } else if data[2].is_null() { &gt; None &gt; } else { &gt;- return Err(WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Expected object or null error")); &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected object or null error", &gt;+ )); &gt; }; &gt; &gt; let result = if data[3].is_null() || data[3].is_object() || data[3].is_array() { &gt; data[3].clone() &gt; } else { &gt;- return Err(WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Expected object params")); &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected object params", &gt;+ )); &gt; }; &gt; &gt;- Ok(MarionetteResponse {id: id, &gt;- error: error, &gt;- result: result}) &gt;+ Ok(MarionetteResponse { &gt;+ id: id, &gt;+ error: error, &gt;+ result: result, &gt;+ }) &gt; } &gt; } &gt; &gt; impl ToJson for MarionetteResponse { &gt; fn to_json(&amp;self) -&gt; Json { &gt;- Json::Array(vec![Json::U64(1), self.id.to_json(), self.error.to_json(), &gt;- self.result.clone()]) &gt;+ Json::Array(vec![ &gt;+ Json::U64(1), &gt;+ self.id.to_json(), &gt;+ self.error.to_json(), &gt;+ self.result.clone(), &gt;+ ]) &gt; } &gt; } &gt; &gt; #[derive(RustcEncodable, RustcDecodable)] &gt; pub struct MarionetteError { &gt; pub code: String, &gt; pub message: String, &gt;- pub stacktrace: Option&lt;String&gt; &gt;+ pub stacktrace: Option&lt;String&gt;, &gt; } &gt; &gt; impl MarionetteError { &gt; fn from_json(data: &amp;Json) -&gt; WebDriverResult&lt;MarionetteError&gt; { &gt; if !data.is_object() { &gt;- return Err(WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Expected an error object")); &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected an error object", &gt;+ )); &gt; } &gt; &gt; let code = try_opt!( &gt;- try_opt!(data.find("error"), &gt;- ErrorStatus::UnknownError, &gt;- "Error value has no error code").as_string(), &gt;+ try_opt!( &gt;+ data.find("error"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Error value has no error code" &gt;+ ).as_string(), &gt; ErrorStatus::UnknownError, &gt;- "Error status was not a string").into(); &gt;+ "Error status was not a string" &gt;+ ).into(); &gt; let message = try_opt!( &gt;- try_opt!(data.find("message"), &gt;- ErrorStatus::UnknownError, &gt;- "Error value has no message").as_string(), &gt;+ try_opt!( &gt;+ data.find("message"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Error value has no message" &gt;+ ).as_string(), &gt; ErrorStatus::UnknownError, &gt;- "Error message was not a string").into(); &gt;+ "Error message was not a string" &gt;+ ).into(); &gt; let stacktrace = match data.find("stacktrace") { &gt; None | Some(&amp;Json::Null) =&gt; None, &gt;- Some(x) =&gt; Some(try_opt!(x.as_string(), &gt;- ErrorStatus::UnknownError, &gt;- "Error message was not a string").into()), &gt;+ Some(x) =&gt; Some( &gt;+ try_opt!( &gt;+ x.as_string(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Error message was not a string" &gt;+ ).into(), &gt;+ ), &gt; }; &gt; &gt;- Ok(MarionetteError { code, message, stacktrace }) &gt;+ Ok(MarionetteError { &gt;+ code, &gt;+ message, &gt;+ stacktrace, &gt;+ }) &gt; } &gt; } &gt; &gt; impl ToJson for MarionetteError { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("error".into(), self.code.to_json()); &gt; data.insert("message".into(), self.message.to_json()); &gt;@@ -1335,17 +1570,17 @@ fn get_free_port() -&gt; IoResult&lt;u16&gt; { &gt; TcpListener::bind((DEFAULT_HOST, 0)) &gt; .and_then(|stream| stream.local_addr()) &gt; .map(|x| x.port()) &gt; } &gt; &gt; pub struct MarionetteConnection { &gt; port: u16, &gt; stream: Option&lt;TcpStream&gt;, &gt;- pub session: MarionetteSession &gt;+ pub session: MarionetteSession, &gt; } &gt; &gt; impl MarionetteConnection { &gt; pub fn new(port: u16, session_id: Option&lt;String&gt;) -&gt; MarionetteConnection { &gt; MarionetteConnection { &gt; port: port, &gt; stream: None, &gt; session: MarionetteSession::new(session_id), &gt;@@ -1405,83 +1640,110 @@ impl MarionetteConnection { &gt; debug!("Connected to Marionette on {}:{}", DEFAULT_HOST, self.port); &gt; self.handshake() &gt; } &gt; &gt; fn handshake(&amp;mut self) -&gt; WebDriverResult&lt;()&gt; { &gt; let resp = try!(self.read_resp()); &gt; let handshake_data = try!(Json::from_str(&amp;*resp)); &gt; &gt;- let data = try_opt!(handshake_data.as_object(), &gt;- ErrorStatus::UnknownError, &gt;- "Expected a json object in handshake"); &gt;+ let data = try_opt!( &gt;+ handshake_data.as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected a json object in handshake" &gt;+ ); &gt; &gt;- self.session.protocol = Some(try_opt!(data.get("marionetteProtocol"), &gt;- ErrorStatus::UnknownError, &gt;- "Missing 'marionetteProtocol' field in handshake").to_string()); &gt;+ self.session.protocol = Some( &gt;+ try_opt!( &gt;+ data.get("marionetteProtocol"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Missing 'marionetteProtocol' field in handshake" &gt;+ ).to_string(), &gt;+ ); &gt; &gt;- self.session.application_type = Some(try_opt!(data.get("applicationType"), &gt;- ErrorStatus::UnknownError, &gt;- "Missing 'applicationType' field in handshake").to_string()); &gt;+ self.session.application_type = Some( &gt;+ try_opt!( &gt;+ data.get("applicationType"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Missing 'applicationType' field in handshake" &gt;+ ).to_string(), &gt;+ ); &gt; &gt; if self.session.protocol != Some("3".into()) { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::UnknownError, &gt;- format!("Unsupported Marionette protocol version {}, required 3", &gt;- self.session.protocol.as_ref().unwrap_or(&amp;"&lt;unknown&gt;".into())))); &gt;+ format!( &gt;+ "Unsupported Marionette protocol version {}, required 3", &gt;+ self.session &gt;+ .protocol &gt;+ .as_ref() &gt;+ .unwrap_or(&amp;"&lt;unknown&gt;".into()) &gt;+ ), &gt;+ )); &gt; } &gt; &gt; Ok(()) &gt; } &gt; &gt;- pub fn close(&amp;self) { &gt;- } &gt;+ pub fn close(&amp;self) {} &gt; &gt;- fn encode_msg(&amp;self, msg:Json) -&gt; String { &gt;+ fn encode_msg(&amp;self, msg: Json) -&gt; String { &gt; let data = json::encode(&amp;msg).unwrap(); &gt; format!("{}:{}", data.len(), data) &gt; } &gt; &gt;- pub fn send_command(&amp;mut self, &gt;- capabilities: Option&lt;BTreeMap&lt;String, Json&gt;&gt;, &gt;- msg: &amp;WebDriverMessage&lt;GeckoExtensionRoute&gt;) &gt;- -&gt; WebDriverResult&lt;WebDriverResponse&gt; { &gt;+ pub fn send_command( &gt;+ &amp;mut self, &gt;+ capabilities: Option&lt;BTreeMap&lt;String, Json&gt;&gt;, &gt;+ msg: &amp;WebDriverMessage&lt;GeckoExtensionRoute&gt;, &gt;+ ) -&gt; WebDriverResult&lt;WebDriverResponse&gt; { &gt; let id = self.session.next_command_id(); &gt;- let command = try!(MarionetteCommand::from_webdriver_message(id, capabilities, msg)); &gt;+ let command = try!(MarionetteCommand::from_webdriver_message( &gt;+ id, &gt;+ capabilities, &gt;+ msg &gt;+ )); &gt; &gt; let resp_data = try!(self.send(command.to_json())); &gt; let json_data: Json = try!(Json::from_str(&amp;*resp_data)); &gt; &gt;- self.session.response(msg, try!(MarionetteResponse::from_json(&amp;json_data))) &gt;+ self.session &gt;+ .response(msg, try!(MarionetteResponse::from_json(&amp;json_data))) &gt; } &gt; &gt; fn send(&amp;mut self, msg: Json) -&gt; WebDriverResult&lt;String&gt; { &gt; let data = self.encode_msg(msg); &gt; &gt; match self.stream { &gt; Some(ref mut stream) =&gt; { &gt; if stream.write(&amp;*data.as_bytes()).is_err() { &gt;- let mut err = WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Failed to write response to stream"); &gt;+ let mut err = WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to write response to stream", &gt;+ ); &gt; err.delete_session = true; &gt; return Err(err); &gt; } &gt; } &gt; None =&gt; { &gt;- let mut err = WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Tried to write before opening stream"); &gt;+ let mut err = WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Tried to write before opening stream", &gt;+ ); &gt; err.delete_session = true; &gt; return Err(err); &gt; } &gt; } &gt; match self.read_resp() { &gt; Ok(resp) =&gt; Ok(resp), &gt; Err(_) =&gt; { &gt;- let mut err = WebDriverError::new(ErrorStatus::UnknownError, &gt;- "Failed to decode response from marionette"); &gt;+ let mut err = WebDriverError::new( &gt;+ ErrorStatus::UnknownError, &gt;+ "Failed to decode response from marionette", &gt;+ ); &gt; err.delete_session = true; &gt; Err(err) &gt; } &gt; } &gt; } &gt; &gt; fn read_resp(&amp;mut self) -&gt; IoResult&lt;String&gt; { &gt; let mut bytes = 0usize; &gt;@@ -1512,18 +1774,20 @@ impl MarionetteConnection { &gt; } &gt; &gt; let buf = &amp;mut [0 as u8; 8192]; &gt; let mut payload = Vec::with_capacity(bytes); &gt; let mut total_read = 0; &gt; while total_read &lt; bytes { &gt; let num_read = try!(stream.read(buf)); &gt; if num_read == 0 { &gt;- return Err(IoError::new(ErrorKind::Other, &gt;- "EOF reading marionette message")) &gt;+ return Err(IoError::new( &gt;+ ErrorKind::Other, &gt;+ "EOF reading marionette message", &gt;+ )); &gt; } &gt; total_read += num_read; &gt; for x in &amp;buf[..num_read] { &gt; payload.push(*x); &gt; } &gt; } &gt; &gt; // TODO(jgraham): Need to handle the error here &gt;@@ -1532,46 +1796,59 @@ impl MarionetteConnection { &gt; } &gt; &gt; trait ToMarionette { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt;; &gt; } &gt; &gt; impl ToMarionette for GetParameters { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt;- Ok(try_opt!(self.to_json().as_object(), ErrorStatus::UnknownError, "Expected an object").clone()) &gt;+ Ok(try_opt!( &gt;+ self.to_json().as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected an object" &gt;+ ).clone()) &gt; } &gt; } &gt; &gt; impl ToMarionette for TimeoutsParameters { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt;- Ok(try_opt!(self.to_json().as_object(), ErrorStatus::UnknownError, "Expected an object").clone()) &gt;+ Ok(try_opt!( &gt;+ self.to_json().as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected an object" &gt;+ ).clone()) &gt; } &gt; } &gt; &gt; impl ToMarionette for WindowRectParameters { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt;- Ok(try_opt!(self.to_json().as_object(), ErrorStatus::UnknownError, "Expected an object").clone()) &gt;+ Ok(try_opt!( &gt;+ self.to_json().as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected an object" &gt;+ ).clone()) &gt; } &gt; } &gt; &gt; impl ToMarionette for SwitchToWindowParameters { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt; let mut data = BTreeMap::new(); &gt; data.insert("name".to_string(), self.handle.to_json()); &gt; Ok(data) &gt; } &gt; } &gt; &gt; impl ToMarionette for LocatorParameters { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt;- Ok(try_opt!(self.to_json().as_object(), &gt;- ErrorStatus::UnknownError, &gt;- "Expected an object") &gt;- .clone()) &gt;+ Ok(try_opt!( &gt;+ self.to_json().as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected an object" &gt;+ ).clone()) &gt; } &gt; } &gt; &gt; impl ToMarionette for SwitchToFrameParameters { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt; let mut data = BTreeMap::new(); &gt; let key = match self.id { &gt; FrameId::Null =&gt; None, &gt;@@ -1592,29 +1869,31 @@ impl ToMarionette for JavascriptCommandParameters { &gt; data.insert("specialPowers".to_string(), false.to_json()); &gt; data.insert("scriptTimeout".to_string(), Json::Null); &gt; Ok(data) &gt; } &gt; } &gt; &gt; impl ToMarionette for ActionsParameters { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt;- Ok(try_opt!(self.to_json().as_object(), &gt;- ErrorStatus::UnknownError, &gt;- "Expected an object") &gt;- .clone()) &gt;+ Ok(try_opt!( &gt;+ self.to_json().as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected an object" &gt;+ ).clone()) &gt; } &gt; } &gt; &gt; impl ToMarionette for GetNamedCookieParameters { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt;- Ok(try_opt!(self.to_json().as_object(), &gt;- ErrorStatus::UnknownError, &gt;- "Expected an object") &gt;- .clone()) &gt;+ Ok(try_opt!( &gt;+ self.to_json().as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected an object" &gt;+ ).clone()) &gt; } &gt; } &gt; &gt; impl ToMarionette for AddCookieParameters { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt; let mut cookie = BTreeMap::new(); &gt; cookie.insert("name".to_string(), self.name.to_json()); &gt; cookie.insert("value".to_string(), self.value.to_json()); &gt;@@ -1635,17 +1914,17 @@ impl ToMarionette for AddCookieParameters { &gt; } &gt; } &gt; &gt; impl ToMarionette for TakeScreenshotParameters { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt; let mut data = BTreeMap::new(); &gt; let element = match self.element { &gt; Nullable::Null =&gt; Json::Null, &gt;- Nullable::Value(ref x) =&gt; Json::Object(try!(x.to_marionette())) &gt;+ Nullable::Value(ref x) =&gt; Json::Object(try!(x.to_marionette())), &gt; }; &gt; data.insert("element".to_string(), element); &gt; Ok(data) &gt; } &gt; } &gt; &gt; impl ToMarionette for WebElement { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt;@@ -1655,69 +1934,75 @@ impl ToMarionette for WebElement { &gt; } &gt; } &gt; &gt; impl&lt;T: ToJson&gt; ToMarionette for Nullable&lt;T&gt; { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt; //Note this is a terrible hack. We don't want Nullable&lt;T: ToJson+ToMarionette&gt; &gt; //so in cases where ToJson != ToMarionette you have to deal with the Nullable &gt; //explicitly. This kind of suggests that the whole design is wrong. &gt;- Ok(try_opt!(self.to_json().as_object(), ErrorStatus::UnknownError, "Expected an object").clone()) &gt;+ Ok(try_opt!( &gt;+ self.to_json().as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Expected an object" &gt;+ ).clone()) &gt; } &gt; } &gt; &gt; impl ToMarionette for FrameId { &gt; fn to_marionette(&amp;self) -&gt; WebDriverResult&lt;BTreeMap&lt;String, Json&gt;&gt; { &gt; let mut data = BTreeMap::new(); &gt; match *self { &gt; FrameId::Short(x) =&gt; data.insert("id".to_string(), x.to_json()), &gt;- FrameId::Element(ref x) =&gt; data.insert("element".to_string(), &gt;- Json::Object(try!(x.to_marionette()))), &gt;- FrameId::Null =&gt; None &gt;+ FrameId::Element(ref x) =&gt; { &gt;+ data.insert("element".to_string(), Json::Object(try!(x.to_marionette()))) &gt;+ } &gt;+ FrameId::Null =&gt; None, &gt; }; &gt; Ok(data) &gt; } &gt; } &gt; &gt; #[cfg(test)] &gt; mod tests { &gt; use marionette::{AddonInstallParameters, Parameters}; &gt; use rustc_serialize::json::Json; &gt;- use std::io::Read; &gt; use std::fs::File; &gt;+ use std::io::Read; &gt; use webdriver::error::WebDriverResult; &gt; &gt; #[test] &gt; fn test_addon_install_params_missing_path() { &gt; let json_data: Json = Json::from_str(r#"{"temporary": true}"#).unwrap(); &gt; let res: WebDriverResult&lt;AddonInstallParameters&gt; = Parameters::from_json(&amp;json_data); &gt; assert!(res.is_err()); &gt; } &gt; &gt; #[test] &gt; fn test_addon_install_params_with_both_path_and_base64() { &gt;- let json_data: Json = Json::from_str( &gt;- r#"{"path": "/path/to.xpi", "addon": "aGVsbG8=", "temporary": true}"#).unwrap(); &gt;+ let json_data: Json = &gt;+ Json::from_str(r#"{"path": "/path/to.xpi", "addon": "aGVsbG8=", "temporary": true}"#) &gt;+ .unwrap(); &gt; let res: WebDriverResult&lt;AddonInstallParameters&gt; = Parameters::from_json(&amp;json_data); &gt; assert!(res.is_err()); &gt; } &gt; &gt; #[test] &gt; fn test_addon_install_params_with_path() { &gt;- let json_data: Json = Json::from_str( &gt;- r#"{"path": "/path/to.xpi", "temporary": true}"#).unwrap(); &gt;+ let json_data: Json = &gt;+ Json::from_str(r#"{"path": "/path/to.xpi", "temporary": true}"#).unwrap(); &gt; let parameters: AddonInstallParameters = Parameters::from_json(&amp;json_data).unwrap(); &gt; assert_eq!(parameters.path, "/path/to.xpi"); &gt; assert_eq!(parameters.temporary, true); &gt; } &gt; &gt; #[test] &gt; fn test_addon_install_params_with_base64() { &gt;- let json_data: Json = Json::from_str( &gt;- r#"{"addon": "aGVsbG8=", "temporary": true}"#).unwrap(); &gt;+ let json_data: Json = &gt;+ Json::from_str(r#"{"addon": "aGVsbG8=", "temporary": true}"#).unwrap(); &gt; let parameters: AddonInstallParameters = Parameters::from_json(&amp;json_data).unwrap(); &gt; &gt; assert_eq!(parameters.temporary, true); &gt; let mut file = File::open(parameters.path).unwrap(); &gt; let mut contents = String::new(); &gt; file.read_to_string(&amp;mut contents).unwrap(); &gt; assert_eq!("hello", contents); &gt; } &gt;diff --git a/testing/mozbase/rust/mozprofile/src/lib.rs b/testing/mozbase/rust/mozprofile/src/lib.rs &gt;index ef7a52274b0f..86816201717f 100644 &gt;--- a/testing/mozbase/rust/mozprofile/src/lib.rs &gt;+++ b/testing/mozbase/rust/mozprofile/src/lib.rs &gt;@@ -1,146 +1,133 @@ &gt; extern crate tempdir; &gt; &gt;-pub mod profile; &gt; pub mod preferences; &gt; pub mod prefreader; &gt;- &gt;+pub mod profile; &gt; &gt; #[cfg(test)] &gt; mod test { &gt;-// use std::fs::File; &gt;-// use profile::Profile; &gt;- use prefreader::{parse, tokenize, serialize}; &gt;- use prefreader::{PrefToken, Position}; &gt;+ // use std::fs::File; &gt;+ // use profile::Profile; &gt; use preferences::Pref; &gt;+ use prefreader::{parse, serialize, tokenize}; &gt;+ use prefreader::{Position, PrefToken}; &gt; use std::collections::BTreeMap; &gt; use std::error::Error; &gt; use std::io::Cursor; &gt; use std::str; &gt; &gt; #[test] &gt; fn tokenize_simple() { &gt; let prefs = " user_pref ( 'example.pref.string', 'value' ) ;\n pref(\"example.pref.int\", -123); sticky_pref('example.pref.bool',false);"; &gt; &gt; let p = Position::new(); &gt; &gt;- let expected = vec![PrefToken::UserPrefFunction(p), &gt;- PrefToken::Paren('(', p), &gt;- PrefToken::String("example.pref.string".into(), p), &gt;- PrefToken::Comma(p), &gt;- PrefToken::String("value".into(), p), &gt;- PrefToken::Paren(')', p), &gt;- PrefToken::Semicolon(p), &gt;- PrefToken::PrefFunction(p), &gt;- PrefToken::Paren('(', p), &gt;- PrefToken::String("example.pref.int".into(), p), &gt;- PrefToken::Comma(p), &gt;- PrefToken::Int(-123, p), &gt;- PrefToken::Paren(')', p), &gt;- PrefToken::Semicolon(p), &gt;- PrefToken::StickyPrefFunction(p), &gt;- PrefToken::Paren('(', p), &gt;- PrefToken::String("example.pref.bool".into(), p), &gt;- PrefToken::Comma(p), &gt;- PrefToken::Bool(false, p), &gt;- PrefToken::Paren(')', p), &gt;- PrefToken::Semicolon(p)]; &gt;+ let expected = vec![ &gt;+ PrefToken::UserPrefFunction(p), &gt;+ PrefToken::Paren('(', p), &gt;+ PrefToken::String("example.pref.string".into(), p), &gt;+ PrefToken::Comma(p), &gt;+ PrefToken::String("value".into(), p), &gt;+ PrefToken::Paren(')', p), &gt;+ PrefToken::Semicolon(p), &gt;+ PrefToken::PrefFunction(p), &gt;+ PrefToken::Paren('(', p), &gt;+ PrefToken::String("example.pref.int".into(), p), &gt;+ PrefToken::Comma(p), &gt;+ PrefToken::Int(-123, p), &gt;+ PrefToken::Paren(')', p), &gt;+ PrefToken::Semicolon(p), &gt;+ PrefToken::StickyPrefFunction(p), &gt;+ PrefToken::Paren('(', p), &gt;+ PrefToken::String("example.pref.bool".into(), p), &gt;+ PrefToken::Comma(p), &gt;+ PrefToken::Bool(false, p), &gt;+ PrefToken::Paren(')', p), &gt;+ PrefToken::Semicolon(p), &gt;+ ]; &gt; &gt; tokenize_test(prefs, &amp;expected); &gt; } &gt; &gt; #[test] &gt; fn tokenize_comments() { &gt; let prefs = "# bash style comment\n /*block comment*/ user_pref/*block comment*/(/*block comment*/ 'example.pref.string' /*block comment*/,/*block comment*/ 'value'/*block comment*/ )// line comment"; &gt; &gt; let p = Position::new(); &gt; &gt;- let expected = vec![PrefToken::CommentBashLine(" bash style comment".into(), p), &gt;- PrefToken::CommentBlock("block comment".into(), p), &gt;- PrefToken::UserPrefFunction(p), &gt;- PrefToken::CommentBlock("block comment".into(), p), &gt;- PrefToken::Paren('(', p), &gt;- PrefToken::CommentBlock("block comment".into(), p), &gt;- PrefToken::String("example.pref.string".into(), p), &gt;- PrefToken::CommentBlock("block comment".into(), p), &gt;- PrefToken::Comma(p), &gt;- PrefToken::CommentBlock("block comment".into(), p), &gt;- PrefToken::String("value".into(), p), &gt;- PrefToken::CommentBlock("block comment".into(), p), &gt;- PrefToken::Paren(')', p), &gt;- PrefToken::CommentLine(" line comment".into(), p)]; &gt;+ let expected = vec![ &gt;+ PrefToken::CommentBashLine(" bash style comment".into(), p), &gt;+ PrefToken::CommentBlock("block comment".into(), p), &gt;+ PrefToken::UserPrefFunction(p), &gt;+ PrefToken::CommentBlock("block comment".into(), p), &gt;+ PrefToken::Paren('(', p), &gt;+ PrefToken::CommentBlock("block comment".into(), p), &gt;+ PrefToken::String("example.pref.string".into(), p), &gt;+ PrefToken::CommentBlock("block comment".into(), p), &gt;+ PrefToken::Comma(p), &gt;+ PrefToken::CommentBlock("block comment".into(), p), &gt;+ PrefToken::String("value".into(), p), &gt;+ PrefToken::CommentBlock("block comment".into(), p), &gt;+ PrefToken::Paren(')', p), &gt;+ PrefToken::CommentLine(" line comment".into(), p), &gt;+ ]; &gt; &gt; tokenize_test(prefs, &amp;expected); &gt; } &gt; &gt; #[test] &gt; fn tokenize_escapes() { &gt; let prefs = r#"user_pref('example\x20pref', "\u0020\u2603\uD800\uDC96\"\'\n\r\\\w)"#; &gt; &gt; let p = Position::new(); &gt; &gt;- let expected = vec![PrefToken::UserPrefFunction(p), &gt;- PrefToken::Paren('(', p), &gt;- PrefToken::String("example pref".into(), p), &gt;- PrefToken::Comma(p), &gt;- PrefToken::String(" ☃𐂖\"'\n\r\\\\w".into(), p), &gt;- PrefToken::Paren(')', p)]; &gt;+ let expected = vec![ &gt;+ PrefToken::UserPrefFunction(p), &gt;+ PrefToken::Paren('(', p), &gt;+ PrefToken::String("example pref".into(), p), &gt;+ PrefToken::Comma(p), &gt;+ PrefToken::String(" ☃𐂖\"'\n\r\\\\w".into(), p), &gt;+ PrefToken::Paren(')', p), &gt;+ ]; &gt; &gt; tokenize_test(prefs, &amp;expected); &gt; } &gt; &gt; fn tokenize_test(prefs: &amp;str, expected: &amp;[PrefToken]) { &gt; println!("{}\n", prefs); &gt; &gt; for (e, a) in expected.iter().zip(tokenize(prefs.as_bytes())) { &gt; let success = match (e, &amp;a) { &gt;- (&amp;PrefToken::PrefFunction(_), &gt;- &amp;PrefToken::PrefFunction(_)) =&gt; true, &gt;- (&amp;PrefToken::UserPrefFunction(_), &gt;- &amp;PrefToken::UserPrefFunction(_)) =&gt; true, &gt;- (&amp;PrefToken::StickyPrefFunction(_), &gt;- &amp;PrefToken::StickyPrefFunction(_)) =&gt; true, &gt;- (&amp;PrefToken::CommentBlock(ref data_e, _), &gt;- &amp;PrefToken::CommentBlock(ref data_a, _)) =&gt; { &gt;- data_e == data_a &gt;- }, &gt;- (&amp;PrefToken::CommentLine(ref data_e, _), &gt;- &amp;PrefToken::CommentLine(ref data_a, _)) =&gt; { &gt;- data_e == data_a &gt;- }, &gt;- (&amp;PrefToken::CommentBashLine(ref data_e, _), &gt;- &amp;PrefToken::CommentBashLine(ref data_a, _)) =&gt; { &gt;- data_e == data_a &gt;- }, &gt;- (&amp;PrefToken::Paren(data_e, _), &gt;- &amp;PrefToken::Paren(data_a, _)) =&gt; { &gt;- data_e == data_a &gt;- }, &gt;- (&amp;PrefToken::Semicolon(_), &gt;- &amp;PrefToken::Semicolon(_)) =&gt; true, &gt;- (&amp;PrefToken::Comma(_), &gt;- &amp;PrefToken::Comma(_)) =&gt; true, &gt;- (&amp;PrefToken::String(ref data_e, _), &gt;- &amp;PrefToken::String(ref data_a, _)) =&gt; { &gt;- data_e == data_a &gt;- }, &gt;- (&amp;PrefToken::Int(data_e, _), &gt;- &amp;PrefToken::Int(data_a, _)) =&gt; { &gt;- data_e == data_a &gt;- }, &gt;- (&amp;PrefToken::Bool(data_e, _), &gt;- &amp;PrefToken::Bool(data_a, _)) =&gt; { &gt;- data_e == data_a &gt;- }, &gt;- (&amp;PrefToken::Error(data_e, _), &gt;- &amp;PrefToken::Error(data_a, _)) =&gt; { &gt;- data_e == data_a &gt;- }, &gt;- (_, _) =&gt; false &gt;+ (&amp;PrefToken::PrefFunction(_), &amp;PrefToken::PrefFunction(_)) =&gt; true, &gt;+ (&amp;PrefToken::UserPrefFunction(_), &amp;PrefToken::UserPrefFunction(_)) =&gt; true, &gt;+ (&amp;PrefToken::StickyPrefFunction(_), &amp;PrefToken::StickyPrefFunction(_)) =&gt; true, &gt;+ ( &gt;+ &amp;PrefToken::CommentBlock(ref data_e, _), &gt;+ &amp;PrefToken::CommentBlock(ref data_a, _), &gt;+ ) =&gt; data_e == data_a, &gt;+ ( &gt;+ &amp;PrefToken::CommentLine(ref data_e, _), &gt;+ &amp;PrefToken::CommentLine(ref data_a, _), &gt;+ ) =&gt; data_e == data_a, &gt;+ ( &gt;+ &amp;PrefToken::CommentBashLine(ref data_e, _), &gt;+ &amp;PrefToken::CommentBashLine(ref data_a, _), &gt;+ ) =&gt; data_e == data_a, &gt;+ (&amp;PrefToken::Paren(data_e, _), &amp;PrefToken::Paren(data_a, _)) =&gt; data_e == data_a, &gt;+ (&amp;PrefToken::Semicolon(_), &amp;PrefToken::Semicolon(_)) =&gt; true, &gt;+ (&amp;PrefToken::Comma(_), &amp;PrefToken::Comma(_)) =&gt; true, &gt;+ (&amp;PrefToken::String(ref data_e, _), &amp;PrefToken::String(ref data_a, _)) =&gt; { &gt;+ data_e == data_a &gt;+ } &gt;+ (&amp;PrefToken::Int(data_e, _), &amp;PrefToken::Int(data_a, _)) =&gt; data_e == data_a, &gt;+ (&amp;PrefToken::Bool(data_e, _), &amp;PrefToken::Bool(data_a, _)) =&gt; data_e == data_a, &gt;+ (&amp;PrefToken::Error(data_e, _), &amp;PrefToken::Error(data_a, _)) =&gt; data_e == data_a, &gt;+ (_, _) =&gt; false, &gt; }; &gt; if !success { &gt; println!("Expected {:?}, got {:?}", e, a); &gt; } &gt; assert!(success); &gt; } &gt; } &gt; &gt;@@ -172,17 +159,17 @@ mod test { &gt; println!("Expected:\n{:?}\nActual\n{:?}", expected, actual); &gt; assert_eq!(actual, &amp;expected); &gt; } &gt; Err(e) =&gt; { &gt; println!("{}", e.description()); &gt; assert!(false) &gt; } &gt; } &gt;- } &gt;+ } &gt; &gt; #[test] &gt; fn serialize_simple() { &gt; let input = " user_pref /* block comment */ ( 'example.pref.string', 'value' ) ;\n pref(\"example.pref.int\", -123); sticky_pref('example.pref.bool',false)"; &gt; let expected = "sticky_pref(\"example.pref.bool\", false); &gt; user_pref(\"example.pref.int\", -123); &gt; user_pref(\"example.pref.string\", \"value\");\n"; &gt; &gt;diff --git a/testing/mozbase/rust/mozprofile/src/preferences.rs b/testing/mozbase/rust/mozprofile/src/preferences.rs &gt;index 619b708fee11..ee9c24510ba5 100644 &gt;--- a/testing/mozbase/rust/mozprofile/src/preferences.rs &gt;+++ b/testing/mozbase/rust/mozprofile/src/preferences.rs &gt;@@ -107,17 +107,20 @@ mod test { &gt; #[test] &gt; fn test_bool() { &gt; assert_eq!(PrefValue::from(true), PrefValue::Bool(true)); &gt; } &gt; &gt; #[test] &gt; fn test_string() { &gt; assert_eq!(PrefValue::from("foo"), PrefValue::String("foo".to_string())); &gt;- assert_eq!(PrefValue::from("foo".to_string()), PrefValue::String("foo".to_string())); &gt;+ assert_eq!( &gt;+ PrefValue::from("foo".to_string()), &gt;+ PrefValue::String("foo".to_string()) &gt;+ ); &gt; } &gt; &gt; #[test] &gt; fn test_int() { &gt; assert_eq!(PrefValue::from(42i8), PrefValue::Int(42i64)); &gt; assert_eq!(PrefValue::from(42u8), PrefValue::Int(42i64)); &gt; assert_eq!(PrefValue::from(42i16), PrefValue::Int(42i64)); &gt; assert_eq!(PrefValue::from(42u16), PrefValue::Int(42i64)); &gt;diff --git a/testing/mozbase/rust/mozprofile/src/prefreader.rs b/testing/mozbase/rust/mozprofile/src/prefreader.rs &gt;index ba2507cdbc50..30c5cf188929 100644 &gt;--- a/testing/mozbase/rust/mozprofile/src/prefreader.rs &gt;+++ b/testing/mozbase/rust/mozprofile/src/prefreader.rs &gt;@@ -1,57 +1,60 @@ &gt; use preferences::{Pref, PrefValue, Preferences}; &gt; use std::borrow::Borrow; &gt; use std::borrow::Cow; &gt; use std::char; &gt; use std::error::Error; &gt; use std::fmt; &gt; use std::io::{self, Write}; &gt; use std::iter::Iterator; &gt;-use std::str; &gt; use std::mem; &gt; use std::ops::Deref; &gt;+use std::str; &gt; &gt; impl PrefReaderError { &gt;- fn new(message: &amp;'static str, position: Position, parent: Option&lt;Box&lt;Error&gt;&gt;) -&gt; PrefReaderError { &gt;+ fn new( &gt;+ message: &amp;'static str, &gt;+ position: Position, &gt;+ parent: Option&lt;Box&lt;Error&gt;&gt;, &gt;+ ) -&gt; PrefReaderError { &gt; PrefReaderError { &gt; message: message, &gt; position: position, &gt;- parent: parent &gt;+ parent: parent, &gt; } &gt; } &gt; } &gt; &gt;- &gt; impl fmt::Display for PrefReaderError { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt;- write!(f, "{} at line {}, column {}", &gt;- self.message, self.position.line, self.position.column) &gt;+ write!( &gt;+ f, &gt;+ "{} at line {}, column {}", &gt;+ self.message, self.position.line, self.position.column &gt;+ ) &gt; } &gt; } &gt; &gt;- &gt; impl Error for PrefReaderError { &gt; fn description(&amp;self) -&gt; &amp;str { &gt; self.message &gt; } &gt; &gt; fn cause(&amp;self) -&gt; Option&lt;&amp;Error&gt; { &gt; match self.parent { &gt; None =&gt; None, &gt;- Some(ref cause) =&gt; Some(cause.deref()) &gt;+ Some(ref cause) =&gt; Some(cause.deref()), &gt; } &gt; } &gt; } &gt; &gt; impl From&lt;io::Error&gt; for PrefReaderError { &gt; fn from(err: io::Error) -&gt; PrefReaderError { &gt;- PrefReaderError::new("IOError", &gt;- Position::new(), &gt;- Some(err.into())) &gt;+ PrefReaderError::new("IOError", Position::new(), Some(err.into())) &gt; } &gt; } &gt; &gt; #[derive(Copy, Clone, Debug, PartialEq)] &gt; enum TokenizerState { &gt; Junk, &gt; CommentStart, &gt; CommentLine, &gt;@@ -67,25 +70,22 @@ enum TokenizerState { &gt; AfterFunctionArg, &gt; AfterFunction, &gt; Error, &gt; } &gt; &gt; #[derive(Copy, Clone, Debug, PartialEq)] &gt; pub struct Position { &gt; line: u32, &gt;- column: u32 &gt;+ column: u32, &gt; } &gt; &gt; impl Position { &gt; pub fn new() -&gt; Position { &gt;- Position { &gt;- line: 1, &gt;- column: 0 &gt;- } &gt;+ Position { line: 1, column: 0 } &gt; } &gt; } &gt; &gt; #[derive(Copy, Clone, Debug, PartialEq)] &gt; pub enum TokenType { &gt; None, &gt; PrefFunction, &gt; UserPrefFunction, &gt;@@ -94,34 +94,34 @@ pub enum TokenType { &gt; CommentLine, &gt; CommentBashLine, &gt; Paren, &gt; Semicolon, &gt; Comma, &gt; String, &gt; Int, &gt; Bool, &gt;- Error &gt;+ Error, &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum PrefToken&lt;'a&gt; { &gt; PrefFunction(Position), &gt; UserPrefFunction(Position), &gt; StickyPrefFunction(Position), &gt; CommentBlock(Cow&lt;'a, str&gt;, Position), &gt; CommentLine(Cow&lt;'a, str&gt;, Position), &gt; CommentBashLine(Cow&lt;'a, str&gt;, Position), &gt; Paren(char, Position), &gt; Semicolon(Position), &gt; Comma(Position), &gt; String(Cow&lt;'a, str&gt;, Position), &gt; Int(i64, Position), &gt; Bool(bool, Position), &gt;- Error(&amp;'static str, Position) &gt;+ Error(&amp;'static str, Position), &gt; } &gt; &gt; impl&lt;'a&gt; PrefToken&lt;'a&gt; { &gt; fn position(&amp;self) -&gt; Position { &gt; match *self { &gt; PrefToken::PrefFunction(position) =&gt; position, &gt; PrefToken::UserPrefFunction(position) =&gt; position, &gt; PrefToken::StickyPrefFunction(position) =&gt; position, &gt;@@ -129,26 +129,26 @@ impl&lt;'a&gt; PrefToken&lt;'a&gt; { &gt; PrefToken::CommentLine(_, position) =&gt; position, &gt; PrefToken::CommentBashLine(_, position) =&gt; position, &gt; PrefToken::Paren(_, position) =&gt; position, &gt; PrefToken::Semicolon(position) =&gt; position, &gt; PrefToken::Comma(position) =&gt; position, &gt; PrefToken::String(_, position) =&gt; position, &gt; PrefToken::Int(_, position) =&gt; position, &gt; PrefToken::Bool(_, position) =&gt; position, &gt;- PrefToken::Error(_, position) =&gt; position &gt;+ PrefToken::Error(_, position) =&gt; position, &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug)] &gt; pub struct PrefReaderError { &gt; message: &amp;'static str, &gt; position: Position, &gt;- parent: Option&lt;Box&lt;Error&gt;&gt; &gt;+ parent: Option&lt;Box&lt;Error&gt;&gt;, &gt; } &gt; &gt; struct TokenData&lt;'a&gt; { &gt; token_type: TokenType, &gt; complete: bool, &gt; position: Position, &gt; data: Cow&lt;'a, str&gt;, &gt; start_pos: usize, &gt;@@ -175,18 +175,21 @@ impl&lt;'a&gt; TokenData&lt;'a&gt; { &gt; self.complete = true; &gt; self.add_slice_to_token(buf, end_pos) &gt; } &gt; &gt; fn add_slice_to_token(&amp;mut self, buf: &amp;'a [u8], end_pos: usize) -&gt; Result&lt;(), PrefReaderError&gt; { &gt; let data = match str::from_utf8(&amp;buf[self.start_pos..end_pos]) { &gt; Ok(x) =&gt; x, &gt; Err(_) =&gt; { &gt;- return Err(PrefReaderError::new("Could not convert string to utf8", &gt;- self.position, None)); &gt;+ return Err(PrefReaderError::new( &gt;+ "Could not convert string to utf8", &gt;+ self.position, &gt;+ None, &gt;+ )); &gt; } &gt; }; &gt; if self.data != "" { &gt; self.data.to_mut().push_str(&amp;data) &gt; } else { &gt; self.data = Cow::Borrowed(&amp;data) &gt; }; &gt; Ok(()) &gt;@@ -230,41 +233,41 @@ impl&lt;'a&gt; PrefTokenizer&lt;'a&gt; { &gt; TokenType::CommentBlock =&gt; PrefToken::CommentBlock(buf, position), &gt; TokenType::CommentLine =&gt; PrefToken::CommentLine(buf, position), &gt; TokenType::CommentBashLine =&gt; PrefToken::CommentBashLine(buf, position), &gt; TokenType::Paren =&gt; { &gt; if buf.len() != 1 { &gt; panic!("Expected a buffer of length one"); &gt; } &gt; PrefToken::Paren(buf.chars().next().unwrap(), position) &gt;- }, &gt;+ } &gt; TokenType::Semicolon =&gt; PrefToken::Semicolon(position), &gt; TokenType::Comma =&gt; PrefToken::Comma(position), &gt; TokenType::String =&gt; PrefToken::String(buf, position), &gt; TokenType::Int =&gt; { &gt;- let value = i64::from_str_radix(buf.borrow(), 10) &gt;- .expect("Integer wasn't parsed as an i64"); &gt;+ let value = &gt;+ i64::from_str_radix(buf.borrow(), 10).expect("Integer wasn't parsed as an i64"); &gt; PrefToken::Int(value, position) &gt;- }, &gt;+ } &gt; TokenType::Bool =&gt; { &gt; let value = match buf.borrow() { &gt; "true" =&gt; true, &gt; "false" =&gt; false, &gt;- x =&gt; panic!(format!("Boolean wasn't 'true' or 'false' (was {})", x)) &gt;+ x =&gt; panic!(format!("Boolean wasn't 'true' or 'false' (was {})", x)), &gt; }; &gt; PrefToken::Bool(value, position) &gt;- }, &gt;- TokenType::Error =&gt; panic!("make_token can't construct errors") &gt;+ } &gt;+ TokenType::Error =&gt; panic!("make_token can't construct errors"), &gt; } &gt; } &gt; &gt; fn get_char(&amp;mut self) -&gt; Option&lt;char&gt; { &gt; if self.pos &gt;= self.data.len() - 1 { &gt; self.cur = None; &gt;- return None &gt;+ return None; &gt; }; &gt; if self.cur.is_some() { &gt; self.pos += 1; &gt; } &gt; let c = self.data[self.pos] as char; &gt; if self.cur == Some('\n') { &gt; self.position.line += 1; &gt; self.position.column = 0; &gt;@@ -295,26 +298,26 @@ impl&lt;'a&gt; PrefTokenizer&lt;'a&gt; { &gt; self.cur = Some(c); &gt; } &gt; self.cur &gt; } &gt; &gt; fn is_space(c: char) -&gt; bool { &gt; match c { &gt; ' ' | '\t' | '\r' | '\n' =&gt; true, &gt;- _ =&gt; false &gt;+ _ =&gt; false, &gt; } &gt; } &gt; &gt; fn skip_whitespace(&amp;mut self) -&gt; Option&lt;char&gt; { &gt; while let Some(c) = self.cur { &gt; if PrefTokenizer::is_space(c) { &gt; self.get_char(); &gt; } else { &gt;- break &gt;+ break; &gt; }; &gt; } &gt; self.cur &gt; } &gt; &gt; fn consume_escape(&amp;mut self, token_data: &amp;mut TokenData&lt;'a&gt;) -&gt; Result&lt;(), PrefReaderError&gt; { &gt; let pos = self.pos; &gt; let escaped = try!(self.read_escape()); &gt;@@ -330,62 +333,84 @@ impl&lt;'a&gt; PrefTokenizer&lt;'a&gt; { &gt; Some('u') =&gt; try!(self.read_hex_escape(4, true)), &gt; Some('x') =&gt; try!(self.read_hex_escape(2, true)), &gt; Some('\\') =&gt; '\\' as u32, &gt; Some('"') =&gt; '"' as u32, &gt; Some('\'') =&gt; '\'' as u32, &gt; Some('r') =&gt; '\r' as u32, &gt; Some('n') =&gt; '\n' as u32, &gt; Some(_) =&gt; return Ok(None), &gt;- None =&gt; return Err(PrefReaderError::new("EOF in character escape", &gt;- self.position, None)) &gt;+ None =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "EOF in character escape", &gt;+ self.position, &gt;+ None, &gt;+ )) &gt;+ } &gt; }; &gt;- Ok(Some(try!(char::from_u32(escape_char) &gt;- .ok_or(PrefReaderError::new("Invalid codepoint decoded from escape", &gt;- self.position, None))))) &gt;+ Ok(Some(try!(char::from_u32(escape_char).ok_or( &gt;+ PrefReaderError::new("Invalid codepoint decoded from escape", self.position, None) &gt;+ )))) &gt; } &gt; &gt; fn read_hex_escape(&amp;mut self, hex_chars: isize, first: bool) -&gt; Result&lt;u32, PrefReaderError&gt; { &gt; let mut value = 0; &gt; for _ in 0..hex_chars { &gt; match self.get_char() { &gt; Some(x) =&gt; { &gt; value = value &lt;&lt; 4; &gt; match x { &gt; '0'...'9' =&gt; value += x as u32 - '0' as u32, &gt; 'a'...'f' =&gt; value += x as u32 - 'a' as u32, &gt; 'A'...'F' =&gt; value += x as u32 - 'A' as u32, &gt;- _ =&gt; return Err(PrefReaderError::new( &gt;- "Unexpected character in escape", self.position, None)) &gt;+ _ =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "Unexpected character in escape", &gt;+ self.position, &gt;+ None, &gt;+ )) &gt;+ } &gt; } &gt;- }, &gt;- None =&gt; return Err(PrefReaderError::new( &gt;- "Unexpected EOF in escape", self.position, None)) &gt;+ } &gt;+ None =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "Unexpected EOF in escape", &gt;+ self.position, &gt;+ None, &gt;+ )) &gt;+ } &gt; } &gt; } &gt; if first &amp;&amp; value &gt;= 0xD800 &amp;&amp; value &lt;= 0xDBFF { &gt; // First part of a surrogate pair &gt; if self.get_char() != Some('\\') || self.get_char() != Some('u') { &gt;- return Err(PrefReaderError::new("Lone high surrogate in surrogate pair", &gt;- self.position, None)) &gt;+ return Err(PrefReaderError::new( &gt;+ "Lone high surrogate in surrogate pair", &gt;+ self.position, &gt;+ None, &gt;+ )); &gt; } &gt; self.unget_char(); &gt; let high_surrogate = value; &gt; let low_surrogate = try!(self.read_hex_escape(4, false)); &gt; let high_value = (high_surrogate - 0xD800) &lt;&lt; 10; &gt; let low_value = low_surrogate - 0xDC00; &gt; value = high_value + low_value + 0x10000; &gt; } else if first &amp;&amp; value &gt;= 0xDC00 &amp;&amp; value &lt;= 0xDFFF { &gt;- return Err(PrefReaderError::new("Lone low surrogate", &gt;- self.position, &gt;- None)) &gt;+ return Err(PrefReaderError::new( &gt;+ "Lone low surrogate", &gt;+ self.position, &gt;+ None, &gt;+ )); &gt; } else if !first &amp;&amp; (value &lt; 0xDC00 || value &gt; 0xDFFF) { &gt;- return Err(PrefReaderError::new("Invalid low surrogate in surrogate pair", &gt;- self.position, &gt;- None)); &gt;+ return Err(PrefReaderError::new( &gt;+ "Invalid low surrogate in surrogate pair", &gt;+ self.position, &gt;+ None, &gt;+ )); &gt; } &gt; Ok(value) &gt; } &gt; &gt; fn get_match(&amp;mut self, target: &amp;str, separators: &amp;str) -&gt; bool { &gt; let initial_pos = self.pos; &gt; let mut matched = true; &gt; for c in target.chars() { &gt;@@ -415,300 +440,303 @@ impl&lt;'a&gt; PrefTokenizer&lt;'a&gt; { &gt; } &gt; &gt; fn next_token(&amp;mut self) -&gt; Result&lt;Option&lt;TokenData&lt;'a&gt;&gt;, PrefReaderError&gt; { &gt; let mut token_data = TokenData::new(TokenType::None, Position::new(), 0); &gt; &gt; loop { &gt; let mut c = match self.get_char() { &gt; Some(x) =&gt; x, &gt;- None =&gt; return Ok(None) &gt;+ None =&gt; return Ok(None), &gt; }; &gt; &gt; self.state = match self.state { &gt; TokenizerState::Junk =&gt; { &gt; c = match self.skip_whitespace() { &gt; Some(x) =&gt; x, &gt;- None =&gt; return Ok(None) &gt;+ None =&gt; return Ok(None), &gt; }; &gt; match c { &gt; '/' =&gt; TokenizerState::CommentStart, &gt; '#' =&gt; { &gt; token_data.start(&amp;self, TokenType::CommentBashLine); &gt; token_data.start_pos = self.pos + 1; &gt; TokenizerState::CommentLine &gt;- }, &gt;+ } &gt; _ =&gt; { &gt; self.unget_char(); &gt; let next = match self.next_state { &gt; Some(x) =&gt; x, &gt; None =&gt; { &gt; return Err(PrefReaderError::new( &gt; "In Junk state without a next state defined", &gt; self.position, &gt;- None)) &gt;+ None, &gt;+ )) &gt; } &gt; }; &gt; self.next_state = None; &gt; next &gt; } &gt; } &gt;+ } &gt;+ TokenizerState::CommentStart =&gt; match c { &gt;+ '*' =&gt; { &gt;+ token_data.start(&amp;self, TokenType::CommentBlock); &gt;+ token_data.start_pos = self.pos + 1; &gt;+ TokenizerState::CommentBlock &gt;+ } &gt;+ '/' =&gt; { &gt;+ token_data.start(&amp;self, TokenType::CommentLine); &gt;+ token_data.start_pos = self.pos + 1; &gt;+ TokenizerState::CommentLine &gt;+ } &gt;+ _ =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "Invalid character after /", &gt;+ self.position, &gt;+ None, &gt;+ )) &gt;+ } &gt; }, &gt;- TokenizerState::CommentStart =&gt; { &gt;- match c { &gt;- '*' =&gt; { &gt;- token_data.start(&amp;self, TokenType::CommentBlock); &gt;- token_data.start_pos = self.pos + 1; &gt;+ TokenizerState::CommentLine =&gt; match c { &gt;+ '\n' =&gt; { &gt;+ try!(token_data.end(&amp;self.data, self.pos)); &gt;+ TokenizerState::Junk &gt;+ } &gt;+ _ =&gt; TokenizerState::CommentLine, &gt;+ }, &gt;+ TokenizerState::CommentBlock =&gt; match c { &gt;+ '*' =&gt; { &gt;+ if self.get_char() == Some('/') { &gt;+ try!(token_data.end(&amp;self.data, self.pos - 1)); &gt;+ TokenizerState::Junk &gt;+ } else { &gt; TokenizerState::CommentBlock &gt;- }, &gt;- '/' =&gt; { &gt;- token_data.start(&amp;self, TokenType::CommentLine); &gt;- token_data.start_pos = self.pos + 1; &gt;- TokenizerState::CommentLine &gt;- }, &gt;- _ =&gt; { &gt;- return Err(PrefReaderError::new( &gt;- "Invalid character after /", self.position, None)) &gt; } &gt; } &gt;- &gt;- }, &gt;- TokenizerState::CommentLine =&gt; { &gt;- match c { &gt;- '\n' =&gt; { &gt;- try!(token_data.end(&amp;self.data, self.pos)); &gt;- TokenizerState::Junk &gt;- }, &gt;- _ =&gt; { &gt;- TokenizerState::CommentLine &gt;- } &gt;- } &gt;- }, &gt;- TokenizerState::CommentBlock =&gt; { &gt;- match c { &gt;- '*' =&gt; { &gt;- if self.get_char() == Some('/') { &gt;- try!(token_data.end(&amp;self.data, self.pos - 1)); &gt;- TokenizerState::Junk &gt;- } else { &gt;- TokenizerState::CommentBlock &gt;- } &gt;- }, &gt;- _ =&gt; TokenizerState::CommentBlock &gt;- } &gt;+ _ =&gt; TokenizerState::CommentBlock, &gt; }, &gt; TokenizerState::FunctionName =&gt; { &gt; let position = self.position; &gt; let start_pos = self.pos; &gt; match c { &gt; 'u' =&gt; { &gt; if self.get_match("user_pref", "(") { &gt; token_data.start(&amp;self, TokenType::UserPrefFunction); &gt; } &gt;- }, &gt;+ } &gt; 's' =&gt; { &gt; if self.get_match("sticky_pref", "(") { &gt; token_data.start(&amp;self, TokenType::StickyPrefFunction); &gt; } &gt; } &gt; 'p' =&gt; { &gt; if self.get_match("pref", "(") { &gt; token_data.start(&amp;self, TokenType::PrefFunction); &gt; } &gt;- }, &gt;+ } &gt; _ =&gt; {} &gt; }; &gt; if token_data.token_type == TokenType::None { &gt; // We didn't match anything &gt; return Err(PrefReaderError::new( &gt;- "Expected a pref function name", position, None)) &gt;+ "Expected a pref function name", &gt;+ position, &gt;+ None, &gt;+ )); &gt; } else { &gt; token_data.start_pos = start_pos; &gt; token_data.position = position; &gt; try!(token_data.end(&amp;self.data, self.pos + 1)); &gt; self.next_state = Some(TokenizerState::AfterFunctionName); &gt; TokenizerState::Junk &gt; } &gt;- }, &gt;- TokenizerState::AfterFunctionName =&gt; { &gt;- match c { &gt;- '(' =&gt; { &gt;- self.next_state = Some(TokenizerState::FunctionArgs); &gt;- token_data.start(&amp;self, TokenType::Paren); &gt;- try!(token_data.end(&amp;self.data, self.pos + 1)); &gt;- self.next_state = Some(TokenizerState::FunctionArgs); &gt;- TokenizerState::Junk &gt;- }, &gt;- _ =&gt; { &gt;- return Err(PrefReaderError::new( &gt;- "Expected an opening paren", self.position, None)) &gt;- } &gt;+ } &gt;+ TokenizerState::AfterFunctionName =&gt; match c { &gt;+ '(' =&gt; { &gt;+ self.next_state = Some(TokenizerState::FunctionArgs); &gt;+ token_data.start(&amp;self, TokenType::Paren); &gt;+ try!(token_data.end(&amp;self.data, self.pos + 1)); &gt;+ self.next_state = Some(TokenizerState::FunctionArgs); &gt;+ TokenizerState::Junk &gt;+ } &gt;+ _ =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "Expected an opening paren", &gt;+ self.position, &gt;+ None, &gt;+ )) &gt; } &gt; }, &gt;- TokenizerState::FunctionArgs =&gt; { &gt;- match c { &gt;- ')' =&gt; { &gt;- token_data.start(&amp;self, TokenType::Paren); &gt;- try!(token_data.end(&amp;self.data, self.pos + 1)); &gt;- self.next_state = Some(TokenizerState::AfterFunction); &gt;- TokenizerState::Junk &gt;- }, &gt;- _ =&gt; { &gt;- self.unget_char(); &gt;- TokenizerState::FunctionArg &gt;- } &gt;+ TokenizerState::FunctionArgs =&gt; match c { &gt;+ ')' =&gt; { &gt;+ token_data.start(&amp;self, TokenType::Paren); &gt;+ try!(token_data.end(&amp;self.data, self.pos + 1)); &gt;+ self.next_state = Some(TokenizerState::AfterFunction); &gt;+ TokenizerState::Junk &gt;+ } &gt;+ _ =&gt; { &gt;+ self.unget_char(); &gt;+ TokenizerState::FunctionArg &gt; } &gt; }, &gt;- TokenizerState::FunctionArg =&gt; { &gt;- match c { &gt;- '"' =&gt; { &gt;- token_data.start(&amp;self, TokenType::String); &gt;- token_data.start_pos = self.pos + 1; &gt;- TokenizerState::DoubleQuotedString &gt;- }, &gt;- '\'' =&gt; { &gt;- token_data.start(&amp;self, TokenType::String); &gt;- token_data.start_pos = self.pos + 1; &gt;- TokenizerState::SingleQuotedString &gt;- }, &gt;- 't' | 'f' =&gt; { &gt;- self.unget_char(); &gt;- TokenizerState::Bool &gt;- }, &gt;- '0'...'9' | '-' |'+' =&gt; { &gt;- token_data.start(&amp;self, TokenType::Int); &gt;- TokenizerState::Number &gt;- }, &gt;- _ =&gt; { &gt;- return Err(PrefReaderError::new( &gt;- "Invalid character at start of function argument", &gt;- self.position, None)) &gt;- } &gt;+ TokenizerState::FunctionArg =&gt; match c { &gt;+ '"' =&gt; { &gt;+ token_data.start(&amp;self, TokenType::String); &gt;+ token_data.start_pos = self.pos + 1; &gt;+ TokenizerState::DoubleQuotedString &gt;+ } &gt;+ '\'' =&gt; { &gt;+ token_data.start(&amp;self, TokenType::String); &gt;+ token_data.start_pos = self.pos + 1; &gt;+ TokenizerState::SingleQuotedString &gt;+ } &gt;+ 't' | 'f' =&gt; { &gt;+ self.unget_char(); &gt;+ TokenizerState::Bool &gt;+ } &gt;+ '0'...'9' | '-' | '+' =&gt; { &gt;+ token_data.start(&amp;self, TokenType::Int); &gt;+ TokenizerState::Number &gt;+ } &gt;+ _ =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "Invalid character at start of function argument", &gt;+ self.position, &gt;+ None, &gt;+ )) &gt; } &gt; }, &gt;- TokenizerState::DoubleQuotedString =&gt; { &gt;- match c { &gt;- '"' =&gt; { &gt;- try!(token_data.end(&amp;self.data, self.pos)); &gt;- self.next_state = Some(TokenizerState::AfterFunctionArg); &gt;- TokenizerState::Junk &gt;- &gt;- }, &gt;- '\n' =&gt; { &gt;- return Err(PrefReaderError::new( &gt;- "EOL in double quoted string", self.position, None)) &gt;- }, &gt;- '\\' =&gt; { &gt;- try!(self.consume_escape(&amp;mut token_data)); &gt;- TokenizerState::DoubleQuotedString &gt;- }, &gt;- _ =&gt; TokenizerState::DoubleQuotedString &gt;+ TokenizerState::DoubleQuotedString =&gt; match c { &gt;+ '"' =&gt; { &gt;+ try!(token_data.end(&amp;self.data, self.pos)); &gt;+ self.next_state = Some(TokenizerState::AfterFunctionArg); &gt;+ TokenizerState::Junk &gt; } &gt;+ '\n' =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "EOL in double quoted string", &gt;+ self.position, &gt;+ None, &gt;+ )) &gt;+ } &gt;+ '\\' =&gt; { &gt;+ try!(self.consume_escape(&amp;mut token_data)); &gt;+ TokenizerState::DoubleQuotedString &gt;+ } &gt;+ _ =&gt; TokenizerState::DoubleQuotedString, &gt; }, &gt;- TokenizerState::SingleQuotedString =&gt; { &gt;- match c { &gt;- '\'' =&gt; { &gt;- try!(token_data.end(&amp;self.data, self.pos)); &gt;- self.next_state = Some(TokenizerState::AfterFunctionArg); &gt;- TokenizerState::Junk &gt;- &gt;- }, &gt;- '\n' =&gt; { &gt;- return Err(PrefReaderError::new( &gt;- "EOL in single quoted string", self.position, None)) &gt;- }, &gt;- '\\' =&gt; { &gt;- try!(self.consume_escape(&amp;mut token_data)); &gt;- TokenizerState::SingleQuotedString &gt;- } &gt;- _ =&gt; TokenizerState::SingleQuotedString &gt;+ TokenizerState::SingleQuotedString =&gt; match c { &gt;+ '\'' =&gt; { &gt;+ try!(token_data.end(&amp;self.data, self.pos)); &gt;+ self.next_state = Some(TokenizerState::AfterFunctionArg); &gt;+ TokenizerState::Junk &gt;+ } &gt;+ '\n' =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "EOL in single quoted string", &gt;+ self.position, &gt;+ None, &gt;+ )) &gt; } &gt;+ '\\' =&gt; { &gt;+ try!(self.consume_escape(&amp;mut token_data)); &gt;+ TokenizerState::SingleQuotedString &gt;+ } &gt;+ _ =&gt; TokenizerState::SingleQuotedString, &gt; }, &gt;- TokenizerState::Number =&gt; { &gt;- match c { &gt;- '0'...'9' =&gt; TokenizerState::Number, &gt;- ')' | ',' =&gt; { &gt;- try!(token_data.end(&amp;self.data, self.pos)); &gt;- self.unget_char(); &gt;- self.next_state = Some(TokenizerState::AfterFunctionArg); &gt;- TokenizerState::Junk &gt;- }, &gt;- x if PrefTokenizer::is_space(x) =&gt; { &gt;- try!(token_data.end(&amp;self.data, self.pos)); &gt;- self.next_state = Some(TokenizerState::AfterFunctionArg); &gt;- TokenizerState::Junk &gt;- }, &gt;- _ =&gt; { &gt;- return Err(PrefReaderError::new( &gt;- "Invalid character in number literal", self.position, None)) &gt;- } &gt;+ TokenizerState::Number =&gt; match c { &gt;+ '0'...'9' =&gt; TokenizerState::Number, &gt;+ ')' | ',' =&gt; { &gt;+ try!(token_data.end(&amp;self.data, self.pos)); &gt;+ self.unget_char(); &gt;+ self.next_state = Some(TokenizerState::AfterFunctionArg); &gt;+ TokenizerState::Junk &gt;+ } &gt;+ x if PrefTokenizer::is_space(x) =&gt; { &gt;+ try!(token_data.end(&amp;self.data, self.pos)); &gt;+ self.next_state = Some(TokenizerState::AfterFunctionArg); &gt;+ TokenizerState::Junk &gt;+ } &gt;+ _ =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "Invalid character in number literal", &gt;+ self.position, &gt;+ None, &gt;+ )) &gt; } &gt; }, &gt; TokenizerState::Bool =&gt; { &gt; let start_pos = self.pos; &gt; let position = self.position; &gt; match c { &gt; 't' =&gt; { &gt; if self.get_match("true", ",)") { &gt; token_data.start(&amp;self, TokenType::Bool) &gt; } &gt;- }, &gt;+ } &gt; 'f' =&gt; { &gt; if self.get_match("false", ",)") { &gt; token_data.start(&amp;self, TokenType::Bool) &gt; } &gt; } &gt; _ =&gt; {} &gt; }; &gt; if token_data.token_type == TokenType::None { &gt; return Err(PrefReaderError::new( &gt; "Unexpected characters in function argument", &gt;- position, None)); &gt;+ position, &gt;+ None, &gt;+ )); &gt; } else { &gt; token_data.start_pos = start_pos; &gt; token_data.position = position; &gt; try!(token_data.end(&amp;self.data, self.pos + 1)); &gt; self.next_state = Some(TokenizerState::AfterFunctionArg); &gt; TokenizerState::Junk &gt; } &gt;- }, &gt;- TokenizerState::AfterFunctionArg =&gt; { &gt;- match c { &gt;- ',' =&gt; { &gt;- token_data.start(&amp;self, TokenType::Comma); &gt;- try!(token_data.end(&amp;self.data, self.pos + 1)); &gt;- self.next_state = Some(TokenizerState::FunctionArg); &gt;- TokenizerState::Junk &gt;- } &gt;- ')' =&gt; { &gt;- token_data.start(&amp;self, TokenType::Paren); &gt;- try!(token_data.end(&amp;self.data, self.pos + 1)); &gt;- self.next_state = Some(TokenizerState::AfterFunction); &gt;- TokenizerState::Junk &gt;- } &gt;- _ =&gt; return Err(PrefReaderError::new &gt;- ("Unexpected character after function argument", &gt;- self.position, &gt;- None)) &gt;+ } &gt;+ TokenizerState::AfterFunctionArg =&gt; match c { &gt;+ ',' =&gt; { &gt;+ token_data.start(&amp;self, TokenType::Comma); &gt;+ try!(token_data.end(&amp;self.data, self.pos + 1)); &gt;+ self.next_state = Some(TokenizerState::FunctionArg); &gt;+ TokenizerState::Junk &gt;+ } &gt;+ ')' =&gt; { &gt;+ token_data.start(&amp;self, TokenType::Paren); &gt;+ try!(token_data.end(&amp;self.data, self.pos + 1)); &gt;+ self.next_state = Some(TokenizerState::AfterFunction); &gt;+ TokenizerState::Junk &gt;+ } &gt;+ _ =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "Unexpected character after function argument", &gt;+ self.position, &gt;+ None, &gt;+ )) &gt; } &gt; }, &gt;- TokenizerState::AfterFunction =&gt; { &gt;- match c { &gt;- ';' =&gt; { &gt;- token_data.start(&amp;self, TokenType::Semicolon); &gt;- try!(token_data.end(&amp;self.data, self.pos)); &gt;- self.next_state = Some(TokenizerState::FunctionName); &gt;- TokenizerState::Junk &gt;- } &gt;- _ =&gt; return Err(PrefReaderError::new( &gt;+ TokenizerState::AfterFunction =&gt; match c { &gt;+ ';' =&gt; { &gt;+ token_data.start(&amp;self, TokenType::Semicolon); &gt;+ try!(token_data.end(&amp;self.data, self.pos)); &gt;+ self.next_state = Some(TokenizerState::FunctionName); &gt;+ TokenizerState::Junk &gt;+ } &gt;+ _ =&gt; { &gt;+ return Err(PrefReaderError::new( &gt; "Unexpected character after function", &gt;- self.position, None)) &gt;+ self.position, &gt;+ None, &gt;+ )) &gt; } &gt; }, &gt;- TokenizerState::Error =&gt; TokenizerState::Error &gt;+ TokenizerState::Error =&gt; TokenizerState::Error, &gt; }; &gt; if token_data.complete { &gt; return Ok(Some(token_data)); &gt; } &gt; } &gt; } &gt; } &gt; &gt;@@ -717,20 +745,18 @@ impl&lt;'a&gt; Iterator for PrefTokenizer&lt;'a&gt; { &gt; &gt; fn next(&amp;mut self) -&gt; Option&lt;PrefToken&lt;'a&gt;&gt; { &gt; if let TokenizerState::Error = self.state { &gt; return None; &gt; } &gt; let token_data = match self.next_token() { &gt; Err(e) =&gt; { &gt; self.state = TokenizerState::Error; &gt;- return Some(PrefToken::Error(e.message, &gt;- e.position)) &gt;- &gt;- }, &gt;+ return Some(PrefToken::Error(e.message, e.position)); &gt;+ } &gt; Ok(Some(token_data)) =&gt; token_data, &gt; Ok(None) =&gt; return None, &gt; }; &gt; let token = self.make_token(token_data); &gt; Some(token) &gt; } &gt; } &gt; &gt;@@ -746,232 +772,252 @@ pub fn serialize_token&lt;T: Write&gt;(token: &amp;PrefToken, output: &amp;mut T) -&gt; Result&lt;() &gt; &amp;PrefToken::UserPrefFunction(_) =&gt; "user_pref", &gt; &amp;PrefToken::StickyPrefFunction(_) =&gt; "sticky_pref", &gt; &amp;PrefToken::CommentBlock(ref data, _) =&gt; { &gt; data_buf.reserve(data.len() + 4); &gt; data_buf.push_str("/*"); &gt; data_buf.push_str(data.borrow()); &gt; data_buf.push_str("*"); &gt; &amp;*data_buf &gt;- }, &gt;+ } &gt; &amp;PrefToken::CommentLine(ref data, _) =&gt; { &gt; data_buf.reserve(data.len() + 2); &gt; data_buf.push_str("//"); &gt; data_buf.push_str(data.borrow()); &gt; &amp;*data_buf &gt;- }, &gt;+ } &gt; &amp;PrefToken::CommentBashLine(ref data, _) =&gt; { &gt; data_buf.reserve(data.len() + 1); &gt; data_buf.push_str("#"); &gt; data_buf.push_str(data.borrow()); &gt; &amp;*data_buf &gt;- }, &gt;+ } &gt; &amp;PrefToken::Paren(data, _) =&gt; { &gt; data_buf.push(data); &gt; &amp;*data_buf &gt;- }, &gt;+ } &gt; &amp;PrefToken::Comma(_) =&gt; ",", &gt; &amp;PrefToken::Semicolon(_) =&gt; ";\n", &gt; &amp;PrefToken::String(ref data, _) =&gt; { &gt; data_buf.reserve(data.len() + 2); &gt; data_buf.push('"'); &gt; data_buf.push_str(escape_quote(data.borrow()).borrow()); &gt; data_buf.push('"'); &gt; &amp;*data_buf &gt;- }, &gt;+ } &gt; &amp;PrefToken::Int(data, _) =&gt; { &gt; data_buf.push_str(&amp;*data.to_string()); &gt; &amp;*data_buf &gt;- }, &gt;+ } &gt; &amp;PrefToken::Bool(data, _) =&gt; { &gt;- if data {"true"} else {"false"} &gt;- }, &gt;- &amp;PrefToken::Error(data, pos) =&gt; return Err(PrefReaderError::new(data, pos, None)) &gt;+ if data { &gt;+ "true" &gt;+ } else { &gt;+ "false" &gt;+ } &gt;+ } &gt;+ &amp;PrefToken::Error(data, pos) =&gt; return Err(PrefReaderError::new(data, pos, None)), &gt; }; &gt; try!(output.write(data.as_bytes())); &gt; Ok(()) &gt; } &gt; &gt; pub fn serialize_tokens&lt;'a, I, W&gt;(tokens: I, output: &amp;mut W) -&gt; Result&lt;(), PrefReaderError&gt; &gt;- where I: Iterator&lt;Item=&amp;'a PrefToken&lt;'a&gt;&gt;, W: Write { &gt;+where &gt;+ I: Iterator&lt;Item = &amp;'a PrefToken&lt;'a&gt;&gt;, &gt;+ W: Write, &gt;+{ &gt; for token in tokens { &gt; try!(serialize_token(token, output)); &gt; } &gt; Ok(()) &gt; } &gt; &gt; fn escape_quote&lt;'a&gt;(data: &amp;'a str) -&gt; Cow&lt;'a, str&gt; { &gt; // Not very efficient… &gt; if data.contains("\"") || data.contains("\\") { &gt;- let new_data = Cow::Owned(data &gt;- .replace(r#"\"#, r#"\\"#) &gt;- .replace(r#"""#, r#"\""#)); &gt;+ let new_data = Cow::Owned(data.replace(r#"\"#, r#"\\"#).replace(r#"""#, r#"\""#)); &gt; new_data &gt; } else { &gt; Cow::Borrowed(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; enum ParserState { &gt; Function, &gt; Key, &gt; Value, &gt; } &gt; &gt; struct PrefBuilder { &gt; key: Option&lt;String&gt;, &gt; value: Option&lt;PrefValue&gt;, &gt;- sticky: bool &gt;+ sticky: bool, &gt; } &gt; &gt; impl PrefBuilder { &gt; fn new() -&gt; PrefBuilder { &gt; PrefBuilder { &gt; key: None, &gt; value: None, &gt;- sticky: false &gt;+ sticky: false, &gt; } &gt; } &gt; } &gt; &gt;- &gt; fn skip_comments&lt;'a&gt;(tokenizer: &amp;mut PrefTokenizer&lt;'a&gt;) -&gt; Option&lt;PrefToken&lt;'a&gt;&gt; { &gt; loop { &gt; match tokenizer.next() { &gt;- Some(PrefToken::CommentBashLine(_, _)) | &gt;- Some(PrefToken::CommentBlock(_, _)) | &gt;- Some(PrefToken::CommentLine(_, _)) =&gt; {}, &gt;+ Some(PrefToken::CommentBashLine(_, _)) &gt;+ | Some(PrefToken::CommentBlock(_, _)) &gt;+ | Some(PrefToken::CommentLine(_, _)) =&gt; {} &gt; Some(x) =&gt; return Some(x), &gt; None =&gt; return None, &gt; } &gt; } &gt; } &gt; &gt;-pub fn parse_tokens&lt;'a&gt;(tokenizer: &amp;mut PrefTokenizer&lt;'a&gt;) -&gt; Result&lt;Preferences, &gt;- PrefReaderError&gt; { &gt;- &gt;+pub fn parse_tokens&lt;'a&gt;(tokenizer: &amp;mut PrefTokenizer&lt;'a&gt;) -&gt; Result&lt;Preferences, PrefReaderError&gt; { &gt; let mut state = ParserState::Function; &gt; let mut current_pref = PrefBuilder::new(); &gt; let mut rv = Preferences::new(); &gt; &gt; loop { &gt; // Not just using a for loop here seems strange, but this restricts the &gt; // scope of the borrow &gt; let token = { &gt; match tokenizer.next() { &gt; Some(x) =&gt; x, &gt;- None =&gt; break &gt;+ None =&gt; break, &gt; } &gt; }; &gt; // First deal with comments and errors &gt; match token { &gt; PrefToken::Error(msg, position) =&gt; { &gt; return Err(PrefReaderError::new(msg.into(), position, None)); &gt;- }, &gt;- PrefToken::CommentBashLine(_, _) | &gt;- PrefToken::CommentLine(_, _) | &gt;- PrefToken::CommentBlock(_, _) =&gt; { &gt;- continue &gt;- }, &gt;+ } &gt;+ PrefToken::CommentBashLine(_, _) &gt;+ | PrefToken::CommentLine(_, _) &gt;+ | PrefToken::CommentBlock(_, _) =&gt; continue, &gt; _ =&gt; {} &gt; } &gt; state = match state { &gt; ParserState::Function =&gt; { &gt; match token { &gt; PrefToken::PrefFunction(_) =&gt; { &gt; current_pref.sticky = false; &gt; } &gt; PrefToken::UserPrefFunction(_) =&gt; { &gt; current_pref.sticky = false; &gt;- }, &gt;+ } &gt; PrefToken::StickyPrefFunction(_) =&gt; { &gt; current_pref.sticky = true; &gt;- }, &gt;+ } &gt; _ =&gt; { &gt;- return Err(PrefReaderError::new("Expected pref function".into(), &gt;- token.position(), None)); &gt;+ return Err(PrefReaderError::new( &gt;+ "Expected pref function".into(), &gt;+ token.position(), &gt;+ None, &gt;+ )); &gt; } &gt; } &gt; let next = skip_comments(tokenizer); &gt; match next { &gt; Some(PrefToken::Paren('(', _)) =&gt; ParserState::Key, &gt;- _ =&gt; return Err(PrefReaderError::new("Expected open paren".into(), &gt;- next.map(|x| x.position()) &gt;- .unwrap_or(tokenizer.position), &gt;- None)) &gt;+ _ =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "Expected open paren".into(), &gt;+ next.map(|x| x.position()).unwrap_or(tokenizer.position), &gt;+ None, &gt;+ )) &gt;+ } &gt; } &gt;- }, &gt;+ } &gt; ParserState::Key =&gt; { &gt; match token { &gt; PrefToken::String(data, _) =&gt; current_pref.key = Some(data.into_owned()), &gt; _ =&gt; { &gt;- return Err(PrefReaderError::new("Expected string", token.position(), None)); &gt;+ return Err(PrefReaderError::new( &gt;+ "Expected string", &gt;+ token.position(), &gt;+ None, &gt;+ )); &gt; } &gt; } &gt; let next = skip_comments(tokenizer); &gt; match next { &gt; Some(PrefToken::Comma(_)) =&gt; ParserState::Value, &gt;- _ =&gt; return Err(PrefReaderError::new("Expected comma", &gt;- next.map(|x| x.position()) &gt;- .unwrap_or(tokenizer.position), &gt;- None)) &gt;+ _ =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "Expected comma", &gt;+ next.map(|x| x.position()).unwrap_or(tokenizer.position), &gt;+ None, &gt;+ )) &gt;+ } &gt; } &gt;- }, &gt;+ } &gt; ParserState::Value =&gt; { &gt; match token { &gt; PrefToken::String(data, _) =&gt; { &gt; current_pref.value = Some(PrefValue::String(data.into_owned())) &gt;- }, &gt;- PrefToken::Int(data, _) =&gt; { &gt;- current_pref.value = Some(PrefValue::Int(data)) &gt; } &gt;- PrefToken::Bool(data, _) =&gt; { &gt;- current_pref.value = Some(PrefValue::Bool(data)) &gt;- }, &gt;+ PrefToken::Int(data, _) =&gt; current_pref.value = Some(PrefValue::Int(data)), &gt;+ PrefToken::Bool(data, _) =&gt; current_pref.value = Some(PrefValue::Bool(data)), &gt; _ =&gt; { &gt;- return Err(PrefReaderError::new("Expected value", token.position(), &gt;- None)) &gt;+ return Err(PrefReaderError::new( &gt;+ "Expected value", &gt;+ token.position(), &gt;+ None, &gt;+ )) &gt; } &gt; } &gt; let next = skip_comments(tokenizer); &gt; match next { &gt; Some(PrefToken::Paren(')', _)) =&gt; {} &gt;- _ =&gt; return Err(PrefReaderError::new("Expected close paren", &gt;- next.map(|x| x.position()) &gt;- .unwrap_or(tokenizer.position), &gt;- None)) &gt;+ _ =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "Expected close paren", &gt;+ next.map(|x| x.position()).unwrap_or(tokenizer.position), &gt;+ None, &gt;+ )) &gt;+ } &gt; } &gt; let next = skip_comments(tokenizer); &gt; match next { &gt;- Some(PrefToken::Semicolon(_)) | &gt;- None =&gt; {}, &gt;- _ =&gt; return Err(PrefReaderError::new("Expected semicolon", &gt;- next.map(|x| x.position()) &gt;- .unwrap_or(tokenizer.position), &gt;- None)) &gt;+ Some(PrefToken::Semicolon(_)) | None =&gt; {} &gt;+ _ =&gt; { &gt;+ return Err(PrefReaderError::new( &gt;+ "Expected semicolon", &gt;+ next.map(|x| x.position()).unwrap_or(tokenizer.position), &gt;+ None, &gt;+ )) &gt;+ } &gt; } &gt; let key = mem::replace(&amp;mut current_pref.key, None); &gt; let value = mem::replace(&amp;mut current_pref.value, None); &gt; let pref = if current_pref.sticky { &gt; Pref::new_sticky(value.unwrap()) &gt; } else { &gt; Pref::new(value.unwrap()) &gt; }; &gt; rv.insert(key.unwrap(), pref); &gt; current_pref.sticky = false; &gt; ParserState::Function &gt;- }, &gt;+ } &gt; } &gt; } &gt; match state { &gt; ParserState::Key | ParserState::Value =&gt; { &gt;- return Err(PrefReaderError::new("EOF in middle of function", &gt;- tokenizer.position, None)); &gt;- }, &gt;+ return Err(PrefReaderError::new( &gt;+ "EOF in middle of function", &gt;+ tokenizer.position, &gt;+ None, &gt;+ )); &gt;+ } &gt; _ =&gt; {} &gt; } &gt; Ok(rv) &gt; } &gt; &gt; pub fn serialize&lt;W: Write&gt;(prefs: &amp;Preferences, output: &amp;mut W) -&gt; io::Result&lt;()&gt; { &gt; let mut p: Vec&lt;_&gt; = prefs.iter().collect(); &gt; p.sort_by(|a, b| a.0.cmp(&amp;b.0)); &gt;@@ -983,28 +1029,28 @@ pub fn serialize&lt;W: Write&gt;(prefs: &amp;Preferences, output: &amp;mut W) -&gt; io::Result&lt;() &gt; }.as_bytes(); &gt; try!(output.write(func)); &gt; try!(output.write("\"".as_bytes())); &gt; try!(output.write(escape_quote(key).as_bytes())); &gt; try!(output.write("\"".as_bytes())); &gt; try!(output.write(", ".as_bytes())); &gt; match pref.value { &gt; PrefValue::Bool(x) =&gt; { &gt;- try!(output.write((if x {"true"} else {"false"}).as_bytes())); &gt;- }, &gt;+ try!(output.write((if x { "true" } else { "false" }).as_bytes())); &gt;+ } &gt; PrefValue::Int(x) =&gt; { &gt; try!(output.write(x.to_string().as_bytes())); &gt;- }, &gt;+ } &gt; PrefValue::String(ref x) =&gt; { &gt; try!(output.write("\"".as_bytes())); &gt; try!(output.write(escape_quote(x).as_bytes())); &gt; try!(output.write("\"".as_bytes())); &gt; } &gt; }; &gt; try!(output.write(");\n".as_bytes())); &gt;- }; &gt;+ } &gt; Ok(()) &gt; } &gt; &gt; pub fn parse&lt;'a&gt;(data: &amp;'a [u8]) -&gt; Result&lt;Preferences, PrefReaderError&gt; { &gt; let mut tokenizer = tokenize(data); &gt; parse_tokens(&amp;mut tokenizer) &gt; } &gt;diff --git a/testing/mozbase/rust/mozprofile/src/profile.rs b/testing/mozbase/rust/mozprofile/src/profile.rs &gt;index d38f50d1fde6..87205d7db3de 100644 &gt;--- a/testing/mozbase/rust/mozprofile/src/profile.rs &gt;+++ b/testing/mozbase/rust/mozprofile/src/profile.rs &gt;@@ -1,14 +1,14 @@ &gt;-use preferences::{Preferences, Pref}; &gt;+use preferences::{Pref, Preferences}; &gt; use prefreader::{parse, serialize, PrefReaderError}; &gt; use std::collections::btree_map::Iter; &gt; use std::fs::File; &gt;-use std::io::Result as IoResult; &gt; use std::io::prelude::*; &gt;+use std::io::Result as IoResult; &gt; use std::path::{Path, PathBuf}; &gt; use tempdir::TempDir; &gt; &gt; #[derive(Debug)] &gt; pub struct Profile { &gt; pub path: PathBuf, &gt; pub temp_dir: Option&lt;TempDir&gt;, &gt; prefs: Option&lt;PrefFile&gt;, &gt;@@ -27,17 +27,17 @@ impl Profile { &gt; temp_path &gt; } &gt; }; &gt; &gt; Ok(Profile { &gt; path: path, &gt; temp_dir: temp_dir, &gt; prefs: None, &gt;- user_prefs: None &gt;+ user_prefs: None, &gt; }) &gt; } &gt; &gt; pub fn prefs(&amp;mut self) -&gt; Result&lt;&amp;mut PrefFile, PrefReaderError&gt; { &gt; if self.prefs.is_none() { &gt; let mut pref_path = PathBuf::from(&amp;self.path); &gt; pref_path.push("prefs.js"); &gt; self.prefs = Some(try!(PrefFile::new(pref_path))) &gt;@@ -71,34 +71,38 @@ impl PrefFile { &gt; let mut f = try!(File::open(&amp;path)); &gt; let mut buf = String::with_capacity(4096); &gt; try!(f.read_to_string(&amp;mut buf)); &gt; try!(parse(buf.as_bytes())) &gt; }; &gt; &gt; Ok(PrefFile { &gt; path: path, &gt;- prefs: prefs &gt;+ prefs: prefs, &gt; }) &gt; } &gt; &gt; pub fn write(&amp;self) -&gt; IoResult&lt;()&gt; { &gt; let mut f = try!(File::create(&amp;self.path)); &gt; serialize(&amp;self.prefs, &amp;mut f) &gt; } &gt; &gt; pub fn insert_slice&lt;K&gt;(&amp;mut self, preferences: &amp;[(K, Pref)]) &gt;- where K: Into&lt;String&gt; + Clone { &gt;+ where &gt;+ K: Into&lt;String&gt; + Clone, &gt;+ { &gt; for &amp;(ref name, ref value) in preferences.iter() { &gt; self.insert((*name).clone(), (*value).clone()); &gt; } &gt; } &gt; &gt; pub fn insert&lt;K&gt;(&amp;mut self, key: K, value: Pref) &gt;- where K: Into&lt;String&gt; { &gt;+ where &gt;+ K: Into&lt;String&gt;, &gt;+ { &gt; self.prefs.insert(key.into(), value); &gt; } &gt; &gt; pub fn remove(&amp;mut self, key: &amp;str) -&gt; Option&lt;Pref&gt; { &gt; self.prefs.remove(key) &gt; } &gt; &gt; pub fn get(&amp;mut self, key: &amp;str) -&gt; Option&lt;&amp;Pref&gt; { &gt;diff --git a/testing/mozbase/rust/mozrunner/src/bin/firefox-default-path.rs b/testing/mozbase/rust/mozrunner/src/bin/firefox-default-path.rs &gt;index 39588b809902..adee6a8015e9 100644 &gt;--- a/testing/mozbase/rust/mozrunner/src/bin/firefox-default-path.rs &gt;+++ b/testing/mozbase/rust/mozrunner/src/bin/firefox-default-path.rs &gt;@@ -5,13 +5,13 @@ use std::io::Write; &gt; &gt; fn main() { &gt; let (path, code) = platform::firefox_default_path() &gt; .map(|x| (x.to_string_lossy().into_owned(), 0)) &gt; .unwrap_or(("Firefox binary not found".to_owned(), 1)); &gt; &gt; let mut writer: Box&lt;Write&gt; = match code { &gt; 0 =&gt; Box::new(std::io::stdout()), &gt;- _ =&gt; Box::new(std::io::stderr()) &gt;+ _ =&gt; Box::new(std::io::stderr()), &gt; }; &gt; writeln!(&amp;mut writer, "{}", &amp;*path).unwrap(); &gt; std::process::exit(code); &gt; } &gt;diff --git a/testing/mozbase/rust/mozrunner/src/firefox_args.rs b/testing/mozbase/rust/mozrunner/src/firefox_args.rs &gt;index b3acff195ef6..8a832e99718c 100644 &gt;--- a/testing/mozbase/rust/mozrunner/src/firefox_args.rs &gt;+++ b/testing/mozbase/rust/mozrunner/src/firefox_args.rs &gt;@@ -92,24 +92,24 @@ impl&lt;'a&gt; From&lt;&amp;'a OsString&gt; for Arg { &gt; "profile" =&gt; Arg::Profile, &gt; "P" =&gt; Arg::NamedProfile, &gt; "ProfileManager" =&gt; Arg::ProfileManager, &gt; "foreground" =&gt; Arg::Foreground, &gt; "no-remote" =&gt; Arg::NoRemote, &gt; _ =&gt; Arg::Other(basename), &gt; } &gt; } else { &gt;- Arg::None &gt;+ Arg::None &gt; } &gt; } &gt; } &gt; &gt; #[cfg(test)] &gt; mod tests { &gt;- use super::{Arg, parse_arg_name}; &gt;+ use super::{parse_arg_name, Arg}; &gt; use std::ffi::OsString; &gt; &gt; fn parse(arg: &amp;str, name: Option&lt;&amp;str&gt;) { &gt; let result = parse_arg_name(arg); &gt; assert_eq!(result, name.map(|x| x.to_string())); &gt; } &gt; &gt; #[test] &gt;@@ -147,24 +147,36 @@ mod tests { &gt; parse("/profile", None); &gt; } &gt; &gt; #[test] &gt; fn test_arg_from_osstring() { &gt; assert_eq!(Arg::from(&amp;OsString::from("-- profile")), Arg::None); &gt; assert_eq!(Arg::from(&amp;OsString::from("profile")), Arg::None); &gt; assert_eq!(Arg::from(&amp;OsString::from("profile -P")), Arg::None); &gt;- assert_eq!(Arg::from(&amp;OsString::from("-profiled")), Arg::Other("profiled".into())); &gt;- assert_eq!(Arg::from(&amp;OsString::from("-PROFILEMANAGER")), Arg::Other("PROFILEMANAGER".into())); &gt;+ assert_eq!( &gt;+ Arg::from(&amp;OsString::from("-profiled")), &gt;+ Arg::Other("profiled".into()) &gt;+ ); &gt;+ assert_eq!( &gt;+ Arg::from(&amp;OsString::from("-PROFILEMANAGER")), &gt;+ Arg::Other("PROFILEMANAGER".into()) &gt;+ ); &gt; &gt; assert_eq!(Arg::from(&amp;OsString::from("--profile")), Arg::Profile); &gt; assert_eq!(Arg::from(&amp;OsString::from("-profile foo")), Arg::Profile); &gt; &gt;- assert_eq!(Arg::from(&amp;OsString::from("--ProfileManager")), Arg::ProfileManager); &gt;- assert_eq!(Arg::from(&amp;OsString::from("-ProfileManager")), Arg::ProfileManager); &gt;+ assert_eq!( &gt;+ Arg::from(&amp;OsString::from("--ProfileManager")), &gt;+ Arg::ProfileManager &gt;+ ); &gt;+ assert_eq!( &gt;+ Arg::from(&amp;OsString::from("-ProfileManager")), &gt;+ Arg::ProfileManager &gt;+ ); &gt; &gt; // TODO: -Ptest is valid &gt; //assert_eq!(Arg::from(&amp;OsString::from("-Ptest")), Arg::NamedProfile); &gt; assert_eq!(Arg::from(&amp;OsString::from("-P")), Arg::NamedProfile); &gt; assert_eq!(Arg::from(&amp;OsString::from("-P test")), Arg::NamedProfile); &gt; &gt; assert_eq!(Arg::from(&amp;OsString::from("--foreground")), Arg::Foreground); &gt; assert_eq!(Arg::from(&amp;OsString::from("-foreground")), Arg::Foreground); &gt;diff --git a/testing/mozbase/rust/mozrunner/src/runner.rs b/testing/mozbase/rust/mozrunner/src/runner.rs &gt;index 11a627182209..ced02f2f0f84 100644 &gt;--- a/testing/mozbase/rust/mozrunner/src/runner.rs &gt;+++ b/testing/mozbase/rust/mozrunner/src/runner.rs &gt;@@ -91,22 +91,20 @@ impl fmt::Display for RunnerError { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; self.description().fmt(f) &gt; } &gt; } &gt; &gt; impl Error for RunnerError { &gt; fn description(&amp;self) -&gt; &amp;str { &gt; match *self { &gt;- RunnerError::Io(ref err) =&gt; { &gt;- match err.kind() { &gt;- ErrorKind::NotFound =&gt; "no such file or directory", &gt;- _ =&gt; err.description(), &gt;- } &gt;- } &gt;+ RunnerError::Io(ref err) =&gt; match err.kind() { &gt;+ ErrorKind::NotFound =&gt; "no such file or directory", &gt;+ _ =&gt; err.description(), &gt;+ }, &gt; RunnerError::PrefReader(ref err) =&gt; err.description(), &gt; } &gt; } &gt; &gt; fn cause(&amp;self) -&gt; Option&lt;&amp;Error&gt; { &gt; Some(match *self { &gt; RunnerError::Io(ref err) =&gt; err as &amp;Error, &gt; RunnerError::PrefReader(ref err) =&gt; err as &amp;Error, &gt;@@ -267,17 +265,17 @@ impl Runner for FirefoxRunner { &gt; let mut seen_foreground = false; &gt; let mut seen_no_remote = false; &gt; let mut seen_profile = false; &gt; for arg in self.args.iter() { &gt; match arg.into() { &gt; Arg::Foreground =&gt; seen_foreground = true, &gt; Arg::NoRemote =&gt; seen_no_remote = true, &gt; Arg::Profile | Arg::NamedProfile | Arg::ProfileManager =&gt; seen_profile = true, &gt;- Arg::Other(_) | Arg::None =&gt; {}, &gt;+ Arg::Other(_) | Arg::None =&gt; {} &gt; } &gt; } &gt; if !seen_foreground { &gt; cmd.arg("-foreground"); &gt; } &gt; if !seen_no_remote { &gt; cmd.arg("-no-remote"); &gt; } &gt;@@ -325,17 +323,18 @@ pub mod platform { &gt; &gt; let home = env::home_dir(); &gt; for &amp;(prefix_home, trial_path) in [ &gt; ( &gt; false, &gt; "/Applications/Firefox.app/Contents/MacOS/firefox-bin", &gt; ), &gt; (true, "Applications/Firefox.app/Contents/MacOS/firefox-bin"), &gt;- ].iter() &gt;+ ] &gt;+ .iter() &gt; { &gt; let path = match (home.as_ref(), prefix_home) { &gt; (Some(ref home_dir), true) =&gt; home_dir.join(trial_path), &gt; (None, true) =&gt; continue, &gt; (_, false) =&gt; PathBuf::from(trial_path), &gt; }; &gt; if is_binary(&amp;path) { &gt; return Some(path); &gt;@@ -350,18 +349,18 @@ pub mod platform { &gt; } &gt; } &gt; &gt; #[cfg(target_os = "windows")] &gt; pub mod platform { &gt; use path::{find_binary, is_binary}; &gt; use std::io::Error; &gt; use std::path::PathBuf; &gt;- use winreg::RegKey; &gt; use winreg::enums::*; &gt;+ use winreg::RegKey; &gt; &gt; /// Searches the Windows registry, then the system path for `firefox.exe`. &gt; /// &gt; /// It _does not_ currently check the `HKEY_CURRENT_USER` tree. &gt; pub fn firefox_default_path() -&gt; Option&lt;PathBuf&gt; { &gt; if let Ok(Some(path)) = firefox_registry_path() { &gt; if is_binary(&amp;path) { &gt; return Some(path); &gt;@@ -369,17 +368,18 @@ pub mod platform { &gt; }; &gt; find_binary("firefox.exe") &gt; } &gt; &gt; fn firefox_registry_path() -&gt; Result&lt;Option&lt;PathBuf&gt;, Error&gt; { &gt; let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); &gt; for subtree_key in ["SOFTWARE", "SOFTWARE\\WOW6432Node"].iter() { &gt; let subtree = hklm.open_subkey_with_flags(subtree_key, KEY_READ)?; &gt;- let mozilla_org = match subtree.open_subkey_with_flags("mozilla.org\\Mozilla", KEY_READ) { &gt;+ let mozilla_org = match subtree.open_subkey_with_flags("mozilla.org\\Mozilla", KEY_READ) &gt;+ { &gt; Ok(val) =&gt; val, &gt; Err(_) =&gt; continue, &gt; }; &gt; let current_version: String = mozilla_org.get_value("CurrentVersion")?; &gt; let mozilla = subtree.open_subkey_with_flags("Mozilla", KEY_READ)?; &gt; for key_res in mozilla.enum_keys() { &gt; let key = key_res?; &gt; let section_data = mozilla.open_subkey_with_flags(&amp;key, KEY_READ)?; &gt;@@ -404,17 +404,21 @@ pub mod platform { &gt; Ok(None) &gt; } &gt; &gt; pub fn arg_prefix_char(c: char) -&gt; bool { &gt; c == '/' || c == '-' &gt; } &gt; } &gt; &gt;-#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] &gt;+#[cfg(not(any( &gt;+ target_os = "linux", &gt;+ target_os = "macos", &gt;+ target_os = "windows" &gt;+)))] &gt; pub mod platform { &gt; use std::path::PathBuf; &gt; &gt; /// Returns `None` for all other operating systems than Linux, macOS, and &gt; /// Windows. &gt; pub fn firefox_default_path() -&gt; Option&lt;PathBuf&gt; { &gt; None &gt; } &gt;diff --git a/testing/mozbase/rust/mozversion/src/lib.rs b/testing/mozbase/rust/mozversion/src/lib.rs &gt;index 07fab5e37bc1..262dbdd462ca 100644 &gt;--- a/testing/mozbase/rust/mozversion/src/lib.rs &gt;+++ b/testing/mozbase/rust/mozversion/src/lib.rs &gt;@@ -1,15 +1,15 @@ &gt; extern crate ini; &gt; extern crate regex; &gt; extern crate semver; &gt; &gt; use ini::Ini; &gt;-use regex::Regex; &gt; use platform::ini_path; &gt;+use regex::Regex; &gt; use std::default::Default; &gt; use std::error; &gt; use std::fmt::{self, Display, Formatter}; &gt; use std::path::Path; &gt; use std::str::FromStr; &gt; &gt; /// Details about the version of a Firefox build. &gt; #[derive(Clone, Default)] &gt;@@ -88,45 +88,59 @@ pub struct Version { &gt; pub pre: Option&lt;(String, u64)&gt;, &gt; } &gt; &gt; impl Version { &gt; pub fn from_str(version_string: &amp;str) -&gt; Result&lt;Version, Error&gt; { &gt; let mut version: Version = Default::default(); &gt; let version_re = Regex::new(r"^(?P&lt;major&gt;\d+)\.(?P&lt;minor&gt;\d+)(?:\.(?P&lt;patch&gt;\d+))?(?:(?P&lt;pre0&gt;[a-z]+)(?P&lt;pre1&gt;\d*))?$").unwrap(); &gt; if let Some(captures) = version_re.captures(version_string) { &gt;- match captures.name("major") &gt;- .and_then(|x| u64::from_str(x.as_str()).ok()) { &gt;- Some(x) =&gt; version.major = x, &gt;- None =&gt; return Err(Error::VersionError("No major version number found".into())) &gt;- } &gt;- match captures.name("minor") &gt;- .and_then(|x| u64::from_str(x.as_str()).ok()) { &gt;- Some(x) =&gt; version.minor = x, &gt;- None =&gt; return Err(Error::VersionError("No minor version number found".into())) &gt;- } &gt;- match captures.name("patch") &gt;- .and_then(|x| u64::from_str(x.as_str()).ok()) { &gt;- Some(x) =&gt; version.patch = x, &gt;- None =&gt; {} &gt;- } &gt;+ match captures &gt;+ .name("major") &gt;+ .and_then(|x| u64::from_str(x.as_str()).ok()) &gt;+ { &gt;+ Some(x) =&gt; version.major = x, &gt;+ None =&gt; return Err(Error::VersionError("No major version number found".into())), &gt;+ } &gt;+ match captures &gt;+ .name("minor") &gt;+ .and_then(|x| u64::from_str(x.as_str()).ok()) &gt;+ { &gt;+ Some(x) =&gt; version.minor = x, &gt;+ None =&gt; return Err(Error::VersionError("No minor version number found".into())), &gt;+ } &gt;+ match captures &gt;+ .name("patch") &gt;+ .and_then(|x| u64::from_str(x.as_str()).ok()) &gt;+ { &gt;+ Some(x) =&gt; version.patch = x, &gt;+ None =&gt; {} &gt;+ } &gt; if let Some(pre_0) = captures.name("pre0").map(|x| x.as_str().to_string()) { &gt; if captures.name("pre1").is_some() { &gt;- if let Some(pre_1) = captures.name("pre1") &gt;- .and_then(|x| u64::from_str(x.as_str()).ok()) { &gt;- version.pre = Some((pre_0, pre_1)) &gt;- } else { &gt;- return Err(Error::VersionError("Failed to convert prelease number to u64".into())); &gt;- } &gt;+ if let Some(pre_1) = captures &gt;+ .name("pre1") &gt;+ .and_then(|x| u64::from_str(x.as_str()).ok()) &gt;+ { &gt;+ version.pre = Some((pre_0, pre_1)) &gt;+ } else { &gt;+ return Err(Error::VersionError( &gt;+ "Failed to convert prelease number to u64".into(), &gt;+ )); &gt;+ } &gt; } else { &gt;- return Err(Error::VersionError("Failed to convert prelease number to u64".into())); &gt;+ return Err(Error::VersionError( &gt;+ "Failed to convert prelease number to u64".into(), &gt;+ )); &gt; } &gt; } &gt; } else { &gt;- return Err(Error::VersionError("Failed to parse input as version string".into())) &gt;+ return Err(Error::VersionError( &gt;+ "Failed to parse input as version string".into(), &gt;+ )); &gt; } &gt; Ok(version) &gt; } &gt; &gt; fn to_semver(&amp;self) -&gt; semver::Version { &gt; // The way the semver crate handles prereleases isn't what we want here &gt; // This should be fixed in the long term by implementing our own comparison &gt; // operators, but for now just act as if prerelease metadata was missing, otherwise &gt;@@ -145,31 +159,31 @@ impl Version { &gt; Ok(req.matches(&amp;self.to_semver())) &gt; } &gt; } &gt; &gt; impl Display for Version { &gt; fn fmt(&amp;self, f: &amp;mut Formatter) -&gt; fmt::Result { &gt; match self.patch { &gt; 0 =&gt; try!(write!(f, "{}.{}", self.major, self.minor)), &gt;- _ =&gt; try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)) &gt;+ _ =&gt; try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch)), &gt; } &gt; if let Some(ref pre) = self.pre { &gt; try!(write!(f, "{}{}", pre.0, pre.1)); &gt; }; &gt; Ok(()) &gt; } &gt; } &gt; &gt; /// Determine the version of Firefox given the path to a binary. &gt; /// &gt; /// Given the path to a Firefox binary, read the associated application.ini &gt; /// and platform.ini files to extract information about the version of Firefox &gt; /// at that path. &gt;-pub fn firefox_version(binary: &amp;Path) -&gt; Result&lt;AppVersion, Error&gt; { &gt;+pub fn firefox_version(binary: &amp;Path) -&gt; Result&lt;AppVersion, Error&gt; { &gt; let mut version = AppVersion::new(); &gt; let mut updated = false; &gt; &gt; if let Some(dir) = ini_path(binary) { &gt; let mut application_ini = dir.clone(); &gt; application_ini.push("application.ini"); &gt; &gt; if Path::exists(&amp;application_ini) { &gt;@@ -187,45 +201,47 @@ pub fn firefox_version(binary: &amp;Path) -&gt; Result&lt;AppVersion, Error&gt; { &gt; let ini_file = Ini::load_from_file(platform_ini).ok(); &gt; if let Some(ini) = ini_file { &gt; updated = true; &gt; version.update_from_platform_ini(&amp;ini); &gt; } &gt; } &gt; &gt; if !updated { &gt;- return Err(Error::MetadataError("Neither platform.ini nor application.ini found".into())) &gt;+ return Err(Error::MetadataError( &gt;+ "Neither platform.ini nor application.ini found".into(), &gt;+ )); &gt; } &gt; } else { &gt;- return Err(Error::MetadataError("Invalid binary path".into())) &gt;+ return Err(Error::MetadataError("Invalid binary path".into())); &gt; } &gt; Ok(version) &gt; } &gt; &gt; #[derive(Debug)] &gt; pub enum Error { &gt; /// Error parsing a version string &gt; VersionError(String), &gt; /// Error reading application metadata &gt; MetadataError(String), &gt; /// Error processing a string as a semver comparator &gt;- SemVerError(semver::ReqParseError) &gt;+ SemVerError(semver::ReqParseError), &gt; } &gt; &gt; impl Display for Error { &gt; fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result { &gt; match self { &gt; &amp;Error::VersionError(ref x) =&gt; { &gt; try!("VersionError: ".fmt(f)); &gt; x.fmt(f) &gt;- }, &gt;+ } &gt; &amp;Error::MetadataError(ref x) =&gt; { &gt; try!("MetadataError: ".fmt(f)); &gt; x.fmt(f) &gt;- }, &gt;+ } &gt; &amp;Error::SemVerError(ref e) =&gt; { &gt; try!("SemVerError: ".fmt(f)); &gt; e.fmt(f) &gt; } &gt; } &gt; } &gt; } &gt; &gt;@@ -252,39 +268,43 @@ impl error::Error for Error { &gt; } &gt; } &gt; &gt; #[cfg(target_os = "macos")] &gt; mod platform { &gt; use std::path::{Path, PathBuf}; &gt; &gt; pub fn ini_path(binary: &amp;Path) -&gt; Option&lt;PathBuf&gt; { &gt;- binary.canonicalize().ok() &gt;+ binary &gt;+ .canonicalize() &gt;+ .ok() &gt; .as_ref() &gt; .and_then(|dir| dir.parent()) &gt; .and_then(|dir| dir.parent()) &gt; .map(|dir| dir.join("Resources")) &gt; } &gt; } &gt; &gt; #[cfg(not(target_os = "macos"))] &gt; mod platform { &gt; use std::path::{Path, PathBuf}; &gt; &gt; pub fn ini_path(binary: &amp;Path) -&gt; Option&lt;PathBuf&gt; { &gt;- binary.canonicalize().ok() &gt;+ binary &gt;+ .canonicalize() &gt;+ .ok() &gt; .as_ref() &gt; .and_then(|dir| dir.parent()) &gt; .map(|dir| dir.to_path_buf()) &gt; } &gt; } &gt; &gt; #[cfg(test)] &gt; mod test { &gt;- use super::{Version}; &gt;+ use super::Version; &gt; &gt; fn parse_version(input: &amp;str) -&gt; String { &gt; Version::from_str(input).unwrap().to_string() &gt; } &gt; &gt; fn compare(version: &amp;str, comparison: &amp;str) -&gt; bool { &gt; let v = Version::from_str(version).unwrap(); &gt; v.matches(comparison).unwrap() &gt;diff --git a/testing/webdriver/src/actions.rs b/testing/webdriver/src/actions.rs &gt;index 22618e80660b..8adb7daacacd 100644 &gt;--- a/testing/webdriver/src/actions.rs &gt;+++ b/testing/webdriver/src/actions.rs &gt;@@ -1,127 +1,149 @@ &gt; use command::Parameters; &gt; use common::{Nullable, WebElement}; &gt;-use error::{WebDriverResult, WebDriverError, ErrorStatus}; &gt;-use rustc_serialize::json::{ToJson, Json}; &gt;-use unicode_segmentation::UnicodeSegmentation; &gt;+use error::{ErrorStatus, WebDriverError, WebDriverResult}; &gt;+use rustc_serialize::json::{Json, ToJson}; &gt; use std::collections::BTreeMap; &gt; use std::default::Default; &gt;+use unicode_segmentation::UnicodeSegmentation; &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct ActionSequence { &gt; pub id: Nullable&lt;String&gt;, &gt;- pub actions: ActionsType &gt;+ pub actions: ActionsType, &gt; } &gt; &gt; impl Parameters for ActionSequence { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;ActionSequence&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Actions chain was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Actions chain was not an object" &gt;+ ); &gt; &gt;- let type_name = try_opt!(try_opt!(data.get("type"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing type parameter").as_string(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Parameter ;type' was not a string"); &gt;+ let type_name = try_opt!( &gt;+ try_opt!( &gt;+ data.get("type"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing type parameter" &gt;+ ).as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Parameter ;type' was not a string" &gt;+ ); &gt; &gt; let id = match data.get("id") { &gt;- Some(x) =&gt; Some(try_opt!(x.as_string(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Parameter 'id' was not a string").to_owned()), &gt;- None =&gt; None &gt;+ Some(x) =&gt; Some( &gt;+ try_opt!( &gt;+ x.as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Parameter 'id' was not a string" &gt;+ ).to_owned(), &gt;+ ), &gt;+ None =&gt; None, &gt; }; &gt; &gt;- &gt; // Note that unlike the spec we get the pointer parameters in ActionsType::from_json &gt; &gt; let actions = match type_name { &gt; "none" | "key" | "pointer" =&gt; try!(ActionsType::from_json(&amp;body)), &gt;- _ =&gt; return Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Invalid action type")) &gt;+ _ =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Invalid action type", &gt;+ )) &gt;+ } &gt; }; &gt; &gt; Ok(ActionSequence { &gt; id: id.into(), &gt;- actions: actions &gt;+ actions: actions, &gt; }) &gt; } &gt; } &gt; &gt; impl ToJson for ActionSequence { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data: BTreeMap&lt;String, Json&gt; = BTreeMap::new(); &gt; data.insert("id".into(), self.id.to_json()); &gt; let (action_type, actions) = match self.actions { &gt;- ActionsType::Null(ref actions) =&gt; { &gt;- ("none", &gt;- actions.iter().map(|x| x.to_json()).collect::&lt;Vec&lt;Json&gt;&gt;()) &gt;- } &gt;- ActionsType::Key(ref actions) =&gt; { &gt;- ("key", &gt;- actions.iter().map(|x| x.to_json()).collect::&lt;Vec&lt;Json&gt;&gt;()) &gt;- } &gt;+ ActionsType::Null(ref actions) =&gt; ( &gt;+ "none", &gt;+ actions.iter().map(|x| x.to_json()).collect::&lt;Vec&lt;Json&gt;&gt;(), &gt;+ ), &gt;+ ActionsType::Key(ref actions) =&gt; ( &gt;+ "key", &gt;+ actions.iter().map(|x| x.to_json()).collect::&lt;Vec&lt;Json&gt;&gt;(), &gt;+ ), &gt; ActionsType::Pointer(ref parameters, ref actions) =&gt; { &gt; data.insert("parameters".into(), parameters.to_json()); &gt;- ("pointer", &gt;- actions.iter().map(|x| x.to_json()).collect::&lt;Vec&lt;Json&gt;&gt;()) &gt;+ ( &gt;+ "pointer", &gt;+ actions.iter().map(|x| x.to_json()).collect::&lt;Vec&lt;Json&gt;&gt;(), &gt;+ ) &gt; } &gt; }; &gt; data.insert("type".into(), action_type.to_json()); &gt; data.insert("actions".into(), actions.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum ActionsType { &gt; Null(Vec&lt;NullActionItem&gt;), &gt; Key(Vec&lt;KeyActionItem&gt;), &gt;- Pointer(PointerActionParameters, Vec&lt;PointerActionItem&gt;) &gt;+ Pointer(PointerActionParameters, Vec&lt;PointerActionItem&gt;), &gt; } &gt; &gt; impl Parameters for ActionsType { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;ActionsType&gt; { &gt; // These unwraps are OK as long as this is only called from ActionSequence::from_json &gt; let data = body.as_object().expect("Body should be a JSON Object"); &gt;- let actions_type = body.find("type").and_then(|x| x.as_string()).expect("Type should be a string"); &gt;- let actions_chain = try_opt!(try_opt!(data.get("actions"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing actions parameter").as_array(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Parameter 'actions' was not an array"); &gt;+ let actions_type = body &gt;+ .find("type") &gt;+ .and_then(|x| x.as_string()) &gt;+ .expect("Type should be a string"); &gt;+ let actions_chain = try_opt!( &gt;+ try_opt!( &gt;+ data.get("actions"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing actions parameter" &gt;+ ).as_array(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Parameter 'actions' was not an array" &gt;+ ); &gt; match actions_type { &gt; "none" =&gt; { &gt; let mut actions = Vec::with_capacity(actions_chain.len()); &gt; for action_body in actions_chain.iter() { &gt; actions.push(try!(NullActionItem::from_json(action_body))); &gt;- }; &gt;+ } &gt; Ok(ActionsType::Null(actions)) &gt;- }, &gt;+ } &gt; "key" =&gt; { &gt; let mut actions = Vec::with_capacity(actions_chain.len()); &gt; for action_body in actions_chain.iter() { &gt; actions.push(try!(KeyActionItem::from_json(action_body))); &gt;- }; &gt;+ } &gt; Ok(ActionsType::Key(actions)) &gt;- }, &gt;+ } &gt; "pointer" =&gt; { &gt; let mut actions = Vec::with_capacity(actions_chain.len()); &gt; let parameters = match data.get("parameters") { &gt; Some(x) =&gt; try!(PointerActionParameters::from_json(x)), &gt;- None =&gt; Default::default() &gt;+ None =&gt; Default::default(), &gt; }; &gt; &gt; for action_body in actions_chain.iter() { &gt; actions.push(try!(PointerActionItem::from_json(action_body))); &gt; } &gt; Ok(ActionsType::Pointer(parameters, actions)) &gt; } &gt;- _ =&gt; panic!("Got unexpected action type after checking type") &gt;+ _ =&gt; panic!("Got unexpected action type after checking type"), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum PointerType { &gt; Mouse, &gt; Pen, &gt;@@ -131,22 +153,22 @@ pub enum PointerType { &gt; impl Parameters for PointerType { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;PointerType&gt; { &gt; match body.as_string() { &gt; Some("mouse") =&gt; Ok(PointerType::Mouse), &gt; Some("pen") =&gt; Ok(PointerType::Pen), &gt; Some("touch") =&gt; Ok(PointerType::Touch), &gt; Some(_) =&gt; Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- "Unsupported pointer type" &gt;+ "Unsupported pointer type", &gt; )), &gt; None =&gt; Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- "Pointer type was not a string" &gt;- )) &gt;+ "Pointer type was not a string", &gt;+ )), &gt; } &gt; } &gt; } &gt; &gt; impl ToJson for PointerType { &gt; fn to_json(&amp;self) -&gt; Json { &gt; match *self { &gt; PointerType::Mouse =&gt; "mouse".to_json(), &gt;@@ -159,208 +181,235 @@ impl ToJson for PointerType { &gt; impl Default for PointerType { &gt; fn default() -&gt; PointerType { &gt; PointerType::Mouse &gt; } &gt; } &gt; &gt; #[derive(Debug, Default, PartialEq)] &gt; pub struct PointerActionParameters { &gt;- pub pointer_type: PointerType &gt;+ pub pointer_type: PointerType, &gt; } &gt; &gt; impl Parameters for PointerActionParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;PointerActionParameters&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Parameter 'parameters' was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Parameter 'parameters' was not an object" &gt;+ ); &gt; let pointer_type = match data.get("pointerType") { &gt; Some(x) =&gt; try!(PointerType::from_json(x)), &gt;- None =&gt; PointerType::default() &gt;+ None =&gt; PointerType::default(), &gt; }; &gt; Ok(PointerActionParameters { &gt;- pointer_type: pointer_type &gt;+ pointer_type: pointer_type, &gt; }) &gt; } &gt; } &gt; &gt; impl ToJson for PointerActionParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt;- data.insert("pointerType".to_owned(), &gt;- self.pointer_type.to_json()); &gt;+ data.insert("pointerType".to_owned(), self.pointer_type.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum NullActionItem { &gt;- General(GeneralAction) &gt;+ General(GeneralAction), &gt; } &gt; &gt; impl Parameters for NullActionItem { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;NullActionItem&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Actions chain was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Actions chain was not an object" &gt;+ ); &gt; let type_name = try_opt!( &gt;- try_opt!(data.get("type"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'type' parameter").as_string(), &gt;+ try_opt!( &gt;+ data.get("type"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'type' parameter" &gt;+ ).as_string(), &gt; ErrorStatus::InvalidArgument, &gt;- "Parameter 'type' was not a string"); &gt;+ "Parameter 'type' was not a string" &gt;+ ); &gt; match type_name { &gt;- "pause" =&gt; Ok(NullActionItem::General( &gt;- try!(GeneralAction::from_json(body)))), &gt;- _ =&gt; return Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Invalid type attribute")) &gt;+ "pause" =&gt; Ok(NullActionItem::General(try!(GeneralAction::from_json( &gt;+ body &gt;+ )))), &gt;+ _ =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Invalid type attribute", &gt;+ )) &gt;+ } &gt; } &gt; } &gt; } &gt; &gt; impl ToJson for NullActionItem { &gt; fn to_json(&amp;self) -&gt; Json { &gt; match self { &gt; &amp;NullActionItem::General(ref x) =&gt; x.to_json(), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum KeyActionItem { &gt; General(GeneralAction), &gt;- Key(KeyAction) &gt;+ Key(KeyAction), &gt; } &gt; &gt; impl Parameters for KeyActionItem { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;KeyActionItem&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Key action item was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Key action item was not an object" &gt;+ ); &gt; let type_name = try_opt!( &gt;- try_opt!(data.get("type"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'type' parameter").as_string(), &gt;+ try_opt!( &gt;+ data.get("type"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'type' parameter" &gt;+ ).as_string(), &gt; ErrorStatus::InvalidArgument, &gt;- "Parameter 'type' was not a string"); &gt;+ "Parameter 'type' was not a string" &gt;+ ); &gt; match type_name { &gt;- "pause" =&gt; Ok(KeyActionItem::General( &gt;- try!(GeneralAction::from_json(body)))), &gt;- _ =&gt; Ok(KeyActionItem::Key( &gt;- try!(KeyAction::from_json(body)))) &gt;+ "pause" =&gt; Ok(KeyActionItem::General(try!(GeneralAction::from_json(body)))), &gt;+ _ =&gt; Ok(KeyActionItem::Key(try!(KeyAction::from_json(body)))), &gt; } &gt; } &gt; } &gt; &gt; impl ToJson for KeyActionItem { &gt; fn to_json(&amp;self) -&gt; Json { &gt; match *self { &gt; KeyActionItem::General(ref x) =&gt; x.to_json(), &gt;- KeyActionItem::Key(ref x) =&gt; x.to_json() &gt;+ KeyActionItem::Key(ref x) =&gt; x.to_json(), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum PointerActionItem { &gt; General(GeneralAction), &gt;- Pointer(PointerAction) &gt;+ Pointer(PointerAction), &gt; } &gt; &gt; impl Parameters for PointerActionItem { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;PointerActionItem&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Pointer action item was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Pointer action item was not an object" &gt;+ ); &gt; let type_name = try_opt!( &gt;- try_opt!(data.get("type"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'type' parameter").as_string(), &gt;+ try_opt!( &gt;+ data.get("type"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'type' parameter" &gt;+ ).as_string(), &gt; ErrorStatus::InvalidArgument, &gt;- "Parameter 'type' was not a string"); &gt;+ "Parameter 'type' was not a string" &gt;+ ); &gt; &gt; match type_name { &gt;- "pause" =&gt; Ok(PointerActionItem::General(try!(GeneralAction::from_json(body)))), &gt;- _ =&gt; Ok(PointerActionItem::Pointer(try!(PointerAction::from_json(body)))) &gt;+ "pause" =&gt; Ok(PointerActionItem::General(try!(GeneralAction::from_json( &gt;+ body &gt;+ )))), &gt;+ _ =&gt; Ok(PointerActionItem::Pointer(try!(PointerAction::from_json( &gt;+ body &gt;+ )))), &gt; } &gt; } &gt; } &gt; &gt; impl ToJson for PointerActionItem { &gt; fn to_json(&amp;self) -&gt; Json { &gt; match self { &gt; &amp;PointerActionItem::General(ref x) =&gt; x.to_json(), &gt;- &amp;PointerActionItem::Pointer(ref x) =&gt; x.to_json() &gt;+ &amp;PointerActionItem::Pointer(ref x) =&gt; x.to_json(), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum GeneralAction { &gt;- Pause(PauseAction) &gt;+ Pause(PauseAction), &gt; } &gt; &gt; impl Parameters for GeneralAction { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;GeneralAction&gt; { &gt; match body.find("type").and_then(|x| x.as_string()) { &gt; Some("pause") =&gt; Ok(GeneralAction::Pause(try!(PauseAction::from_json(body)))), &gt;- _ =&gt; Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Invalid or missing type attribute")) &gt;+ _ =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Invalid or missing type attribute", &gt;+ )), &gt; } &gt; } &gt; } &gt; &gt; impl ToJson for GeneralAction { &gt; fn to_json(&amp;self) -&gt; Json { &gt; match self { &gt;- &amp;GeneralAction::Pause(ref x) =&gt; x.to_json() &gt;+ &amp;GeneralAction::Pause(ref x) =&gt; x.to_json(), &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct PauseAction { &gt;- pub duration: u64 &gt;+ pub duration: u64, &gt; } &gt; &gt; impl Parameters for PauseAction { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;PauseAction&gt; { &gt; let default = Json::U64(0); &gt; Ok(PauseAction { &gt;- duration: try_opt!(body.find("duration").unwrap_or(&amp;default).as_u64(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Parameter 'duration' was not a positive integer") &gt;+ duration: try_opt!( &gt;+ body.find("duration").unwrap_or(&amp;default).as_u64(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Parameter 'duration' was not a positive integer" &gt;+ ), &gt; }) &gt; } &gt; } &gt; &gt; impl ToJson for PauseAction { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt;- data.insert("type".to_owned(), &gt;- "pause".to_json()); &gt;- data.insert("duration".to_owned(), &gt;- self.duration.to_json()); &gt;+ data.insert("type".to_owned(), "pause".to_json()); &gt;+ data.insert("duration".to_owned(), self.duration.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum KeyAction { &gt; Up(KeyUpAction), &gt;- Down(KeyDownAction) &gt;+ Down(KeyDownAction), &gt; } &gt; &gt; impl Parameters for KeyAction { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;KeyAction&gt; { &gt; match body.find("type").and_then(|x| x.as_string()) { &gt; Some("keyDown") =&gt; Ok(KeyAction::Down(try!(KeyDownAction::from_json(body)))), &gt; Some("keyUp") =&gt; Ok(KeyAction::Up(try!(KeyUpAction::from_json(body)))), &gt;- Some(_) | None =&gt; Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Invalid type attribute value for key action")) &gt;+ Some(_) | None =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Invalid type attribute value for key action", &gt;+ )), &gt; } &gt; } &gt; } &gt; &gt; impl ToJson for KeyAction { &gt; fn to_json(&amp;self) -&gt; Json { &gt; match self { &gt; &amp;KeyAction::Down(ref x) =&gt; x.to_json(), &gt;@@ -371,110 +420,112 @@ impl ToJson for KeyAction { &gt; &gt; fn validate_key_value(value_str: &amp;str) -&gt; WebDriverResult&lt;String&gt; { &gt; let mut graphemes = value_str.graphemes(true); &gt; let value = if let Some(g) = graphemes.next() { &gt; g &gt; } else { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- "Parameter 'value' was an empty string")) &gt;+ "Parameter 'value' was an empty string", &gt;+ )); &gt; }; &gt; if graphemes.next().is_some() { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- "Parameter 'value' contained multiple graphemes")) &gt;+ "Parameter 'value' contained multiple graphemes", &gt;+ )); &gt; }; &gt; Ok(value.to_string()) &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct KeyUpAction { &gt;- pub value: String &gt;+ pub value: String, &gt; } &gt; &gt; impl Parameters for KeyUpAction { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;KeyUpAction&gt; { &gt; let value_str = try_opt!( &gt;- try_opt!(body.find("value"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing value parameter").as_string(), &gt;+ try_opt!( &gt;+ body.find("value"), &gt; ErrorStatus::InvalidArgument, &gt;- "Parameter 'value' was not a string"); &gt;+ "Missing value parameter" &gt;+ ).as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Parameter 'value' was not a string" &gt;+ ); &gt; &gt; let value = try!(validate_key_value(value_str)); &gt;- Ok(KeyUpAction { &gt;- value: value &gt;- }) &gt;+ Ok(KeyUpAction { value: value }) &gt; } &gt; } &gt; &gt; impl ToJson for KeyUpAction { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt;- data.insert("type".to_owned(), &gt;- "keyUp".to_json()); &gt;- data.insert("value".to_string(), &gt;- self.value.to_string().to_json()); &gt;+ data.insert("type".to_owned(), "keyUp".to_json()); &gt;+ data.insert("value".to_string(), self.value.to_string().to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct KeyDownAction { &gt;- pub value: String &gt;+ pub value: String, &gt; } &gt; &gt; impl Parameters for KeyDownAction { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;KeyDownAction&gt; { &gt; let value_str = try_opt!( &gt;- try_opt!(body.find("value"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing value parameter").as_string(), &gt;+ try_opt!( &gt;+ body.find("value"), &gt; ErrorStatus::InvalidArgument, &gt;- "Parameter 'value' was not a string"); &gt;+ "Missing value parameter" &gt;+ ).as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Parameter 'value' was not a string" &gt;+ ); &gt; let value = try!(validate_key_value(value_str)); &gt;- Ok(KeyDownAction { &gt;- value: value &gt;- }) &gt;+ Ok(KeyDownAction { value: value }) &gt; } &gt; } &gt; &gt; impl ToJson for KeyDownAction { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt;- data.insert("type".to_owned(), &gt;- "keyDown".to_json()); &gt;- data.insert("value".to_owned(), &gt;- self.value.to_string().to_json()); &gt;+ data.insert("type".to_owned(), "keyDown".to_json()); &gt;+ data.insert("value".to_owned(), self.value.to_string().to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum PointerOrigin { &gt; Viewport, &gt; Pointer, &gt; Element(WebElement), &gt; } &gt; &gt; impl Parameters for PointerOrigin { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;PointerOrigin&gt; { &gt; match *body { &gt;- Json::String(ref x) =&gt; { &gt;- match &amp;**x { &gt;- "viewport" =&gt; Ok(PointerOrigin::Viewport), &gt;- "pointer" =&gt; Ok(PointerOrigin::Pointer), &gt;- _ =&gt; Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Unknown pointer origin")) &gt;- } &gt;+ Json::String(ref x) =&gt; match &amp;**x { &gt;+ "viewport" =&gt; Ok(PointerOrigin::Viewport), &gt;+ "pointer" =&gt; Ok(PointerOrigin::Pointer), &gt;+ _ =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Unknown pointer origin", &gt;+ )), &gt; }, &gt; Json::Object(_) =&gt; Ok(PointerOrigin::Element(try!(WebElement::from_json(body)))), &gt;- _ =&gt; Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Pointer origin was not a string or an object")) &gt;+ _ =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Pointer origin was not a string or an object", &gt;+ )), &gt; } &gt; } &gt; } &gt; &gt; impl ToJson for PointerOrigin { &gt; fn to_json(&amp;self) -&gt; Json { &gt; match *self { &gt; PointerOrigin::Viewport =&gt; "viewport".to_json(), &gt;@@ -490,166 +541,170 @@ impl Default for PointerOrigin { &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum PointerAction { &gt; Up(PointerUpAction), &gt; Down(PointerDownAction), &gt; Move(PointerMoveAction), &gt;- Cancel &gt;+ Cancel, &gt; } &gt; &gt; impl Parameters for PointerAction { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;PointerAction&gt; { &gt; match body.find("type").and_then(|x| x.as_string()) { &gt; Some("pointerUp") =&gt; Ok(PointerAction::Up(try!(PointerUpAction::from_json(body)))), &gt;- Some("pointerDown") =&gt; Ok(PointerAction::Down(try!(PointerDownAction::from_json(body)))), &gt;- Some("pointerMove") =&gt; Ok(PointerAction::Move(try!(PointerMoveAction::from_json(body)))), &gt;+ Some("pointerDown") =&gt; Ok(PointerAction::Down(try!(PointerDownAction::from_json( &gt;+ body &gt;+ )))), &gt;+ Some("pointerMove") =&gt; Ok(PointerAction::Move(try!(PointerMoveAction::from_json( &gt;+ body &gt;+ )))), &gt; Some("pointerCancel") =&gt; Ok(PointerAction::Cancel), &gt; Some(_) | None =&gt; Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- "Missing or invalid type argument for pointer action")) &gt;+ "Missing or invalid type argument for pointer action", &gt;+ )), &gt; } &gt; } &gt; } &gt; &gt; impl ToJson for PointerAction { &gt; fn to_json(&amp;self) -&gt; Json { &gt; match self { &gt; &amp;PointerAction::Down(ref x) =&gt; x.to_json(), &gt; &amp;PointerAction::Up(ref x) =&gt; x.to_json(), &gt; &amp;PointerAction::Move(ref x) =&gt; x.to_json(), &gt; &amp;PointerAction::Cancel =&gt; { &gt; let mut data = BTreeMap::new(); &gt;- data.insert("type".to_owned(), &gt;- "pointerCancel".to_json()); &gt;+ data.insert("type".to_owned(), "pointerCancel".to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct PointerUpAction { &gt; pub button: u64, &gt; } &gt; &gt; impl Parameters for PointerUpAction { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;PointerUpAction&gt; { &gt; let button = try_opt!( &gt;- try_opt!(body.find("button"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing button parameter").as_u64(), &gt;+ try_opt!( &gt;+ body.find("button"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing button parameter" &gt;+ ).as_u64(), &gt; ErrorStatus::InvalidArgument, &gt;- "Parameter 'button' was not a positive integer"); &gt;+ "Parameter 'button' was not a positive integer" &gt;+ ); &gt; &gt;- Ok(PointerUpAction { &gt;- button: button &gt;- }) &gt;+ Ok(PointerUpAction { button: button }) &gt; } &gt; } &gt; &gt; impl ToJson for PointerUpAction { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt;- data.insert("type".to_owned(), &gt;- "pointerUp".to_json()); &gt;+ data.insert("type".to_owned(), "pointerUp".to_json()); &gt; data.insert("button".to_owned(), self.button.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct PointerDownAction { &gt; pub button: u64, &gt; } &gt; &gt; impl Parameters for PointerDownAction { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;PointerDownAction&gt; { &gt; let button = try_opt!( &gt;- try_opt!(body.find("button"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing button parameter").as_u64(), &gt;+ try_opt!( &gt;+ body.find("button"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing button parameter" &gt;+ ).as_u64(), &gt; ErrorStatus::InvalidArgument, &gt;- "Parameter 'button' was not a positive integer"); &gt;+ "Parameter 'button' was not a positive integer" &gt;+ ); &gt; &gt;- Ok(PointerDownAction { &gt;- button: button &gt;- }) &gt;+ Ok(PointerDownAction { button: button }) &gt; } &gt; } &gt; &gt; impl ToJson for PointerDownAction { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt;- data.insert("type".to_owned(), &gt;- "pointerDown".to_json()); &gt;+ data.insert("type".to_owned(), "pointerDown".to_json()); &gt; data.insert("button".to_owned(), self.button.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct PointerMoveAction { &gt; pub duration: Nullable&lt;u64&gt;, &gt; pub origin: PointerOrigin, &gt; pub x: Nullable&lt;i64&gt;, &gt;- pub y: Nullable&lt;i64&gt; &gt;+ pub y: Nullable&lt;i64&gt;, &gt; } &gt; &gt; impl Parameters for PointerMoveAction { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;PointerMoveAction&gt; { &gt; let duration = match body.find("duration") { &gt;- Some(duration) =&gt; Some(try_opt!(duration.as_u64(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Parameter 'duration' was not a positive integer")), &gt;- None =&gt; None &gt;- &gt;+ Some(duration) =&gt; Some(try_opt!( &gt;+ duration.as_u64(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Parameter 'duration' was not a positive integer" &gt;+ )), &gt;+ None =&gt; None, &gt; }; &gt; &gt; let origin = match body.find("origin") { &gt; Some(o) =&gt; try!(PointerOrigin::from_json(o)), &gt;- None =&gt; PointerOrigin::default() &gt;+ None =&gt; PointerOrigin::default(), &gt; }; &gt; &gt; let x = match body.find("x") { &gt;- Some(x) =&gt; { &gt;- Some(try_opt!(x.as_i64(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Parameter 'x' was not an integer")) &gt;- }, &gt;- None =&gt; None &gt;+ Some(x) =&gt; Some(try_opt!( &gt;+ x.as_i64(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Parameter 'x' was not an integer" &gt;+ )), &gt;+ None =&gt; None, &gt; }; &gt; &gt; let y = match body.find("y") { &gt;- Some(y) =&gt; { &gt;- Some(try_opt!(y.as_i64(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Parameter 'y' was not an integer")) &gt;- }, &gt;- None =&gt; None &gt;+ Some(y) =&gt; Some(try_opt!( &gt;+ y.as_i64(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Parameter 'y' was not an integer" &gt;+ )), &gt;+ None =&gt; None, &gt; }; &gt; &gt; Ok(PointerMoveAction { &gt; duration: duration.into(), &gt; origin: origin.into(), &gt; x: x.into(), &gt; y: y.into(), &gt; }) &gt; } &gt; } &gt; &gt; impl ToJson for PointerMoveAction { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("type".to_owned(), "pointerMove".to_json()); &gt; if self.duration.is_value() { &gt;- data.insert("duration".to_owned(), &gt;- self.duration.to_json()); &gt;+ data.insert("duration".to_owned(), self.duration.to_json()); &gt; } &gt; &gt; data.insert("origin".to_owned(), self.origin.to_json()); &gt; &gt; if self.x.is_value() { &gt; data.insert("x".to_owned(), self.x.to_json()); &gt; } &gt; if self.y.is_value() { &gt;diff --git a/testing/webdriver/src/capabilities.rs b/testing/webdriver/src/capabilities.rs &gt;index fd10ca690034..fc49c08d4116 100644 &gt;--- a/testing/webdriver/src/capabilities.rs &gt;+++ b/testing/webdriver/src/capabilities.rs &gt;@@ -74,18 +74,20 @@ pub trait BrowserCapabilities { &gt; /// This trait is expected to be implemented on objects holding the capabilities &gt; /// from a new session command. &gt; pub trait CapabilitiesMatching { &gt; /// Match the BrowserCapabilities against some candidate capabilites &gt; /// &gt; /// Takes a BrowserCapabilites object and returns a set of capabilites that &gt; /// are valid for that browser, if any, or None if there are no matching &gt; /// capabilities. &gt;- fn match_browser&lt;T: BrowserCapabilities&gt;(&amp;self, browser_capabilities: &amp;mut T) &gt;- -&gt; WebDriverResult&lt;Option&lt;Capabilities&gt;&gt;; &gt;+ fn match_browser&lt;T: BrowserCapabilities&gt;( &gt;+ &amp;self, &gt;+ browser_capabilities: &amp;mut T, &gt;+ ) -&gt; WebDriverResult&lt;Option&lt;Capabilities&gt;&gt;; &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct SpecNewSessionParameters { &gt; pub alwaysMatch: Capabilities, &gt; pub firstMatch: Vec&lt;Capabilities&gt;, &gt; } &gt; &gt;@@ -142,142 +144,164 @@ impl SpecNewSessionParameters { &gt; } &gt; } &gt; } &gt; Ok(capabilities) &gt; } &gt; &gt; fn validate_page_load_strategy(value: &amp;Json) -&gt; WebDriverResult&lt;()&gt; { &gt; match value { &gt;- &amp;Json::String(ref x) =&gt; { &gt;- match &amp;**x { &gt;- "normal" | &gt;- "eager" | &gt;- "none" =&gt; {}, &gt;- x =&gt; { &gt;- return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- format!("Invalid page load strategy: {}", x))) &gt;- } &gt;+ &amp;Json::String(ref x) =&gt; match &amp;**x { &gt;+ "normal" | "eager" | "none" =&gt; {} &gt;+ x =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("Invalid page load strategy: {}", x), &gt;+ )) &gt; } &gt;+ }, &gt;+ _ =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "pageLoadStrategy is not a string", &gt;+ )) &gt; } &gt;- _ =&gt; return Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "pageLoadStrategy is not a string")) &gt; } &gt; Ok(()) &gt; } &gt; &gt; fn validate_proxy(proxy_value: &amp;Json) -&gt; WebDriverResult&lt;()&gt; { &gt;- let obj = try_opt!(proxy_value.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "proxy is not an object"); &gt;+ let obj = try_opt!( &gt;+ proxy_value.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "proxy is not an object" &gt;+ ); &gt; &gt; for (key, value) in obj.iter() { &gt; match &amp;**key { &gt; "proxyType" =&gt; match value.as_string() { &gt;- Some("pac") | &gt;- Some("direct") | &gt;- Some("autodetect") | &gt;- Some("system") | &gt;- Some("manual") =&gt; {}, &gt;- Some(x) =&gt; return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- format!("Invalid proxyType value: {}", x))), &gt;- None =&gt; return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- format!("proxyType is not a string: {}", value))), &gt;+ Some("pac") | Some("direct") | Some("autodetect") | Some("system") &gt;+ | Some("manual") =&gt; {} &gt;+ Some(x) =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("Invalid proxyType value: {}", x), &gt;+ )) &gt;+ } &gt;+ None =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("proxyType is not a string: {}", value), &gt;+ )) &gt;+ } &gt; }, &gt; &gt; "proxyAutoconfigUrl" =&gt; match value.as_string() { &gt; Some(x) =&gt; { &gt; Url::parse(x).or(Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- format!("proxyAutoconfigUrl is not a valid URL: {}", x))))?; &gt;- }, &gt;- None =&gt; return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- "proxyAutoconfigUrl is not a string" &gt;- )) &gt;+ format!("proxyAutoconfigUrl is not a valid URL: {}", x), &gt;+ )))?; &gt;+ } &gt;+ None =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "proxyAutoconfigUrl is not a string", &gt;+ )) &gt;+ } &gt; }, &gt; &gt; "ftpProxy" =&gt; SpecNewSessionParameters::validate_host(value, "ftpProxy")?, &gt; "httpProxy" =&gt; SpecNewSessionParameters::validate_host(value, "httpProxy")?, &gt; "noProxy" =&gt; SpecNewSessionParameters::validate_no_proxy(value)?, &gt; "sslProxy" =&gt; SpecNewSessionParameters::validate_host(value, "sslProxy")?, &gt; "socksProxy" =&gt; SpecNewSessionParameters::validate_host(value, "socksProxy")?, &gt; "socksVersion" =&gt; if !value.is_number() { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- format!("socksVersion is not a number: {}", value) &gt;- )) &gt;+ format!("socksVersion is not a number: {}", value), &gt;+ )); &gt; }, &gt; &gt;- x =&gt; return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- format!("Invalid proxy configuration entry: {}", x))) &gt;+ x =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("Invalid proxy configuration entry: {}", x), &gt;+ )) &gt;+ } &gt; } &gt; } &gt; &gt; Ok(()) &gt; } &gt; &gt; fn validate_no_proxy(value: &amp;Json) -&gt; WebDriverResult&lt;()&gt; { &gt; match value.as_array() { &gt; Some(hosts) =&gt; { &gt; for host in hosts { &gt; match host.as_string() { &gt;- Some(_) =&gt; {}, &gt;- None =&gt; return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- format!("noProxy item is not a string: {}", host) &gt;- )) &gt;+ Some(_) =&gt; {} &gt;+ None =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("noProxy item is not a string: {}", host), &gt;+ )) &gt;+ } &gt; } &gt; } &gt;- }, &gt;- None =&gt; return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- format!("noProxy is not an array: {}", value) &gt;- )) &gt;+ } &gt;+ None =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("noProxy is not an array: {}", value), &gt;+ )) &gt;+ } &gt; } &gt; &gt; Ok(()) &gt; } &gt; &gt; /// Validate whether a named capability is JSON value is a string containing a host &gt; /// and possible port &gt; fn validate_host(value: &amp;Json, entry: &amp;str) -&gt; WebDriverResult&lt;()&gt; { &gt; match value.as_string() { &gt; Some(host) =&gt; { &gt; if host.contains("://") { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- format!("{} must not contain a scheme: {}", entry, host))); &gt;+ format!("{} must not contain a scheme: {}", entry, host), &gt;+ )); &gt; } &gt; &gt; // Temporarily add a scheme so the host can be parsed as URL &gt; let s = String::from(format!("http://{}", host)); &gt; let url = Url::parse(s.as_str()).or(Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt;- format!("{} is not a valid URL: {}", entry, host))))?; &gt;+ format!("{} is not a valid URL: {}", entry, host), &gt;+ )))?; &gt; &gt;- if url.username() != "" || &gt;- url.password() != None || &gt;- url.path() != "/" || &gt;- url.query() != None || &gt;- url.fragment() != None { &gt;- return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- format!("{} is not of the form host[:port]: {}", entry, host))); &gt;- } &gt;- }, &gt;+ if url.username() != "" &gt;+ || url.password() != None &gt;+ || url.path() != "/" &gt;+ || url.query() != None &gt;+ || url.fragment() != None &gt;+ { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("{} is not of the form host[:port]: {}", entry, host), &gt;+ )); &gt;+ } &gt;+ } &gt; &gt;- None =&gt; return Err(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- format!("{} is not a string: {}", entry, value) &gt;- )) &gt;+ None =&gt; { &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("{} is not a string: {}", entry, value), &gt;+ )) &gt;+ } &gt; } &gt; &gt; Ok(()) &gt; } &gt; &gt; fn validate_timeouts(value: &amp;Json) -&gt; WebDriverResult&lt;()&gt; { &gt; let obj = try_opt!( &gt; value.as_object(), &gt;@@ -316,21 +340,17 @@ impl SpecNewSessionParameters { &gt; fn validate_unhandled_prompt_behaviour(value: &amp;Json) -&gt; WebDriverResult&lt;()&gt; { &gt; let behaviour = try_opt!( &gt; value.as_string(), &gt; ErrorStatus::InvalidArgument, &gt; format!("unhandledPromptBehavior is not a string: {}", value) &gt; ); &gt; &gt; match behaviour { &gt;- "accept" | &gt;- "accept and notify" | &gt;- "dismiss" | &gt;- "dismiss and notify" | &gt;- "ignore" =&gt; {}, &gt;+ "accept" | "accept and notify" | "dismiss" | "dismiss and notify" | "ignore" =&gt; {} &gt; x =&gt; { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt; format!("Invalid unhandledPromptBehavior value: {}", x), &gt; )) &gt; } &gt; } &gt; &gt;@@ -338,17 +358,20 @@ impl SpecNewSessionParameters { &gt; } &gt; } &gt; &gt; impl Parameters for SpecNewSessionParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;SpecNewSessionParameters&gt; { &gt; let data = try_opt!( &gt; body.as_object(), &gt; ErrorStatus::UnknownError, &gt;- format!("Malformed capabilities, message body is not an object: {}", body) &gt;+ format!( &gt;+ "Malformed capabilities, message body is not an object: {}", &gt;+ body &gt;+ ) &gt; ); &gt; &gt; let capabilities = try_opt!( &gt; try_opt!( &gt; data.get("capabilities"), &gt; ErrorStatus::InvalidArgument, &gt; "Malformed capabilities, missing \"capabilities\" field" &gt; ).as_object(), &gt;@@ -369,23 +392,22 @@ impl Parameters for SpecNewSessionParameters { &gt; let first_matches = try_opt!( &gt; capabilities &gt; .get("firstMatch") &gt; .unwrap_or(&amp;default_first_matches) &gt; .as_array(), &gt; ErrorStatus::InvalidArgument, &gt; "Malformed capabilities, firstMatch field is not an array" &gt; ).iter() &gt;- .map(|x| { &gt;- x.as_object().map(|x| x.clone()).ok_or(WebDriverError::new( &gt;- ErrorStatus::InvalidArgument, &gt;- "Malformed capabilities, firstMatch entry is not an object", &gt;- )) &gt;- }) &gt;- .collect::&lt;WebDriverResult&lt;Vec&lt;Capabilities&gt;&gt;&gt;()?; &gt;+ .map(|x| { &gt;+ x.as_object().map(|x| x.clone()).ok_or(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Malformed capabilities, firstMatch entry is not an object", &gt;+ )) &gt;+ }).collect::&lt;WebDriverResult&lt;Vec&lt;Capabilities&gt;&gt;&gt;()?; &gt; &gt; return Ok(SpecNewSessionParameters { &gt; alwaysMatch: always_match.clone(), &gt; firstMatch: first_matches, &gt; }); &gt; } &gt; } &gt; &gt;@@ -410,29 +432,29 @@ impl CapabilitiesMatching for SpecNewSessionParameters { &gt; &amp;self.firstMatch &gt; } else { &gt; &amp;default &gt; }; &gt; &gt; let merged_capabilities = capabilities_list &gt; .iter() &gt; .map(|first_match_entry| { &gt;- if first_match_entry.keys().any(|k| self.alwaysMatch.contains_key(k)) { &gt;+ if first_match_entry &gt;+ .keys() &gt;+ .any(|k| self.alwaysMatch.contains_key(k)) &gt;+ { &gt; return Err(WebDriverError::new( &gt; ErrorStatus::InvalidArgument, &gt; "firstMatch key shadowed a value in alwaysMatch", &gt; )); &gt; } &gt; let mut merged = self.alwaysMatch.clone(); &gt; merged.append(&amp;mut first_match_entry.clone()); &gt; Ok(merged) &gt;- }) &gt;- .map(|merged| { &gt;- merged.and_then(|x| self.validate(x, browser_capabilities)) &gt;- }) &gt;+ }).map(|merged| merged.and_then(|x| self.validate(x, browser_capabilities))) &gt; .collect::&lt;WebDriverResult&lt;Vec&lt;Capabilities&gt;&gt;&gt;()?; &gt; &gt; let selected = merged_capabilities &gt; .iter() &gt; .filter_map(|merged| { &gt; browser_capabilities.init(merged); &gt; &gt; for (key, value) in merged.iter() { &gt;@@ -470,29 +492,27 @@ impl CapabilitiesMatching for SpecNewSessionParameters { &gt; .platform_name(merged) &gt; .ok() &gt; .and_then(|x| x); &gt; if value.as_string() != browserValue.as_ref().map(|x| &amp;**x) { &gt; return None; &gt; } &gt; } &gt; "acceptInsecureCerts" =&gt; { &gt;- if value.as_boolean().unwrap_or(false) &amp;&amp; &gt;- !browser_capabilities &gt;- .accept_insecure_certs(merged) &gt;- .unwrap_or(false) &gt;+ if value.as_boolean().unwrap_or(false) &amp;&amp; !browser_capabilities &gt;+ .accept_insecure_certs(merged) &gt;+ .unwrap_or(false) &gt; { &gt; return None; &gt; } &gt; } &gt; "setWindowRect" =&gt; { &gt;- if value.as_boolean().unwrap_or(false) &amp;&amp; &gt;- !browser_capabilities &gt;- .set_window_rect(merged) &gt;- .unwrap_or(false) &gt;+ if value.as_boolean().unwrap_or(false) &amp;&amp; !browser_capabilities &gt;+ .set_window_rect(merged) &gt;+ .unwrap_or(false) &gt; { &gt; return None; &gt; } &gt; } &gt; "proxy" =&gt; { &gt; let default = BTreeMap::new(); &gt; let proxy = value.as_object().unwrap_or(&amp;default); &gt; if !browser_capabilities &gt;@@ -513,18 +533,17 @@ impl CapabilitiesMatching for SpecNewSessionParameters { &gt; } else { &gt; // Accept the capability &gt; } &gt; } &gt; } &gt; } &gt; &gt; return Some(merged); &gt;- }) &gt;- .next() &gt;+ }).next() &gt; .map(|x| x.clone()); &gt; Ok(selected) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct LegacyNewSessionParameters { &gt; pub desired: Capabilities, &gt;@@ -554,17 +573,20 @@ impl CapabilitiesMatching for LegacyNewSessionParameters { &gt; } &gt; } &gt; &gt; impl Parameters for LegacyNewSessionParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;LegacyNewSessionParameters&gt; { &gt; let data = try_opt!( &gt; body.as_object(), &gt; ErrorStatus::UnknownError, &gt;- format!("Malformed legacy capabilities, message body is not an object: {}", body) &gt;+ format!( &gt;+ "Malformed legacy capabilities, message body is not an object: {}", &gt;+ body &gt;+ ) &gt; ); &gt; &gt; let desired = if let Some(capabilities) = data.get("desiredCapabilities") { &gt; try_opt!( &gt; capabilities.as_object(), &gt; ErrorStatus::InvalidArgument, &gt; "Malformed legacy capabilities, desiredCapabilities field is not an object" &gt; ).clone() &gt;@@ -592,18 +614,18 @@ impl ToJson for LegacyNewSessionParameters { &gt; data.insert("desiredCapabilities".to_owned(), self.desired.to_json()); &gt; data.insert("requiredCapabilities".to_owned(), self.required.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[cfg(test)] &gt; mod tests { &gt;- use rustc_serialize::json::Json; &gt; use super::{SpecNewSessionParameters, WebDriverResult}; &gt;+ use rustc_serialize::json::Json; &gt; &gt; fn validate_proxy(value: &amp;str) -&gt; WebDriverResult&lt;()&gt; { &gt; let data = Json::from_str(value).unwrap(); &gt; SpecNewSessionParameters::validate_proxy(&amp;data) &gt; } &gt; &gt; #[test] &gt; fn test_validate_proxy() { &gt;diff --git a/testing/webdriver/src/command.rs b/testing/webdriver/src/command.rs &gt;index 37cd841e79b5..25cc0ed5bd5e 100644 &gt;--- a/testing/webdriver/src/command.rs &gt;+++ b/testing/webdriver/src/command.rs &gt;@@ -1,17 +1,19 @@ &gt;-use actions::{ActionSequence}; &gt;-use capabilities::{SpecNewSessionParameters, LegacyNewSessionParameters, &gt;- CapabilitiesMatching, BrowserCapabilities, Capabilities}; &gt;-use common::{Date, Nullable, WebElement, FrameId, LocatorStrategy}; &gt;-use error::{WebDriverResult, WebDriverError, ErrorStatus}; &gt;-use httpapi::{Route, WebDriverExtensionRoute, VoidWebDriverExtensionRoute}; &gt;+use actions::ActionSequence; &gt;+use capabilities::{ &gt;+ BrowserCapabilities, Capabilities, CapabilitiesMatching, LegacyNewSessionParameters, &gt;+ SpecNewSessionParameters, &gt;+}; &gt;+use common::{Date, FrameId, LocatorStrategy, Nullable, WebElement}; &gt;+use error::{ErrorStatus, WebDriverError, WebDriverResult}; &gt;+use httpapi::{Route, VoidWebDriverExtensionRoute, WebDriverExtensionRoute}; &gt; use regex::Captures; &gt; use rustc_serialize::json; &gt;-use rustc_serialize::json::{ToJson, Json}; &gt;+use rustc_serialize::json::{Json, ToJson}; &gt; use std::collections::BTreeMap; &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum WebDriverCommand&lt;T: WebDriverExtensionCommand&gt; { &gt; NewSession(NewSessionParameters), &gt; DeleteSession, &gt; Get(GetParameters), &gt; GetCurrentUrl, &gt;@@ -62,368 +64,406 @@ pub enum WebDriverCommand&lt;T: WebDriverExtensionCommand&gt; { &gt; ReleaseActions, &gt; DismissAlert, &gt; AcceptAlert, &gt; GetAlertText, &gt; SendAlertText(SendKeysParameters), &gt; TakeScreenshot, &gt; TakeElementScreenshot(WebElement), &gt; Status, &gt;- Extension(T) &gt;+ Extension(T), &gt; } &gt; &gt;-pub trait WebDriverExtensionCommand : Clone + Send + PartialEq { &gt;+pub trait WebDriverExtensionCommand: Clone + Send + PartialEq { &gt; fn parameters_json(&amp;self) -&gt; Option&lt;Json&gt;; &gt; } &gt; &gt; #[derive(Clone, Debug, PartialEq)] &gt; pub struct VoidWebDriverExtensionCommand; &gt; &gt; impl WebDriverExtensionCommand for VoidWebDriverExtensionCommand { &gt; fn parameters_json(&amp;self) -&gt; Option&lt;Json&gt; { &gt; panic!("No extensions implemented"); &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt;-pub struct WebDriverMessage &lt;U: WebDriverExtensionRoute=VoidWebDriverExtensionRoute&gt; { &gt;+pub struct WebDriverMessage&lt;U: WebDriverExtensionRoute = VoidWebDriverExtensionRoute&gt; { &gt; pub session_id: Option&lt;String&gt;, &gt; pub command: WebDriverCommand&lt;U::Command&gt;, &gt; } &gt; &gt; impl&lt;U: WebDriverExtensionRoute&gt; WebDriverMessage&lt;U&gt; { &gt;- pub fn new(session_id: Option&lt;String&gt;, &gt;- command: WebDriverCommand&lt;U::Command&gt;) &gt;- -&gt; WebDriverMessage&lt;U&gt; { &gt;+ pub fn new( &gt;+ session_id: Option&lt;String&gt;, &gt;+ command: WebDriverCommand&lt;U::Command&gt;, &gt;+ ) -&gt; WebDriverMessage&lt;U&gt; { &gt; WebDriverMessage { &gt; session_id: session_id, &gt; command: command, &gt; } &gt; } &gt; &gt;- pub fn from_http(match_type: Route&lt;U&gt;, &gt;- params: &amp;Captures, &gt;- raw_body: &amp;str, &gt;- requires_body: bool) &gt;- -&gt; WebDriverResult&lt;WebDriverMessage&lt;U&gt;&gt; { &gt;+ pub fn from_http( &gt;+ match_type: Route&lt;U&gt;, &gt;+ params: &amp;Captures, &gt;+ raw_body: &amp;str, &gt;+ requires_body: bool, &gt;+ ) -&gt; WebDriverResult&lt;WebDriverMessage&lt;U&gt;&gt; { &gt; let session_id = WebDriverMessage::&lt;U&gt;::get_session_id(params); &gt; let body_data = try!(WebDriverMessage::&lt;U&gt;::decode_body(raw_body, requires_body)); &gt; &gt; let command = match match_type { &gt; Route::NewSession =&gt; { &gt; let parameters: NewSessionParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::NewSession(parameters) &gt;- }, &gt;+ } &gt; Route::DeleteSession =&gt; WebDriverCommand::DeleteSession, &gt; Route::Get =&gt; { &gt; let parameters: GetParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::Get(parameters) &gt;- }, &gt;+ } &gt; Route::GetCurrentUrl =&gt; WebDriverCommand::GetCurrentUrl, &gt; Route::GoBack =&gt; WebDriverCommand::GoBack, &gt; Route::GoForward =&gt; WebDriverCommand::GoForward, &gt; Route::Refresh =&gt; WebDriverCommand::Refresh, &gt; Route::GetTitle =&gt; WebDriverCommand::GetTitle, &gt; Route::GetPageSource =&gt; WebDriverCommand::GetPageSource, &gt; Route::GetWindowHandle =&gt; WebDriverCommand::GetWindowHandle, &gt; Route::GetWindowHandles =&gt; WebDriverCommand::GetWindowHandles, &gt; Route::CloseWindow =&gt; WebDriverCommand::CloseWindow, &gt; Route::GetTimeouts =&gt; WebDriverCommand::GetTimeouts, &gt; Route::SetTimeouts =&gt; { &gt; let parameters: TimeoutsParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::SetTimeouts(parameters) &gt;- }, &gt;- Route::GetWindowRect | Route::GetWindowPosition | Route::GetWindowSize =&gt; WebDriverCommand::GetWindowRect, &gt;+ } &gt;+ Route::GetWindowRect | Route::GetWindowPosition | Route::GetWindowSize =&gt; { &gt;+ WebDriverCommand::GetWindowRect &gt;+ } &gt; Route::SetWindowRect | Route::SetWindowPosition | Route::SetWindowSize =&gt; { &gt; let parameters: WindowRectParameters = Parameters::from_json(&amp;body_data)?; &gt; WebDriverCommand::SetWindowRect(parameters) &gt;- }, &gt;+ } &gt; Route::MinimizeWindow =&gt; WebDriverCommand::MinimizeWindow, &gt; Route::MaximizeWindow =&gt; WebDriverCommand::MaximizeWindow, &gt; Route::FullscreenWindow =&gt; WebDriverCommand::FullscreenWindow, &gt; Route::SwitchToWindow =&gt; { &gt; let parameters: SwitchToWindowParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::SwitchToWindow(parameters) &gt; } &gt; Route::SwitchToFrame =&gt; { &gt; let parameters: SwitchToFrameParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::SwitchToFrame(parameters) &gt;- }, &gt;+ } &gt; Route::SwitchToParentFrame =&gt; WebDriverCommand::SwitchToParentFrame, &gt; Route::FindElement =&gt; { &gt; let parameters: LocatorParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::FindElement(parameters) &gt;- }, &gt;+ } &gt; Route::FindElements =&gt; { &gt; let parameters: LocatorParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::FindElements(parameters) &gt;- }, &gt;+ } &gt; Route::FindElementElement =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; let parameters: LocatorParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::FindElementElement(element, parameters) &gt;- }, &gt;+ } &gt; Route::FindElementElements =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; let parameters: LocatorParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::FindElementElements(element, parameters) &gt;- }, &gt;+ } &gt; Route::GetActiveElement =&gt; WebDriverCommand::GetActiveElement, &gt; Route::IsDisplayed =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; WebDriverCommand::IsDisplayed(element) &gt;- }, &gt;+ } &gt; Route::IsSelected =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; WebDriverCommand::IsSelected(element) &gt;- }, &gt;+ } &gt; Route::GetElementAttribute =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt;- let attr = try_opt!(params.name("name"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing name parameter").as_str(); &gt;+ let attr = try_opt!( &gt;+ params.name("name"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing name parameter" &gt;+ ).as_str(); &gt; WebDriverCommand::GetElementAttribute(element, attr.into()) &gt;- }, &gt;+ } &gt; Route::GetElementProperty =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt;- let property = try_opt!(params.name("name"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing name parameter").as_str(); &gt;+ let property = try_opt!( &gt;+ params.name("name"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing name parameter" &gt;+ ).as_str(); &gt; WebDriverCommand::GetElementProperty(element, property.into()) &gt;- }, &gt;+ } &gt; Route::GetCSSValue =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt;- let property = try_opt!(params.name("propertyName"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing propertyName parameter").as_str(); &gt;+ let property = try_opt!( &gt;+ params.name("propertyName"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing propertyName parameter" &gt;+ ).as_str(); &gt; WebDriverCommand::GetCSSValue(element, property.into()) &gt;- }, &gt;+ } &gt; Route::GetElementText =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; WebDriverCommand::GetElementText(element) &gt;- }, &gt;+ } &gt; Route::GetElementTagName =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; WebDriverCommand::GetElementTagName(element) &gt;- }, &gt;+ } &gt; Route::GetElementRect =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; WebDriverCommand::GetElementRect(element) &gt;- }, &gt;+ } &gt; Route::IsEnabled =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; WebDriverCommand::IsEnabled(element) &gt;- }, &gt;+ } &gt; Route::ElementClick =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; WebDriverCommand::ElementClick(element) &gt;- }, &gt;+ } &gt; Route::ElementTap =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; WebDriverCommand::ElementTap(element) &gt;- }, &gt;+ } &gt; Route::ElementClear =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; WebDriverCommand::ElementClear(element) &gt;- }, &gt;+ } &gt; Route::ElementSendKeys =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; let parameters: SendKeysParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::ElementSendKeys(element, parameters) &gt;- }, &gt;+ } &gt; Route::ExecuteScript =&gt; { &gt;- let parameters: JavascriptCommandParameters = try!(Parameters::from_json(&amp;body_data)); &gt;+ let parameters: JavascriptCommandParameters = &gt;+ try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::ExecuteScript(parameters) &gt;- }, &gt;+ } &gt; Route::ExecuteAsyncScript =&gt; { &gt;- let parameters: JavascriptCommandParameters = try!(Parameters::from_json(&amp;body_data)); &gt;+ let parameters: JavascriptCommandParameters = &gt;+ try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::ExecuteAsyncScript(parameters) &gt;- }, &gt;- Route::GetCookies =&gt; { &gt;- WebDriverCommand::GetCookies &gt;- }, &gt;+ } &gt;+ Route::GetCookies =&gt; WebDriverCommand::GetCookies, &gt; Route::GetNamedCookie =&gt; { &gt;- let name = try_opt!(params.name("name"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'name' parameter").as_str().into(); &gt;+ let name = try_opt!( &gt;+ params.name("name"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'name' parameter" &gt;+ ).as_str() &gt;+ .into(); &gt; WebDriverCommand::GetNamedCookie(name) &gt;- }, &gt;+ } &gt; Route::AddCookie =&gt; { &gt; let parameters: AddCookieParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::AddCookie(parameters) &gt;- }, &gt;- Route::DeleteCookies =&gt; { &gt;- WebDriverCommand::DeleteCookies &gt;- }, &gt;+ } &gt;+ Route::DeleteCookies =&gt; WebDriverCommand::DeleteCookies, &gt; Route::DeleteCookie =&gt; { &gt;- let name = try_opt!(params.name("name"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing name parameter").as_str().into(); &gt;+ let name = try_opt!( &gt;+ params.name("name"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing name parameter" &gt;+ ).as_str() &gt;+ .into(); &gt; WebDriverCommand::DeleteCookie(name) &gt;- }, &gt;+ } &gt; Route::PerformActions =&gt; { &gt; let parameters: ActionsParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::PerformActions(parameters) &gt;- }, &gt;- Route::ReleaseActions =&gt; { &gt;- WebDriverCommand::ReleaseActions &gt;- }, &gt;- Route::DismissAlert =&gt; { &gt;- WebDriverCommand::DismissAlert &gt;- }, &gt;- Route::AcceptAlert =&gt; { &gt;- WebDriverCommand::AcceptAlert &gt;- }, &gt;- Route::GetAlertText =&gt; { &gt;- WebDriverCommand::GetAlertText &gt;- }, &gt;+ } &gt;+ Route::ReleaseActions =&gt; WebDriverCommand::ReleaseActions, &gt;+ Route::DismissAlert =&gt; WebDriverCommand::DismissAlert, &gt;+ Route::AcceptAlert =&gt; WebDriverCommand::AcceptAlert, &gt;+ Route::GetAlertText =&gt; WebDriverCommand::GetAlertText, &gt; Route::SendAlertText =&gt; { &gt; let parameters: SendKeysParameters = try!(Parameters::from_json(&amp;body_data)); &gt; WebDriverCommand::SendAlertText(parameters) &gt;- }, &gt;+ } &gt; Route::TakeScreenshot =&gt; WebDriverCommand::TakeScreenshot, &gt;- Route::TakeElementScreenshot =&gt; { &gt;- let element_id = try_opt!(params.name("elementId"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing elementId parameter"); &gt;+ Route::TakeElementScreenshot =&gt; { &gt;+ let element_id = try_opt!( &gt;+ params.name("elementId"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing elementId parameter" &gt;+ ); &gt; let element = WebElement::new(element_id.as_str().into()); &gt; WebDriverCommand::TakeElementScreenshot(element) &gt;- }, &gt;+ } &gt; Route::Status =&gt; WebDriverCommand::Status, &gt;- Route::Extension(ref extension) =&gt; { &gt;- try!(extension.command(params, &amp;body_data)) &gt;- } &gt;+ Route::Extension(ref extension) =&gt; try!(extension.command(params, &amp;body_data)), &gt; }; &gt; Ok(WebDriverMessage::new(session_id, command)) &gt; } &gt; &gt; fn get_session_id(params: &amp;Captures) -&gt; Option&lt;String&gt; { &gt; params.name("sessionId").map(|x| x.as_str().into()) &gt; } &gt; &gt; fn decode_body(body: &amp;str, requires_body: bool) -&gt; WebDriverResult&lt;Json&gt; { &gt; if requires_body { &gt; match Json::from_str(body) { &gt; Ok(x @ Json::Object(_)) =&gt; Ok(x), &gt;- Ok(_) =&gt; { &gt;- Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Body was not a JSON Object")) &gt;- } &gt;+ Ok(_) =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Body was not a JSON Object", &gt;+ )), &gt; Err(json::ParserError::SyntaxError(_, line, col)) =&gt; { &gt; let msg = format!("Failed to decode request as JSON: \"{}\"", body); &gt; let stack = format!("Syntax error at :{}:{}", line, col); &gt;- Err(WebDriverError::new_with_stack(ErrorStatus::InvalidArgument, msg, stack)) &gt;- } &gt;- Err(json::ParserError::IoError(e)) =&gt; { &gt;- Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- format!("I/O error whilst decoding body: {}", e))) &gt;+ Err(WebDriverError::new_with_stack( &gt;+ ErrorStatus::InvalidArgument, &gt;+ msg, &gt;+ stack, &gt;+ )) &gt; } &gt;+ Err(json::ParserError::IoError(e)) =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("I/O error whilst decoding body: {}", e), &gt;+ )), &gt; } &gt; } else { &gt; Ok(Json::Null) &gt; } &gt; } &gt; } &gt; &gt;-impl &lt;U:WebDriverExtensionRoute&gt; ToJson for WebDriverMessage&lt;U&gt; { &gt;+impl&lt;U: WebDriverExtensionRoute&gt; ToJson for WebDriverMessage&lt;U&gt; { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let parameters = match self.command { &gt;- WebDriverCommand::AcceptAlert | &gt;- WebDriverCommand::CloseWindow | &gt;- WebDriverCommand::ReleaseActions | &gt;- WebDriverCommand::DeleteCookie(_) | &gt;- WebDriverCommand::DeleteCookies | &gt;- WebDriverCommand::DeleteSession | &gt;- WebDriverCommand::DismissAlert | &gt;- WebDriverCommand::ElementClear(_) | &gt;- WebDriverCommand::ElementClick(_) | &gt;- WebDriverCommand::ElementTap(_) | &gt;- WebDriverCommand::GetActiveElement | &gt;- WebDriverCommand::GetAlertText | &gt;- WebDriverCommand::GetNamedCookie(_) | &gt;- WebDriverCommand::GetCookies | &gt;- WebDriverCommand::GetCSSValue(_, _) | &gt;- WebDriverCommand::GetCurrentUrl | &gt;- WebDriverCommand::GetElementAttribute(_, _) | &gt;- WebDriverCommand::GetElementProperty(_, _) | &gt;- WebDriverCommand::GetElementRect(_) | &gt;- WebDriverCommand::GetElementTagName(_) | &gt;- WebDriverCommand::GetElementText(_) | &gt;- WebDriverCommand::GetPageSource | &gt;- WebDriverCommand::GetTimeouts | &gt;- WebDriverCommand::GetTitle | &gt;- WebDriverCommand::GetWindowHandle | &gt;- WebDriverCommand::GetWindowHandles | &gt;- WebDriverCommand::GetWindowRect | &gt;- WebDriverCommand::GoBack | &gt;- WebDriverCommand::GoForward | &gt;- WebDriverCommand::IsDisplayed(_) | &gt;- WebDriverCommand::IsEnabled(_) | &gt;- WebDriverCommand::IsSelected(_) | &gt;- WebDriverCommand::MinimizeWindow | &gt;- WebDriverCommand::MaximizeWindow | &gt;- WebDriverCommand::FullscreenWindow | &gt;- WebDriverCommand::NewSession(_) | &gt;- WebDriverCommand::Refresh | &gt;- WebDriverCommand::Status | &gt;- WebDriverCommand::SwitchToParentFrame | &gt;- WebDriverCommand::TakeElementScreenshot(_) | &gt;- WebDriverCommand::TakeScreenshot =&gt; { &gt;- None &gt;- }, &gt;+ WebDriverCommand::AcceptAlert &gt;+ | WebDriverCommand::CloseWindow &gt;+ | WebDriverCommand::ReleaseActions &gt;+ | WebDriverCommand::DeleteCookie(_) &gt;+ | WebDriverCommand::DeleteCookies &gt;+ | WebDriverCommand::DeleteSession &gt;+ | WebDriverCommand::DismissAlert &gt;+ | WebDriverCommand::ElementClear(_) &gt;+ | WebDriverCommand::ElementClick(_) &gt;+ | WebDriverCommand::ElementTap(_) &gt;+ | WebDriverCommand::GetActiveElement &gt;+ | WebDriverCommand::GetAlertText &gt;+ | WebDriverCommand::GetNamedCookie(_) &gt;+ | WebDriverCommand::GetCookies &gt;+ | WebDriverCommand::GetCSSValue(_, _) &gt;+ | WebDriverCommand::GetCurrentUrl &gt;+ | WebDriverCommand::GetElementAttribute(_, _) &gt;+ | WebDriverCommand::GetElementProperty(_, _) &gt;+ | WebDriverCommand::GetElementRect(_) &gt;+ | WebDriverCommand::GetElementTagName(_) &gt;+ | WebDriverCommand::GetElementText(_) &gt;+ | WebDriverCommand::GetPageSource &gt;+ | WebDriverCommand::GetTimeouts &gt;+ | WebDriverCommand::GetTitle &gt;+ | WebDriverCommand::GetWindowHandle &gt;+ | WebDriverCommand::GetWindowHandles &gt;+ | WebDriverCommand::GetWindowRect &gt;+ | WebDriverCommand::GoBack &gt;+ | WebDriverCommand::GoForward &gt;+ | WebDriverCommand::IsDisplayed(_) &gt;+ | WebDriverCommand::IsEnabled(_) &gt;+ | WebDriverCommand::IsSelected(_) &gt;+ | WebDriverCommand::MinimizeWindow &gt;+ | WebDriverCommand::MaximizeWindow &gt;+ | WebDriverCommand::FullscreenWindow &gt;+ | WebDriverCommand::NewSession(_) &gt;+ | WebDriverCommand::Refresh &gt;+ | WebDriverCommand::Status &gt;+ | WebDriverCommand::SwitchToParentFrame &gt;+ | WebDriverCommand::TakeElementScreenshot(_) &gt;+ | WebDriverCommand::TakeScreenshot =&gt; None, &gt; &gt; WebDriverCommand::AddCookie(ref x) =&gt; Some(x.to_json()), &gt; WebDriverCommand::ElementSendKeys(_, ref x) =&gt; Some(x.to_json()), &gt;- WebDriverCommand::ExecuteAsyncScript(ref x) | &gt;- WebDriverCommand::ExecuteScript(ref x) =&gt; Some(x.to_json()), &gt;+ WebDriverCommand::ExecuteAsyncScript(ref x) &gt;+ | WebDriverCommand::ExecuteScript(ref x) =&gt; Some(x.to_json()), &gt; WebDriverCommand::FindElementElement(_, ref x) =&gt; Some(x.to_json()), &gt; WebDriverCommand::FindElementElements(_, ref x) =&gt; Some(x.to_json()), &gt; WebDriverCommand::FindElement(ref x) =&gt; Some(x.to_json()), &gt; WebDriverCommand::FindElements(ref x) =&gt; Some(x.to_json()), &gt; WebDriverCommand::Get(ref x) =&gt; Some(x.to_json()), &gt; WebDriverCommand::PerformActions(ref x) =&gt; Some(x.to_json()), &gt; WebDriverCommand::SendAlertText(ref x) =&gt; Some(x.to_json()), &gt; WebDriverCommand::SetTimeouts(ref x) =&gt; Some(x.to_json()), &gt;@@ -454,64 +494,77 @@ pub trait Parameters: Sized { &gt; #[derive(Debug, PartialEq)] &gt; pub enum NewSessionParameters { &gt; Spec(SpecNewSessionParameters), &gt; Legacy(LegacyNewSessionParameters), &gt; } &gt; &gt; impl Parameters for NewSessionParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;NewSessionParameters&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::UnknownError, &gt;- "Message body was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Message body was not an object" &gt;+ ); &gt; if data.get("capabilities").is_some() { &gt;- Ok(NewSessionParameters::Spec(try!(SpecNewSessionParameters::from_json(body)))) &gt;+ Ok(NewSessionParameters::Spec(try!( &gt;+ SpecNewSessionParameters::from_json(body) &gt;+ ))) &gt; } else { &gt;- Ok(NewSessionParameters::Legacy(try!(LegacyNewSessionParameters::from_json(body)))) &gt;+ Ok(NewSessionParameters::Legacy(try!( &gt;+ LegacyNewSessionParameters::from_json(body) &gt;+ ))) &gt; } &gt; } &gt; } &gt; &gt; impl ToJson for NewSessionParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; match self { &gt; &amp;NewSessionParameters::Spec(ref x) =&gt; x.to_json(), &gt;- &amp;NewSessionParameters::Legacy(ref x) =&gt; x.to_json() &gt;+ &amp;NewSessionParameters::Legacy(ref x) =&gt; x.to_json(), &gt; } &gt; } &gt; } &gt; &gt; impl CapabilitiesMatching for NewSessionParameters { &gt;- fn match_browser&lt;T: BrowserCapabilities&gt;(&amp;self, browser_capabilities: &amp;mut T) &gt;- -&gt; WebDriverResult&lt;Option&lt;Capabilities&gt;&gt; { &gt;+ fn match_browser&lt;T: BrowserCapabilities&gt;( &gt;+ &amp;self, &gt;+ browser_capabilities: &amp;mut T, &gt;+ ) -&gt; WebDriverResult&lt;Option&lt;Capabilities&gt;&gt; { &gt; match self { &gt; &amp;NewSessionParameters::Spec(ref x) =&gt; x.match_browser(browser_capabilities), &gt;- &amp;NewSessionParameters::Legacy(ref x) =&gt; x.match_browser(browser_capabilities) &gt;+ &amp;NewSessionParameters::Legacy(ref x) =&gt; x.match_browser(browser_capabilities), &gt; } &gt; } &gt; } &gt; &gt;- &gt; #[derive(Debug, PartialEq)] &gt; pub struct GetParameters { &gt;- pub url: String &gt;+ pub url: String, &gt; } &gt; &gt; impl Parameters for GetParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;GetParameters&gt; { &gt;- let data = try_opt!(body.as_object(), ErrorStatus::UnknownError, &gt;- "Message body was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Message body was not an object" &gt;+ ); &gt; let url = try_opt!( &gt;- try_opt!(data.get("url"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'url' parameter").as_string(), &gt;+ try_opt!( &gt;+ data.get("url"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'url' parameter" &gt;+ ).as_string(), &gt; ErrorStatus::InvalidArgument, &gt;- "'url' not a string"); &gt;+ "'url' not a string" &gt;+ ); &gt; Ok(GetParameters { &gt;- url: url.to_string() &gt;+ url: url.to_string(), &gt; }) &gt; } &gt; } &gt; &gt; impl ToJson for GetParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("url".to_string(), self.url.to_json()); &gt;@@ -523,44 +576,46 @@ impl ToJson for GetParameters { &gt; pub struct TimeoutsParameters { &gt; pub script: Option&lt;u64&gt;, &gt; pub page_load: Option&lt;u64&gt;, &gt; pub implicit: Option&lt;u64&gt;, &gt; } &gt; &gt; impl Parameters for TimeoutsParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;TimeoutsParameters&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::UnknownError, &gt;- "Message body was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Message body was not an object" &gt;+ ); &gt; &gt; let script = match data.get("script") { &gt;- Some(json) =&gt; { &gt;- Some(try_opt!(json.as_u64(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Script timeout duration was not a signed integer")) &gt;- } &gt;+ Some(json) =&gt; Some(try_opt!( &gt;+ json.as_u64(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Script timeout duration was not a signed integer" &gt;+ )), &gt; None =&gt; None, &gt; }; &gt; &gt; let page_load = match data.get("pageLoad") { &gt;- Some(json) =&gt; { &gt;- Some(try_opt!(json.as_u64(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Page load timeout duration was not a signed integer")) &gt;- } &gt;+ Some(json) =&gt; Some(try_opt!( &gt;+ json.as_u64(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Page load timeout duration was not a signed integer" &gt;+ )), &gt; None =&gt; None, &gt; }; &gt; &gt; let implicit = match data.get("implicit") { &gt;- Some(json) =&gt; { &gt;- Some(try_opt!(json.as_u64(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Implicit timeout duration was not a signed integer")) &gt;- } &gt;+ Some(json) =&gt; Some(try_opt!( &gt;+ json.as_u64(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Implicit timeout duration was not a signed integer" &gt;+ )), &gt; None =&gt; None, &gt; }; &gt; &gt; Ok(TimeoutsParameters { &gt; script: script, &gt; page_load: page_load, &gt; implicit: implicit, &gt; }) &gt;@@ -598,18 +653,21 @@ pub struct WindowRectParameters { &gt; pub x: Nullable&lt;i32&gt;, &gt; pub y: Nullable&lt;i32&gt;, &gt; pub width: Nullable&lt;i32&gt;, &gt; pub height: Nullable&lt;i32&gt;, &gt; } &gt; &gt; impl Parameters for WindowRectParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;WindowRectParameters&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::InvalidArgument, "Message body was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Message body was not an object" &gt;+ ); &gt; &gt; let x = match data.get("x") { &gt; Some(json) =&gt; try!(Nullable::from_json(json, |n| { &gt; let x = try_opt!( &gt; n.as_f64(), &gt; ErrorStatus::InvalidArgument, &gt; "'x' is not a number" &gt; ) as i64; &gt;@@ -673,191 +731,220 @@ impl Parameters for WindowRectParameters { &gt; "'height' is larger than i32", &gt; )); &gt; } &gt; Ok(height as i32) &gt; })), &gt; None =&gt; Nullable::Null, &gt; }; &gt; &gt;- Ok(WindowRectParameters { x, y, width, height }) &gt;+ Ok(WindowRectParameters { &gt;+ x, &gt;+ y, &gt;+ width, &gt;+ height, &gt;+ }) &gt; } &gt; } &gt; &gt; impl ToJson for WindowRectParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("x".to_string(), self.x.to_json()); &gt; data.insert("y".to_string(), self.y.to_json()); &gt; data.insert("width".to_string(), self.width.to_json()); &gt; data.insert("height".to_string(), self.height.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct SwitchToWindowParameters { &gt;- pub handle: String &gt;+ pub handle: String, &gt; } &gt; &gt; impl Parameters for SwitchToWindowParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;SwitchToWindowParameters&gt; { &gt;- let data = try_opt!(body.as_object(), ErrorStatus::UnknownError, &gt;- "Message body was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Message body was not an object" &gt;+ ); &gt; let handle = try_opt!( &gt;- try_opt!(data.get("handle"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'handle' parameter").as_string(), &gt;+ try_opt!( &gt;+ data.get("handle"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'handle' parameter" &gt;+ ).as_string(), &gt; ErrorStatus::InvalidArgument, &gt;- "'handle' not a string"); &gt;+ "'handle' not a string" &gt;+ ); &gt; return Ok(SwitchToWindowParameters { &gt;- handle: handle.to_string() &gt;- }) &gt;+ handle: handle.to_string(), &gt;+ }); &gt; } &gt; } &gt; &gt; impl ToJson for SwitchToWindowParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("handle".to_string(), self.handle.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct LocatorParameters { &gt; pub using: LocatorStrategy, &gt;- pub value: String &gt;+ pub value: String, &gt; } &gt; &gt; impl Parameters for LocatorParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;LocatorParameters&gt; { &gt;- let data = try_opt!(body.as_object(), ErrorStatus::UnknownError, &gt;- "Message body was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Message body was not an object" &gt;+ ); &gt; &gt;- let using = try!(LocatorStrategy::from_json( &gt;- try_opt!(data.get("using"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'using' parameter"))); &gt;+ let using = try!(LocatorStrategy::from_json(try_opt!( &gt;+ data.get("using"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'using' parameter" &gt;+ ))); &gt; &gt; let value = try_opt!( &gt;- try_opt!(data.get("value"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'value' parameter").as_string(), &gt;+ try_opt!( &gt;+ data.get("value"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'value' parameter" &gt;+ ).as_string(), &gt; ErrorStatus::InvalidArgument, &gt;- "Could not convert using to string").to_string(); &gt;+ "Could not convert using to string" &gt;+ ).to_string(); &gt; &gt; return Ok(LocatorParameters { &gt; using: using, &gt;- value: value &gt;- }) &gt;+ value: value, &gt;+ }); &gt; } &gt; } &gt; &gt; impl ToJson for LocatorParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("using".to_string(), self.using.to_json()); &gt; data.insert("value".to_string(), self.value.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct SwitchToFrameParameters { &gt;- pub id: FrameId &gt;+ pub id: FrameId, &gt; } &gt; &gt; impl Parameters for SwitchToFrameParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;SwitchToFrameParameters&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::UnknownError, &gt;- "Message body was not an object"); &gt;- let id = try!(FrameId::from_json(try_opt!(data.get("id"), &gt;- ErrorStatus::UnknownError, &gt;- "Missing 'id' parameter"))); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::UnknownError, &gt;+ "Message body was not an object" &gt;+ ); &gt;+ let id = try!(FrameId::from_json(try_opt!( &gt;+ data.get("id"), &gt;+ ErrorStatus::UnknownError, &gt;+ "Missing 'id' parameter" &gt;+ ))); &gt; &gt;- Ok(SwitchToFrameParameters { &gt;- id: id &gt;- }) &gt;+ Ok(SwitchToFrameParameters { id: id }) &gt; } &gt; } &gt; &gt; impl ToJson for SwitchToFrameParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("id".to_string(), self.id.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct SendKeysParameters { &gt;- pub text: String &gt;+ pub text: String, &gt; } &gt; &gt; impl Parameters for SendKeysParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;SendKeysParameters&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Message body was not an object"); &gt;- let text = try_opt!(try_opt!(data.get("text"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'text' parameter").as_string(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Could not convert 'text' to string"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Message body was not an object" &gt;+ ); &gt;+ let text = try_opt!( &gt;+ try_opt!( &gt;+ data.get("text"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'text' parameter" &gt;+ ).as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Could not convert 'text' to string" &gt;+ ); &gt; &gt;- Ok(SendKeysParameters { &gt;- text: text.into() &gt;- }) &gt;+ Ok(SendKeysParameters { text: text.into() }) &gt; } &gt; } &gt; &gt; impl ToJson for SendKeysParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("value".to_string(), self.text.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct JavascriptCommandParameters { &gt; pub script: String, &gt;- pub args: Nullable&lt;Vec&lt;Json&gt;&gt; &gt;+ pub args: Nullable&lt;Vec&lt;Json&gt;&gt;, &gt; } &gt; &gt; impl Parameters for JavascriptCommandParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;JavascriptCommandParameters&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Message body was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Message body was not an object" &gt;+ ); &gt; &gt;- let args_json = try_opt!(data.get("args"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing args parameter"); &gt;+ let args_json = try_opt!( &gt;+ data.get("args"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing args parameter" &gt;+ ); &gt; &gt;- let args = try!(Nullable::from_json( &gt;- args_json, &gt;- |x| { &gt;- Ok((try_opt!(x.as_array(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Failed to convert args to Array")).clone()) &gt;- })); &gt;+ let args = try!(Nullable::from_json(args_json, |x| Ok((try_opt!( &gt;+ x.as_array(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Failed to convert args to Array" &gt;+ )).clone()))); &gt; &gt;- //TODO: Look for WebElements in args? &gt;+ //TODO: Look for WebElements in args? &gt; let script = try_opt!( &gt;- try_opt!(data.get("script"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing script parameter").as_string(), &gt;+ try_opt!( &gt;+ data.get("script"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing script parameter" &gt;+ ).as_string(), &gt; ErrorStatus::InvalidArgument, &gt;- "Failed to convert script to String"); &gt;+ "Failed to convert script to String" &gt;+ ); &gt; Ok(JavascriptCommandParameters { &gt; script: script.to_string(), &gt;- args: args.clone() &gt;+ args: args.clone(), &gt; }) &gt; } &gt; } &gt; &gt; impl ToJson for JavascriptCommandParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; //TODO: Wrap script so that it becomes marionette-compatible &gt;@@ -869,28 +956,31 @@ impl ToJson for JavascriptCommandParameters { &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct GetNamedCookieParameters { &gt; pub name: Nullable&lt;String&gt;, &gt; } &gt; &gt; impl Parameters for GetNamedCookieParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;GetNamedCookieParameters&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Message body was not an object"); &gt;- let name_json = try_opt!(data.get("name"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'name' parameter"); &gt;- let name = try!(Nullable::from_json(name_json, |x| { &gt;- Ok(try_opt!(x.as_string(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Failed to convert name to string") &gt;- .to_string()) &gt;- })); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Message body was not an object" &gt;+ ); &gt;+ let name_json = try_opt!( &gt;+ data.get("name"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'name' parameter" &gt;+ ); &gt;+ let name = try!(Nullable::from_json(name_json, |x| Ok(try_opt!( &gt;+ x.as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Failed to convert name to string" &gt;+ ).to_string()))); &gt; return Ok(GetNamedCookieParameters { name: name }); &gt; } &gt; } &gt; &gt; impl ToJson for GetNamedCookieParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("name".to_string(), self.name.to_json()); &gt;@@ -901,106 +991,110 @@ impl ToJson for GetNamedCookieParameters { &gt; #[derive(Debug, PartialEq)] &gt; pub struct AddCookieParameters { &gt; pub name: String, &gt; pub value: String, &gt; pub path: Nullable&lt;String&gt;, &gt; pub domain: Nullable&lt;String&gt;, &gt; pub expiry: Nullable&lt;Date&gt;, &gt; pub secure: bool, &gt;- pub httpOnly: bool &gt;+ pub httpOnly: bool, &gt; } &gt; &gt; impl Parameters for AddCookieParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;AddCookieParameters&gt; { &gt; if !body.is_object() { &gt;- return Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- "Message body was not an object")); &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Message body was not an object", &gt;+ )); &gt; } &gt; &gt;- let data = try_opt!(body.find("cookie").and_then(|x| x.as_object()), &gt;- ErrorStatus::InvalidArgument, &gt;- "Cookie parameter not found or not an object"); &gt;+ let data = try_opt!( &gt;+ body.find("cookie").and_then(|x| x.as_object()), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Cookie parameter not found or not an object" &gt;+ ); &gt; &gt; let name = try_opt!( &gt;- try_opt!(data.get("name"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'name' parameter").as_string(), &gt;+ try_opt!( &gt;+ data.get("name"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'name' parameter" &gt;+ ).as_string(), &gt; ErrorStatus::InvalidArgument, &gt;- "'name' is not a string").to_string(); &gt;+ "'name' is not a string" &gt;+ ).to_string(); &gt; &gt; let value = try_opt!( &gt;- try_opt!(data.get("value"), &gt;- ErrorStatus::InvalidArgument, &gt;- "Missing 'value' parameter").as_string(), &gt;+ try_opt!( &gt;+ data.get("value"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Missing 'value' parameter" &gt;+ ).as_string(), &gt; ErrorStatus::InvalidArgument, &gt;- "'value' is not a string").to_string(); &gt;+ "'value' is not a string" &gt;+ ).to_string(); &gt; &gt; let path = match data.get("path") { &gt;- Some(path_json) =&gt; { &gt;- try!(Nullable::from_json( &gt;- path_json, &gt;- |x| { &gt;- Ok(try_opt!(x.as_string(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Failed to convert path to String").to_string()) &gt;- })) &gt;- }, &gt;- None =&gt; Nullable::Null &gt;+ Some(path_json) =&gt; try!(Nullable::from_json(path_json, |x| Ok(try_opt!( &gt;+ x.as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Failed to convert path to String" &gt;+ ).to_string()))), &gt;+ None =&gt; Nullable::Null, &gt; }; &gt; &gt; let domain = match data.get("domain") { &gt;- Some(domain_json) =&gt; { &gt;- try!(Nullable::from_json( &gt;- domain_json, &gt;- |x| { &gt;- Ok(try_opt!(x.as_string(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Failed to convert domain to String").to_string()) &gt;- })) &gt;- }, &gt;- None =&gt; Nullable::Null &gt;+ Some(domain_json) =&gt; try!(Nullable::from_json(domain_json, |x| Ok(try_opt!( &gt;+ x.as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Failed to convert domain to String" &gt;+ ).to_string()))), &gt;+ None =&gt; Nullable::Null, &gt; }; &gt; &gt; let expiry = match data.get("expiry") { &gt;- Some(expiry_json) =&gt; { &gt;- try!(Nullable::from_json( &gt;- expiry_json, &gt;- |x| { &gt;- Ok(Date::new(try_opt!(x.as_u64(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Failed to convert expiry to Date"))) &gt;- })) &gt;- }, &gt;- None =&gt; Nullable::Null &gt;+ Some(expiry_json) =&gt; try!(Nullable::from_json(expiry_json, |x| Ok(Date::new( &gt;+ try_opt!( &gt;+ x.as_u64(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Failed to convert expiry to Date" &gt;+ ) &gt;+ )))), &gt;+ None =&gt; Nullable::Null, &gt; }; &gt; &gt; let secure = match data.get("secure") { &gt;- Some(x) =&gt; try_opt!(x.as_boolean(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Failed to convert secure to boolean"), &gt;- None =&gt; false &gt;+ Some(x) =&gt; try_opt!( &gt;+ x.as_boolean(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Failed to convert secure to boolean" &gt;+ ), &gt;+ None =&gt; false, &gt; }; &gt; &gt; let http_only = match data.get("httpOnly") { &gt;- Some(x) =&gt; try_opt!(x.as_boolean(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Failed to convert httpOnly to boolean"), &gt;- None =&gt; false &gt;+ Some(x) =&gt; try_opt!( &gt;+ x.as_boolean(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Failed to convert httpOnly to boolean" &gt;+ ), &gt;+ None =&gt; false, &gt; }; &gt; &gt; return Ok(AddCookieParameters { &gt; name: name, &gt; value: value, &gt; path: path, &gt; domain: domain, &gt; expiry: expiry, &gt; secure: secure, &gt;- httpOnly: http_only &gt;- }) &gt;+ httpOnly: http_only, &gt;+ }); &gt; } &gt; } &gt; &gt; impl ToJson for AddCookieParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("name".to_string(), self.name.to_json()); &gt; data.insert("value".to_string(), self.value.to_json()); &gt;@@ -1010,87 +1104,94 @@ impl ToJson for AddCookieParameters { &gt; data.insert("secure".to_string(), self.secure.to_json()); &gt; data.insert("httpOnly".to_string(), self.httpOnly.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct TakeScreenshotParameters { &gt;- pub element: Nullable&lt;WebElement&gt; &gt;+ pub element: Nullable&lt;WebElement&gt;, &gt; } &gt; &gt; impl Parameters for TakeScreenshotParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;TakeScreenshotParameters&gt; { &gt;- let data = try_opt!(body.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Message body was not an object"); &gt;+ let data = try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Message body was not an object" &gt;+ ); &gt; let element = match data.get("element") { &gt;- Some(element_json) =&gt; try!(Nullable::from_json( &gt;- element_json, &gt;- |x| { &gt;- Ok(try!(WebElement::from_json(x))) &gt;- })), &gt;- None =&gt; Nullable::Null &gt;+ Some(element_json) =&gt; try!(Nullable::from_json(element_json, |x| Ok(try!( &gt;+ WebElement::from_json(x) &gt;+ )))), &gt;+ None =&gt; Nullable::Null, &gt; }; &gt; &gt;- return Ok(TakeScreenshotParameters { &gt;- element: element &gt;- }) &gt;+ return Ok(TakeScreenshotParameters { element: element }); &gt; } &gt; } &gt; &gt; impl ToJson for TakeScreenshotParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert("element".to_string(), self.element.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub struct ActionsParameters { &gt;- pub actions: Vec&lt;ActionSequence&gt; &gt;+ pub actions: Vec&lt;ActionSequence&gt;, &gt; } &gt; &gt; impl Parameters for ActionsParameters { &gt; fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;ActionsParameters&gt; { &gt;- try_opt!(body.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Message body was not an object"); &gt;+ try_opt!( &gt;+ body.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Message body was not an object" &gt;+ ); &gt; let actions = try_opt!( &gt;- try_opt!(body.find("actions"), &gt;- ErrorStatus::InvalidArgument, &gt;- "No actions parameter found").as_array(), &gt;+ try_opt!( &gt;+ body.find("actions"), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "No actions parameter found" &gt;+ ).as_array(), &gt; ErrorStatus::InvalidArgument, &gt;- "Parameter 'actions' was not an array"); &gt;+ "Parameter 'actions' was not an array" &gt;+ ); &gt; &gt; let mut result = Vec::with_capacity(actions.len()); &gt; for chain in actions.iter() { &gt; result.push(try!(ActionSequence::from_json(chain))); &gt; } &gt;- Ok(ActionsParameters { &gt;- actions: result &gt;- }) &gt;+ Ok(ActionsParameters { actions: result }) &gt; } &gt; } &gt; &gt; impl ToJson for ActionsParameters { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt;- data.insert("actions".to_owned(), &gt;- self.actions.iter().map(|x| x.to_json()).collect::&lt;Vec&lt;Json&gt;&gt;().to_json()); &gt;+ data.insert( &gt;+ "actions".to_owned(), &gt;+ self.actions &gt;+ .iter() &gt;+ .map(|x| x.to_json()) &gt;+ .collect::&lt;Vec&lt;Json&gt;&gt;() &gt;+ .to_json(), &gt;+ ); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt; #[cfg(test)] &gt; mod tests { &gt;- use rustc_serialize::json::Json; &gt; use super::{Nullable, Parameters, WindowRectParameters}; &gt;+ use rustc_serialize::json::Json; &gt; &gt; #[test] &gt; fn test_window_rect() { &gt; let expected = WindowRectParameters { &gt; x: Nullable::Value(0i32), &gt; y: Nullable::Value(1i32), &gt; width: Nullable::Value(2i32), &gt; height: Nullable::Value(3i32), &gt;@@ -1126,12 +1227,13 @@ mod tests { &gt; #[test] &gt; fn test_window_rect_floats() { &gt; let expected = WindowRectParameters { &gt; x: Nullable::Value(1i32), &gt; y: Nullable::Value(2i32), &gt; width: Nullable::Value(3i32), &gt; height: Nullable::Value(4i32), &gt; }; &gt;- let actual = Json::from_str(r#"{"x": 1.1, "y": 2.2, "width": 3.3, "height": 4.4}"#).unwrap(); &gt;+ let actual = &gt;+ Json::from_str(r#"{"x": 1.1, "y": 2.2, "width": 3.3, "height": 4.4}"#).unwrap(); &gt; assert_eq!(expected, Parameters::from_json(&amp;actual).unwrap()); &gt; } &gt; } &gt;diff --git a/testing/webdriver/src/common.rs b/testing/webdriver/src/common.rs &gt;index 5a0f3398baa2..c13f3d28abcf 100644 &gt;--- a/testing/webdriver/src/common.rs &gt;+++ b/testing/webdriver/src/common.rs &gt;@@ -1,13 +1,13 @@ &gt;-use rustc_serialize::{Encodable, Encoder}; &gt; use rustc_serialize::json::{Json, ToJson}; &gt;+use rustc_serialize::{Encodable, Encoder}; &gt; use std::collections::BTreeMap; &gt; &gt;-use error::{WebDriverResult, WebDriverError, ErrorStatus}; &gt;+use error::{ErrorStatus, WebDriverError, WebDriverResult}; &gt; &gt; pub static ELEMENT_KEY: &amp;'static str = "element-6066-11e4-a52e-4f735466cecf"; &gt; pub static FRAME_KEY: &amp;'static str = "frame-075b-4da1-b6ba-e579c2d3230a"; &gt; pub static WINDOW_KEY: &amp;'static str = "window-fcc6-11e5-b4f8-330a88ab9d7f"; &gt; &gt; #[derive(Clone, Debug, PartialEq, RustcEncodable)] &gt; pub struct Date(pub u64); &gt; &gt;@@ -22,203 +22,217 @@ impl ToJson for Date { &gt; let &amp;Date(x) = self; &gt; x.to_json() &gt; } &gt; } &gt; &gt; #[derive(Clone, Debug, PartialEq)] &gt; pub enum Nullable&lt;T: ToJson&gt; { &gt; Value(T), &gt;- Null &gt;+ Null, &gt; } &gt; &gt; impl&lt;T: ToJson&gt; Nullable&lt;T&gt; { &gt;- pub fn is_null(&amp;self) -&gt; bool { &gt;+ pub fn is_null(&amp;self) -&gt; bool { &gt; match *self { &gt; Nullable::Value(_) =&gt; false, &gt;- Nullable::Null =&gt; true &gt;+ Nullable::Null =&gt; true, &gt; } &gt; } &gt; &gt;- pub fn is_value(&amp;self) -&gt; bool { &gt;+ pub fn is_value(&amp;self) -&gt; bool { &gt; match *self { &gt; Nullable::Value(_) =&gt; true, &gt;- Nullable::Null =&gt; false &gt;+ Nullable::Null =&gt; false, &gt; } &gt; } &gt; &gt; pub fn map&lt;F, U: ToJson&gt;(self, f: F) -&gt; Nullable&lt;U&gt; &gt;- where F: FnOnce(T) -&gt; U { &gt;+ where &gt;+ F: FnOnce(T) -&gt; U, &gt;+ { &gt; match self { &gt; Nullable::Value(val) =&gt; Nullable::Value(f(val)), &gt;- Nullable::Null =&gt; Nullable::Null &gt;+ Nullable::Null =&gt; Nullable::Null, &gt; } &gt; } &gt; } &gt; &gt; impl&lt;T: ToJson&gt; Nullable&lt;T&gt; { &gt; //This is not very pretty &gt;- pub fn from_json&lt;F: FnOnce(&amp;Json) -&gt; WebDriverResult&lt;T&gt;&gt;(value: &amp;Json, f: F) -&gt; WebDriverResult&lt;Nullable&lt;T&gt;&gt; { &gt;+ pub fn from_json&lt;F: FnOnce(&amp;Json) -&gt; WebDriverResult&lt;T&gt;&gt;( &gt;+ value: &amp;Json, &gt;+ f: F, &gt;+ ) -&gt; WebDriverResult&lt;Nullable&lt;T&gt;&gt; { &gt; if value.is_null() { &gt; Ok(Nullable::Null) &gt; } else { &gt; Ok(Nullable::Value(try!(f(value)))) &gt; } &gt; } &gt; } &gt; &gt; impl&lt;T: ToJson&gt; ToJson for Nullable&lt;T&gt; { &gt; fn to_json(&amp;self) -&gt; Json { &gt; match *self { &gt; Nullable::Value(ref x) =&gt; x.to_json(), &gt;- Nullable::Null =&gt; Json::Null &gt;+ Nullable::Null =&gt; Json::Null, &gt; } &gt; } &gt; } &gt; &gt; impl&lt;T: ToJson&gt; Encodable for Nullable&lt;T&gt; { &gt; fn encode&lt;S: Encoder&gt;(&amp;self, s: &amp;mut S) -&gt; Result&lt;(), S::Error&gt; { &gt; match *self { &gt; Nullable::Value(ref x) =&gt; x.to_json().encode(s), &gt;- Nullable::Null =&gt; s.emit_option_none() &gt;+ Nullable::Null =&gt; s.emit_option_none(), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;T: ToJson&gt; Into&lt;Option&lt;T&gt;&gt; for Nullable&lt;T&gt; { &gt; fn into(self) -&gt; Option&lt;T&gt; { &gt; match self { &gt; Nullable::Value(val) =&gt; Some(val), &gt;- Nullable::Null =&gt; None &gt;+ Nullable::Null =&gt; None, &gt; } &gt; } &gt; } &gt; &gt; impl&lt;T: ToJson&gt; From&lt;Option&lt;T&gt;&gt; for Nullable&lt;T&gt; { &gt; fn from(option: Option&lt;T&gt;) -&gt; Nullable&lt;T&gt; { &gt; match option { &gt; Some(val) =&gt; Nullable::Value(val), &gt; None =&gt; Nullable::Null, &gt; } &gt; } &gt; } &gt; &gt; #[derive(Clone, Debug, PartialEq)] &gt; pub struct WebElement { &gt;- pub id: String &gt;+ pub id: String, &gt; } &gt; &gt; impl WebElement { &gt; pub fn new(id: String) -&gt; WebElement { &gt;- WebElement { &gt;- id: id &gt;- } &gt;+ WebElement { id: id } &gt; } &gt; &gt; pub fn from_json(data: &amp;Json) -&gt; WebDriverResult&lt;WebElement&gt; { &gt;- let object = try_opt!(data.as_object(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Could not convert webelement to object"); &gt;- let id_value = try_opt!(object.get(ELEMENT_KEY), &gt;- ErrorStatus::InvalidArgument, &gt;- "Could not find webelement key"); &gt;+ let object = try_opt!( &gt;+ data.as_object(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Could not convert webelement to object" &gt;+ ); &gt;+ let id_value = try_opt!( &gt;+ object.get(ELEMENT_KEY), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Could not find webelement key" &gt;+ ); &gt; &gt;- let id = try_opt!(id_value.as_string(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Could not convert web element to string").to_string(); &gt;+ let id = try_opt!( &gt;+ id_value.as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Could not convert web element to string" &gt;+ ).to_string(); &gt; &gt; Ok(WebElement::new(id)) &gt; } &gt; } &gt; &gt; impl ToJson for WebElement { &gt; fn to_json(&amp;self) -&gt; Json { &gt; let mut data = BTreeMap::new(); &gt; data.insert(ELEMENT_KEY.to_string(), self.id.to_json()); &gt; Json::Object(data) &gt; } &gt; } &gt; &gt;-impl &lt;T&gt; From&lt;T&gt; for WebElement &gt;- where T: Into&lt;String&gt; { &gt;+impl&lt;T&gt; From&lt;T&gt; for WebElement &gt;+where &gt;+ T: Into&lt;String&gt;, &gt;+{ &gt; fn from(data: T) -&gt; WebElement { &gt; WebElement::new(data.into()) &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum FrameId { &gt; Short(u16), &gt; Element(WebElement), &gt;- Null &gt;+ Null, &gt; } &gt; &gt; impl FrameId { &gt; pub fn from_json(data: &amp;Json) -&gt; WebDriverResult&lt;FrameId&gt; { &gt; match data { &gt; &amp;Json::U64(x) =&gt; { &gt; if x &gt; u16::max_value() as u64 || x &lt; u16::min_value() as u64 { &gt;- return Err(WebDriverError::new(ErrorStatus::NoSuchFrame, &gt;- "frame id out of range")) &gt;+ return Err(WebDriverError::new( &gt;+ ErrorStatus::NoSuchFrame, &gt;+ "frame id out of range", &gt;+ )); &gt; }; &gt; Ok(FrameId::Short(x as u16)) &gt;- }, &gt;+ } &gt; &amp;Json::Null =&gt; Ok(FrameId::Null), &gt;- &amp;Json::Object(_) =&gt; Ok(FrameId::Element( &gt;- try!(WebElement::from_json(data)))), &gt;- _ =&gt; Err(WebDriverError::new(ErrorStatus::NoSuchFrame, &gt;- "frame id has unexpected type")) &gt;+ &amp;Json::Object(_) =&gt; Ok(FrameId::Element(try!(WebElement::from_json(data)))), &gt;+ _ =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::NoSuchFrame, &gt;+ "frame id has unexpected type", &gt;+ )), &gt; } &gt; } &gt; } &gt; &gt; impl ToJson for FrameId { &gt; fn to_json(&amp;self) -&gt; Json { &gt; match *self { &gt;- FrameId::Short(x) =&gt; { &gt;- Json::U64(x as u64) &gt;- }, &gt;- FrameId::Element(ref x) =&gt; { &gt;- Json::String(x.id.clone()) &gt;- }, &gt;- FrameId::Null =&gt; { &gt;- Json::Null &gt;- } &gt;+ FrameId::Short(x) =&gt; Json::U64(x as u64), &gt;+ FrameId::Element(ref x) =&gt; Json::String(x.id.clone()), &gt;+ FrameId::Null =&gt; Json::Null, &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug, PartialEq)] &gt; pub enum LocatorStrategy { &gt; CSSSelector, &gt; LinkText, &gt; PartialLinkText, &gt; TagName, &gt; XPath, &gt; } &gt; &gt; impl LocatorStrategy { &gt; pub fn from_json(body: &amp;Json) -&gt; WebDriverResult&lt;LocatorStrategy&gt; { &gt;- match try_opt!(body.as_string(), &gt;- ErrorStatus::InvalidArgument, &gt;- "Expected locator strategy as string") { &gt;+ match try_opt!( &gt;+ body.as_string(), &gt;+ ErrorStatus::InvalidArgument, &gt;+ "Expected locator strategy as string" &gt;+ ) { &gt; "css selector" =&gt; Ok(LocatorStrategy::CSSSelector), &gt; "link text" =&gt; Ok(LocatorStrategy::LinkText), &gt; "partial link text" =&gt; Ok(LocatorStrategy::PartialLinkText), &gt; "tag name" =&gt; Ok(LocatorStrategy::TagName), &gt; "xpath" =&gt; Ok(LocatorStrategy::XPath), &gt;- x =&gt; Err(WebDriverError::new(ErrorStatus::InvalidArgument, &gt;- format!("Unknown locator strategy {}", x))) &gt;+ x =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidArgument, &gt;+ format!("Unknown locator strategy {}", x), &gt;+ )), &gt; } &gt; } &gt; } &gt; &gt; impl ToJson for LocatorStrategy { &gt; fn to_json(&amp;self) -&gt; Json { &gt;- Json::String(match *self { &gt;- LocatorStrategy::CSSSelector =&gt; "css selector", &gt;- LocatorStrategy::LinkText =&gt; "link text", &gt;- LocatorStrategy::PartialLinkText =&gt; "partial link text", &gt;- LocatorStrategy::TagName =&gt; "tag name", &gt;- LocatorStrategy::XPath =&gt; "xpath" &gt;- }.to_string()) &gt;+ Json::String( &gt;+ match *self { &gt;+ LocatorStrategy::CSSSelector =&gt; "css selector", &gt;+ LocatorStrategy::LinkText =&gt; "link text", &gt;+ LocatorStrategy::PartialLinkText =&gt; "partial link text", &gt;+ LocatorStrategy::TagName =&gt; "tag name", &gt;+ LocatorStrategy::XPath =&gt; "xpath", &gt;+ }.to_string(), &gt;+ ) &gt; } &gt; } &gt;diff --git a/testing/webdriver/src/error.rs b/testing/webdriver/src/error.rs &gt;index 0533cb246e23..4183e10f1ec5 100644 &gt;--- a/testing/webdriver/src/error.rs &gt;+++ b/testing/webdriver/src/error.rs &gt;@@ -164,18 +164,17 @@ impl ErrorStatus { &gt; NoSuchWindow =&gt; "no such window", &gt; ScriptTimeout =&gt; "script timeout", &gt; SessionNotCreated =&gt; "session not created", &gt; StaleElementReference =&gt; "stale element reference", &gt; Timeout =&gt; "timeout", &gt; UnableToCaptureScreen =&gt; "unable to capture screen", &gt; UnableToSetCookie =&gt; "unable to set cookie", &gt; UnexpectedAlertOpen =&gt; "unexpected alert open", &gt;- UnknownCommand | &gt;- UnknownError =&gt; "unknown error", &gt;+ UnknownCommand | UnknownError =&gt; "unknown error", &gt; UnknownMethod =&gt; "unknown method", &gt; UnknownPath =&gt; "unknown command", &gt; UnsupportedOperation =&gt; "unsupported operation", &gt; } &gt; } &gt; &gt; /// Returns the correct HTTP status code associated with the error type. &gt; pub fn http_status(&amp;self) -&gt; StatusCode { &gt;@@ -258,28 +257,30 @@ pub struct WebDriverError { &gt; pub error: ErrorStatus, &gt; pub message: Cow&lt;'static, str&gt;, &gt; pub stack: Cow&lt;'static, str&gt;, &gt; pub delete_session: bool, &gt; } &gt; &gt; impl WebDriverError { &gt; pub fn new&lt;S&gt;(error: ErrorStatus, message: S) -&gt; WebDriverError &gt;- where S: Into&lt;Cow&lt;'static, str&gt;&gt; &gt;+ where &gt;+ S: Into&lt;Cow&lt;'static, str&gt;&gt;, &gt; { &gt; WebDriverError { &gt; error: error, &gt; message: message.into(), &gt; stack: "".into(), &gt; delete_session: false, &gt; } &gt; } &gt; &gt; pub fn new_with_stack&lt;S&gt;(error: ErrorStatus, message: S, stack: S) -&gt; WebDriverError &gt;- where S: Into&lt;Cow&lt;'static, str&gt;&gt; &gt;+ where &gt;+ S: Into&lt;Cow&lt;'static, str&gt;&gt;, &gt; { &gt; WebDriverError { &gt; error: error, &gt; message: message.into(), &gt; stack: stack.into(), &gt; delete_session: false, &gt; } &gt; } &gt;diff --git a/testing/webdriver/src/httpapi.rs b/testing/webdriver/src/httpapi.rs &gt;index f16a440acfda..957ab0645e8d 100644 &gt;--- a/testing/webdriver/src/httpapi.rs &gt;+++ b/testing/webdriver/src/httpapi.rs &gt;@@ -1,99 +1,250 @@ &gt;-use regex::{Regex, Captures}; &gt;+use regex::{Captures, Regex}; &gt; use rustc_serialize::json::Json; &gt; &gt; use hyper::method::Method; &gt;-use hyper::method::Method::{Get, Post, Delete}; &gt;+use hyper::method::Method::{Delete, Get, Post}; &gt; &gt;-use command::{WebDriverCommand, WebDriverMessage, WebDriverExtensionCommand, &gt;- VoidWebDriverExtensionCommand}; &gt;-use error::{WebDriverResult, WebDriverError, ErrorStatus}; &gt;+use command::{ &gt;+ VoidWebDriverExtensionCommand, WebDriverCommand, WebDriverExtensionCommand, WebDriverMessage, &gt;+}; &gt;+use error::{ErrorStatus, WebDriverError, WebDriverResult}; &gt; &gt;-fn standard_routes&lt;U:WebDriverExtensionRoute&gt;() -&gt; Vec&lt;(Method, &amp;'static str, Route&lt;U&gt;)&gt; { &gt;- return vec![(Post, "/session", Route::NewSession), &gt;- (Delete, "/session/{sessionId}", Route::DeleteSession), &gt;- (Post, "/session/{sessionId}/url", Route::Get), &gt;- (Get, "/session/{sessionId}/url", Route::GetCurrentUrl), &gt;- (Post, "/session/{sessionId}/back", Route::GoBack), &gt;- (Post, "/session/{sessionId}/forward", Route::GoForward), &gt;- (Post, "/session/{sessionId}/refresh", Route::Refresh), &gt;- (Get, "/session/{sessionId}/title", Route::GetTitle), &gt;- (Get, "/session/{sessionId}/source", Route::GetPageSource), &gt;- (Get, "/session/{sessionId}/window", Route::GetWindowHandle), &gt;- (Get, "/session/{sessionId}/window/handles", Route::GetWindowHandles), &gt;- (Delete, "/session/{sessionId}/window", Route::CloseWindow), &gt;- (Get, "/session/{sessionId}/window/size", Route::GetWindowSize), &gt;- (Post, "/session/{sessionId}/window/size", Route::SetWindowSize), &gt;- (Get, "/session/{sessionId}/window/position", Route::GetWindowPosition), &gt;- (Post, "/session/{sessionId}/window/position", Route::SetWindowPosition), &gt;- (Get, "/session/{sessionId}/window/rect", Route::GetWindowRect), &gt;- (Post, "/session/{sessionId}/window/rect", Route::SetWindowRect), &gt;- (Post, "/session/{sessionId}/window/minimize", Route::MinimizeWindow), &gt;- (Post, "/session/{sessionId}/window/maximize", Route::MaximizeWindow), &gt;- (Post, "/session/{sessionId}/window/fullscreen", Route::FullscreenWindow), &gt;- (Post, "/session/{sessionId}/window", Route::SwitchToWindow), &gt;- (Post, "/session/{sessionId}/frame", Route::SwitchToFrame), &gt;- (Post, "/session/{sessionId}/frame/parent", Route::SwitchToParentFrame), &gt;- (Post, "/session/{sessionId}/element", Route::FindElement), &gt;- (Post, "/session/{sessionId}/elements", Route::FindElements), &gt;- (Post, "/session/{sessionId}/element/{elementId}/element", Route::FindElementElement), &gt;- (Post, "/session/{sessionId}/element/{elementId}/elements", Route::FindElementElements), &gt;- (Get, "/session/{sessionId}/element/active", Route::GetActiveElement), &gt;- (Get, "/session/{sessionId}/element/{elementId}/displayed", Route::IsDisplayed), &gt;- (Get, "/session/{sessionId}/element/{elementId}/selected", Route::IsSelected), &gt;- (Get, "/session/{sessionId}/element/{elementId}/attribute/{name}", Route::GetElementAttribute), &gt;- (Get, "/session/{sessionId}/element/{elementId}/property/{name}", Route::GetElementProperty), &gt;- (Get, "/session/{sessionId}/element/{elementId}/css/{propertyName}", Route::GetCSSValue), &gt;- (Get, "/session/{sessionId}/element/{elementId}/text", Route::GetElementText), &gt;- (Get, "/session/{sessionId}/element/{elementId}/name", Route::GetElementTagName), &gt;- (Get, "/session/{sessionId}/element/{elementId}/rect", Route::GetElementRect), &gt;- (Get, "/session/{sessionId}/element/{elementId}/enabled", Route::IsEnabled), &gt;- (Post, "/session/{sessionId}/execute/sync", Route::ExecuteScript), &gt;- (Post, "/session/{sessionId}/execute/async", Route::ExecuteAsyncScript), &gt;- (Get, "/session/{sessionId}/cookie", Route::GetCookies), &gt;- (Get, "/session/{sessionId}/cookie/{name}", Route::GetNamedCookie), &gt;- (Post, "/session/{sessionId}/cookie", Route::AddCookie), &gt;- (Delete, "/session/{sessionId}/cookie", Route::DeleteCookies), &gt;- (Delete, "/session/{sessionId}/cookie/{name}", Route::DeleteCookie), &gt;- (Get, "/session/{sessionId}/timeouts", Route::GetTimeouts), &gt;- (Post, "/session/{sessionId}/timeouts", Route::SetTimeouts), &gt;- (Post, "/session/{sessionId}/element/{elementId}/click", Route::ElementClick), &gt;- (Post, "/session/{sessionId}/element/{elementId}/tap", Route::ElementTap), &gt;- (Post, "/session/{sessionId}/element/{elementId}/clear", Route::ElementClear), &gt;- (Post, "/session/{sessionId}/element/{elementId}/value", Route::ElementSendKeys), &gt;- (Post, "/session/{sessionId}/alert/dismiss", Route::DismissAlert), &gt;- (Post, "/session/{sessionId}/alert/accept", Route::AcceptAlert), &gt;- (Get, "/session/{sessionId}/alert/text", Route::GetAlertText), &gt;- (Post, "/session/{sessionId}/alert/text", Route::SendAlertText), &gt;- (Get, "/session/{sessionId}/screenshot", Route::TakeScreenshot), &gt;- (Get, "/session/{sessionId}/element/{elementId}/screenshot", Route::TakeElementScreenshot), &gt;- (Post, "/session/{sessionId}/actions", Route::PerformActions), &gt;- (Delete, "/session/{sessionId}/actions", Route::ReleaseActions), &gt;- (Get, "/status", Route::Status),] &gt;+fn standard_routes&lt;U: WebDriverExtensionRoute&gt;() -&gt; Vec&lt;(Method, &amp;'static str, Route&lt;U&gt;)&gt; { &gt;+ return vec![ &gt;+ (Post, "/session", Route::NewSession), &gt;+ (Delete, "/session/{sessionId}", Route::DeleteSession), &gt;+ (Post, "/session/{sessionId}/url", Route::Get), &gt;+ (Get, "/session/{sessionId}/url", Route::GetCurrentUrl), &gt;+ (Post, "/session/{sessionId}/back", Route::GoBack), &gt;+ (Post, "/session/{sessionId}/forward", Route::GoForward), &gt;+ (Post, "/session/{sessionId}/refresh", Route::Refresh), &gt;+ (Get, "/session/{sessionId}/title", Route::GetTitle), &gt;+ (Get, "/session/{sessionId}/source", Route::GetPageSource), &gt;+ (Get, "/session/{sessionId}/window", Route::GetWindowHandle), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/window/handles", &gt;+ Route::GetWindowHandles, &gt;+ ), &gt;+ (Delete, "/session/{sessionId}/window", Route::CloseWindow), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/window/size", &gt;+ Route::GetWindowSize, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/window/size", &gt;+ Route::SetWindowSize, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/window/position", &gt;+ Route::GetWindowPosition, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/window/position", &gt;+ Route::SetWindowPosition, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/window/rect", &gt;+ Route::GetWindowRect, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/window/rect", &gt;+ Route::SetWindowRect, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/window/minimize", &gt;+ Route::MinimizeWindow, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/window/maximize", &gt;+ Route::MaximizeWindow, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/window/fullscreen", &gt;+ Route::FullscreenWindow, &gt;+ ), &gt;+ (Post, "/session/{sessionId}/window", Route::SwitchToWindow), &gt;+ (Post, "/session/{sessionId}/frame", Route::SwitchToFrame), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/frame/parent", &gt;+ Route::SwitchToParentFrame, &gt;+ ), &gt;+ (Post, "/session/{sessionId}/element", Route::FindElement), &gt;+ (Post, "/session/{sessionId}/elements", Route::FindElements), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/element/{elementId}/element", &gt;+ Route::FindElementElement, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/element/{elementId}/elements", &gt;+ Route::FindElementElements, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/element/active", &gt;+ Route::GetActiveElement, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/element/{elementId}/displayed", &gt;+ Route::IsDisplayed, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/element/{elementId}/selected", &gt;+ Route::IsSelected, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/element/{elementId}/attribute/{name}", &gt;+ Route::GetElementAttribute, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/element/{elementId}/property/{name}", &gt;+ Route::GetElementProperty, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/element/{elementId}/css/{propertyName}", &gt;+ Route::GetCSSValue, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/element/{elementId}/text", &gt;+ Route::GetElementText, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/element/{elementId}/name", &gt;+ Route::GetElementTagName, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/element/{elementId}/rect", &gt;+ Route::GetElementRect, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/element/{elementId}/enabled", &gt;+ Route::IsEnabled, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/execute/sync", &gt;+ Route::ExecuteScript, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/execute/async", &gt;+ Route::ExecuteAsyncScript, &gt;+ ), &gt;+ (Get, "/session/{sessionId}/cookie", Route::GetCookies), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/cookie/{name}", &gt;+ Route::GetNamedCookie, &gt;+ ), &gt;+ (Post, "/session/{sessionId}/cookie", Route::AddCookie), &gt;+ (Delete, "/session/{sessionId}/cookie", Route::DeleteCookies), &gt;+ ( &gt;+ Delete, &gt;+ "/session/{sessionId}/cookie/{name}", &gt;+ Route::DeleteCookie, &gt;+ ), &gt;+ (Get, "/session/{sessionId}/timeouts", Route::GetTimeouts), &gt;+ (Post, "/session/{sessionId}/timeouts", Route::SetTimeouts), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/element/{elementId}/click", &gt;+ Route::ElementClick, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/element/{elementId}/tap", &gt;+ Route::ElementTap, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/element/{elementId}/clear", &gt;+ Route::ElementClear, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/element/{elementId}/value", &gt;+ Route::ElementSendKeys, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/alert/dismiss", &gt;+ Route::DismissAlert, &gt;+ ), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/alert/accept", &gt;+ Route::AcceptAlert, &gt;+ ), &gt;+ (Get, "/session/{sessionId}/alert/text", Route::GetAlertText), &gt;+ ( &gt;+ Post, &gt;+ "/session/{sessionId}/alert/text", &gt;+ Route::SendAlertText, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/screenshot", &gt;+ Route::TakeScreenshot, &gt;+ ), &gt;+ ( &gt;+ Get, &gt;+ "/session/{sessionId}/element/{elementId}/screenshot", &gt;+ Route::TakeElementScreenshot, &gt;+ ), &gt;+ (Post, "/session/{sessionId}/actions", Route::PerformActions), &gt;+ ( &gt;+ Delete, &gt;+ "/session/{sessionId}/actions", &gt;+ Route::ReleaseActions, &gt;+ ), &gt;+ (Get, "/status", Route::Status), &gt;+ ]; &gt; } &gt; &gt; #[derive(Clone, Copy, Debug)] &gt;-pub enum Route&lt;U:WebDriverExtensionRoute&gt; { &gt;+pub enum Route&lt;U: WebDriverExtensionRoute&gt; { &gt; NewSession, &gt; DeleteSession, &gt; Get, &gt; GetCurrentUrl, &gt; GoBack, &gt; GoForward, &gt; Refresh, &gt; GetTitle, &gt; GetPageSource, &gt; GetWindowHandle, &gt; GetWindowHandles, &gt; CloseWindow, &gt;- GetWindowSize, // deprecated &gt;- SetWindowSize, // deprecated &gt;- GetWindowPosition, // deprecated &gt;- SetWindowPosition, // deprecated &gt;+ GetWindowSize, // deprecated &gt;+ SetWindowSize, // deprecated &gt;+ GetWindowPosition, // deprecated &gt;+ SetWindowPosition, // deprecated &gt; GetWindowRect, &gt; SetWindowRect, &gt; MinimizeWindow, &gt; MaximizeWindow, &gt; FullscreenWindow, &gt; SwitchToWindow, &gt; SwitchToFrame, &gt; SwitchToParentFrame, &gt;@@ -131,47 +282,51 @@ pub enum Route&lt;U:WebDriverExtensionRoute&gt; { &gt; GetAlertText, &gt; SendAlertText, &gt; TakeScreenshot, &gt; TakeElementScreenshot, &gt; Status, &gt; Extension(U), &gt; } &gt; &gt;-pub trait WebDriverExtensionRoute : Clone + Send + PartialEq { &gt;+pub trait WebDriverExtensionRoute: Clone + Send + PartialEq { &gt; type Command: WebDriverExtensionCommand + 'static; &gt; &gt; fn command(&amp;self, &amp;Captures, &amp;Json) -&gt; WebDriverResult&lt;WebDriverCommand&lt;Self::Command&gt;&gt;; &gt; } &gt; &gt; #[derive(Clone, Debug, PartialEq)] &gt; pub struct VoidWebDriverExtensionRoute; &gt; &gt; impl WebDriverExtensionRoute for VoidWebDriverExtensionRoute { &gt; type Command = VoidWebDriverExtensionCommand; &gt; &gt;- fn command(&amp;self, _:&amp;Captures, _:&amp;Json) -&gt; WebDriverResult&lt;WebDriverCommand&lt;VoidWebDriverExtensionCommand&gt;&gt; { &gt;+ fn command( &gt;+ &amp;self, &gt;+ _: &amp;Captures, &gt;+ _: &amp;Json, &gt;+ ) -&gt; WebDriverResult&lt;WebDriverCommand&lt;VoidWebDriverExtensionCommand&gt;&gt; { &gt; panic!("No extensions implemented"); &gt; } &gt; } &gt; &gt; #[derive(Clone, Debug)] &gt; struct RequestMatcher&lt;U: WebDriverExtensionRoute&gt; { &gt; method: Method, &gt; path_regexp: Regex, &gt;- match_type: Route&lt;U&gt; &gt;+ match_type: Route&lt;U&gt;, &gt; } &gt; &gt;-impl &lt;U: WebDriverExtensionRoute&gt; RequestMatcher&lt;U&gt; { &gt;+impl&lt;U: WebDriverExtensionRoute&gt; RequestMatcher&lt;U&gt; { &gt; pub fn new(method: Method, path: &amp;str, match_type: Route&lt;U&gt;) -&gt; RequestMatcher&lt;U&gt; { &gt; let path_regexp = RequestMatcher::&lt;U&gt;::compile_path(path); &gt; RequestMatcher { &gt; method: method, &gt; path_regexp: path_regexp, &gt;- match_type: match_type &gt;+ match_type: match_type, &gt; } &gt; } &gt; &gt; pub fn get_match&lt;'t&gt;(&amp;'t self, method: Method, path: &amp;'t str) -&gt; (bool, Option&lt;Captures&gt;) { &gt; let captures = self.path_regexp.captures(path); &gt; (method == self.method, captures) &gt; } &gt; &gt;@@ -179,17 +334,17 @@ impl &lt;U: WebDriverExtensionRoute&gt; RequestMatcher&lt;U&gt; { &gt; let mut rv = String::new(); &gt; rv.push_str("^"); &gt; let components = path.split('/'); &gt; for component in components { &gt; if component.starts_with("{") { &gt; if !component.ends_with("}") { &gt; panic!("Invalid url pattern") &gt; } &gt;- rv.push_str(&amp;format!("(?P&lt;{}&gt;[^/]+)/", &amp;component[1..component.len()-1])[..]); &gt;+ rv.push_str(&amp;format!("(?P&lt;{}&gt;[^/]+)/", &amp;component[1..component.len() - 1])[..]); &gt; } else { &gt; rv.push_str(&amp;format!("{}/", component)[..]); &gt; } &gt; } &gt; //Remove the trailing / &gt; rv.pop(); &gt; rv.push_str("$"); &gt; //This will fail at runtime if the regexp is invalid &gt;@@ -197,49 +352,60 @@ impl &lt;U: WebDriverExtensionRoute&gt; RequestMatcher&lt;U&gt; { &gt; } &gt; } &gt; &gt; #[derive(Debug)] &gt; pub struct WebDriverHttpApi&lt;U: WebDriverExtensionRoute&gt; { &gt; routes: Vec&lt;(Method, RequestMatcher&lt;U&gt;)&gt;, &gt; } &gt; &gt;-impl &lt;U: WebDriverExtensionRoute&gt; WebDriverHttpApi&lt;U&gt; { &gt;+impl&lt;U: WebDriverExtensionRoute&gt; WebDriverHttpApi&lt;U&gt; { &gt; pub fn new(extension_routes: &amp;[(Method, &amp;str, U)]) -&gt; WebDriverHttpApi&lt;U&gt; { &gt;- let mut rv = WebDriverHttpApi::&lt;U&gt; { &gt;- routes: vec![], &gt;- }; &gt;+ let mut rv = WebDriverHttpApi::&lt;U&gt; { routes: vec![] }; &gt; debug!("Creating routes"); &gt; for &amp;(ref method, ref url, ref match_type) in standard_routes::&lt;U&gt;().iter() { &gt; rv.add(method.clone(), *url, (*match_type).clone()); &gt;- }; &gt;+ } &gt; for &amp;(ref method, ref url, ref extension_route) in extension_routes.iter() { &gt;- rv.add(method.clone(), *url, Route::Extension(extension_route.clone())); &gt;- }; &gt;+ rv.add( &gt;+ method.clone(), &gt;+ *url, &gt;+ Route::Extension(extension_route.clone()), &gt;+ ); &gt;+ } &gt; rv &gt; } &gt; &gt; fn add(&amp;mut self, method: Method, path: &amp;str, match_type: Route&lt;U&gt;) { &gt; let http_matcher = RequestMatcher::new(method.clone(), path, match_type); &gt; self.routes.push((method, http_matcher)); &gt; } &gt; &gt;- pub fn decode_request(&amp;self, method: Method, path: &amp;str, body: &amp;str) -&gt; WebDriverResult&lt;WebDriverMessage&lt;U&gt;&gt; { &gt;+ pub fn decode_request( &gt;+ &amp;self, &gt;+ method: Method, &gt;+ path: &amp;str, &gt;+ body: &amp;str, &gt;+ ) -&gt; WebDriverResult&lt;WebDriverMessage&lt;U&gt;&gt; { &gt; let mut error = ErrorStatus::UnknownPath; &gt; for &amp;(ref match_method, ref matcher) in self.routes.iter() { &gt; if method == *match_method { &gt; let (method_match, captures) = matcher.get_match(method.clone(), path); &gt; if captures.is_some() { &gt; if method_match { &gt;- return WebDriverMessage::from_http(matcher.match_type.clone(), &gt;- &amp;captures.unwrap(), &gt;- body, &gt;- method == Post) &gt;+ return WebDriverMessage::from_http( &gt;+ matcher.match_type.clone(), &gt;+ &amp;captures.unwrap(), &gt;+ body, &gt;+ method == Post, &gt;+ ); &gt; } else { &gt; error = ErrorStatus::UnknownMethod; &gt; } &gt; } &gt; } &gt; } &gt;- Err(WebDriverError::new(error, &gt;- format!("{} {} did not match a known command", method, path))) &gt;+ Err(WebDriverError::new( &gt;+ error, &gt;+ format!("{} {} did not match a known command", method, path), &gt;+ )) &gt; } &gt; } &gt;diff --git a/testing/webdriver/src/lib.rs b/testing/webdriver/src/lib.rs &gt;index e708c72e5e3f..30a97925921d 100644 &gt;--- a/testing/webdriver/src/lib.rs &gt;+++ b/testing/webdriver/src/lib.rs &gt;@@ -1,29 +1,30 @@ &gt; #![allow(non_snake_case)] &gt; &gt; #[macro_use] &gt; extern crate log; &gt;-extern crate rustc_serialize; &gt;+extern crate cookie; &gt; extern crate hyper; &gt; extern crate regex; &gt;-extern crate cookie; &gt;+extern crate rustc_serialize; &gt; extern crate time; &gt;-extern crate url; &gt; extern crate unicode_segmentation; &gt;+extern crate url; &gt; &gt;-#[macro_use] pub mod macros; &gt;+#[macro_use] &gt;+pub mod macros; &gt; pub mod actions; &gt;-pub mod httpapi; &gt; pub mod capabilities; &gt; pub mod command; &gt; pub mod common; &gt; pub mod error; &gt;-pub mod server; &gt;+pub mod httpapi; &gt; pub mod response; &gt;+pub mod server; &gt; &gt; #[cfg(test)] &gt; mod nullable_tests { &gt; use super::common::Nullable; &gt; &gt; #[test] &gt; fn test_nullable_map() { &gt; let mut test = Nullable::Value(21); &gt;diff --git a/testing/webdriver/src/macros.rs b/testing/webdriver/src/macros.rs &gt;index 46e97ae39ede..07a12978485d 100644 &gt;--- a/testing/webdriver/src/macros.rs &gt;+++ b/testing/webdriver/src/macros.rs &gt;@@ -1,8 +1,8 @@ &gt; macro_rules! try_opt { &gt;- ($expr:expr, $err_type:expr, $err_msg:expr) =&gt; ({ &gt;+ ($expr:expr, $err_type:expr, $err_msg:expr) =&gt; {{ &gt; match $expr { &gt; Some(x) =&gt; x, &gt;- None =&gt; return Err(WebDriverError::new($err_type, $err_msg)) &gt;+ None =&gt; return Err(WebDriverError::new($err_type, $err_msg)), &gt; } &gt;- }) &gt;+ }}; &gt; } &gt;diff --git a/testing/webdriver/src/response.rs b/testing/webdriver/src/response.rs &gt;index 4bd9ceccdc3e..a9d67e515fb1 100644 &gt;--- a/testing/webdriver/src/response.rs &gt;+++ b/testing/webdriver/src/response.rs &gt;@@ -50,40 +50,44 @@ impl WebDriverResponse { &gt; &gt; #[derive(Debug, RustcEncodable)] &gt; pub struct CloseWindowResponse { &gt; pub window_handles: Vec&lt;String&gt;, &gt; } &gt; &gt; impl CloseWindowResponse { &gt; pub fn new(handles: Vec&lt;String&gt;) -&gt; CloseWindowResponse { &gt;- CloseWindowResponse { window_handles: handles } &gt;+ CloseWindowResponse { &gt;+ window_handles: handles, &gt;+ } &gt; } &gt; } &gt; &gt; impl ToJson for CloseWindowResponse { &gt; fn to_json(&amp;self) -&gt; Json { &gt;- Json::Array(self.window_handles &gt;- .iter() &gt;- .map(|x| Json::String(x.clone())) &gt;- .collect::&lt;Vec&lt;Json&gt;&gt;()) &gt;+ Json::Array( &gt;+ self.window_handles &gt;+ .iter() &gt;+ .map(|x| Json::String(x.clone())) &gt;+ .collect::&lt;Vec&lt;Json&gt;&gt;(), &gt;+ ) &gt; } &gt; } &gt; &gt; #[derive(Debug, RustcEncodable)] &gt; pub struct NewSessionResponse { &gt; pub sessionId: String, &gt;- pub capabilities: json::Json &gt;+ pub capabilities: json::Json, &gt; } &gt; &gt; impl NewSessionResponse { &gt; pub fn new(session_id: String, capabilities: json::Json) -&gt; NewSessionResponse { &gt; NewSessionResponse { &gt; capabilities: capabilities, &gt;- sessionId: session_id &gt;+ sessionId: session_id, &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug, RustcEncodable)] &gt; pub struct TimeoutsResponse { &gt; pub script: u64, &gt; pub pageLoad: u64, &gt;@@ -97,24 +101,22 @@ impl TimeoutsResponse { &gt; pageLoad: page_load, &gt; implicit: implicit, &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug, RustcEncodable)] &gt; pub struct ValueResponse { &gt;- pub value: json::Json &gt;+ pub value: json::Json, &gt; } &gt; &gt; impl ValueResponse { &gt; pub fn new(value: json::Json) -&gt; ValueResponse { &gt;- ValueResponse { &gt;- value: value &gt;- } &gt;+ ValueResponse { value: value } &gt; } &gt; } &gt; &gt; #[derive(Debug, RustcEncodable)] &gt; pub struct ElementRectResponse { &gt; /// X axis position of the top-left corner of the element relative &gt; // to the current browsing context’s document element in CSS reference &gt; // pixels. &gt;@@ -213,33 +215,34 @@ pub struct CookieResponse { &gt; &gt; #[derive(Debug, RustcEncodable)] &gt; pub struct CookiesResponse { &gt; pub value: Vec&lt;Cookie&gt;, &gt; } &gt; &gt; #[cfg(test)] &gt; mod tests { &gt;- use super::{CloseWindowResponse, Cookie, CookieResponse, CookiesResponse, ElementRectResponse, &gt;- NewSessionResponse, Nullable, TimeoutsResponse, ValueResponse, WebDriverResponse, &gt;- WindowRectResponse}; &gt;+ use super::{ &gt;+ CloseWindowResponse, Cookie, CookieResponse, CookiesResponse, ElementRectResponse, &gt;+ NewSessionResponse, Nullable, TimeoutsResponse, ValueResponse, WebDriverResponse, &gt;+ WindowRectResponse, &gt;+ }; &gt; use rustc_serialize::json::Json; &gt; use std::collections::BTreeMap; &gt; &gt; fn test(resp: WebDriverResponse, expected_str: &amp;str) { &gt; let data = resp.to_json_string(); &gt; let actual = Json::from_str(&amp;*data).unwrap(); &gt; let expected = Json::from_str(expected_str).unwrap(); &gt; assert_eq!(actual, expected); &gt; } &gt; &gt; #[test] &gt; fn test_close_window() { &gt;- let resp = WebDriverResponse::CloseWindow( &gt;- CloseWindowResponse::new(vec!["test".into()])); &gt;+ let resp = WebDriverResponse::CloseWindow(CloseWindowResponse::new(vec!["test".into()])); &gt; let expected = r#"{"value": ["test"]}"#; &gt; test(resp, expected); &gt; } &gt; &gt; #[test] &gt; fn test_cookie() { &gt; let cookie = Cookie { &gt; name: "name".into(), &gt;@@ -254,27 +257,26 @@ mod tests { &gt; let expected = r#"{"value": {"name": "name", "expiry": null, "value": "value", &gt; "path": "/", "domain": null, "secure": true, "httpOnly": false}}"#; &gt; test(resp, expected); &gt; } &gt; &gt; #[test] &gt; fn test_cookies() { &gt; let resp = WebDriverResponse::Cookies(CookiesResponse { &gt;- value: vec![ &gt;- Cookie { &gt;- name: "name".into(), &gt;- value: "value".into(), &gt;- path: Nullable::Value("/".into()), &gt;- domain: Nullable::Null, &gt;- expiry: Nullable::Null, &gt;- secure: true, &gt;- httpOnly: false, &gt;- } &gt;- ]}); &gt;+ value: vec![Cookie { &gt;+ name: "name".into(), &gt;+ value: "value".into(), &gt;+ path: Nullable::Value("/".into()), &gt;+ domain: Nullable::Null, &gt;+ expiry: Nullable::Null, &gt;+ secure: true, &gt;+ httpOnly: false, &gt;+ }], &gt;+ }); &gt; let expected = r#"{"value": [{"name": "name", "value": "value", "path": "/", &gt; "domain": null, "expiry": null, "secure": true, "httpOnly": false}]}"#; &gt; test(resp, expected); &gt; } &gt; &gt; #[test] &gt; fn test_element_rect() { &gt; let rect = ElementRectResponse { &gt;@@ -298,33 +300,35 @@ mod tests { &gt; }; &gt; let resp = WebDriverResponse::WindowRect(rect); &gt; let expected = r#"{"value": {"x": 0, "y": 1, "width": 2, "height": 3}}"#; &gt; test(resp, expected); &gt; } &gt; &gt; #[test] &gt; fn test_new_session() { &gt;- let resp = WebDriverResponse::NewSession( &gt;- NewSessionResponse::new("test".into(), &gt;- Json::Object(BTreeMap::new()))); &gt;+ let resp = WebDriverResponse::NewSession(NewSessionResponse::new( &gt;+ "test".into(), &gt;+ Json::Object(BTreeMap::new()), &gt;+ )); &gt; let expected = r#"{"value": {"sessionId": "test", "capabilities": {}}}"#; &gt; test(resp, expected); &gt; } &gt; &gt; #[test] &gt; fn test_timeouts() { &gt;- let resp = WebDriverResponse::Timeouts(TimeoutsResponse::new( &gt;- 1, 2, 3)); &gt;+ let resp = WebDriverResponse::Timeouts(TimeoutsResponse::new(1, 2, 3)); &gt; let expected = r#"{"value": {"script": 1, "pageLoad": 2, "implicit": 3}}"#; &gt; test(resp, expected); &gt; } &gt; &gt; #[test] &gt; fn test_value() { &gt; let mut value = BTreeMap::new(); &gt;- value.insert("example".into(), Json::Array(vec![Json::String("test".into())])); &gt;- let resp = WebDriverResponse::Generic(ValueResponse::new( &gt;- Json::Object(value))); &gt;+ value.insert( &gt;+ "example".into(), &gt;+ Json::Array(vec![Json::String("test".into())]), &gt;+ ); &gt;+ let resp = WebDriverResponse::Generic(ValueResponse::new(Json::Object(value))); &gt; let expected = r#"{"value": {"example": ["test"]}}"#; &gt; test(resp, expected); &gt; } &gt; } &gt;diff --git a/testing/webdriver/src/server.rs b/testing/webdriver/src/server.rs &gt;index c5fe98558f3b..bf0a0ea79242 100644 &gt;--- a/testing/webdriver/src/server.rs &gt;+++ b/testing/webdriver/src/server.rs &gt;@@ -1,55 +1,59 @@ &gt; use std::io::Read; &gt; use std::marker::PhantomData; &gt; use std::net::SocketAddr; &gt; use std::sync::mpsc::{channel, Receiver, Sender}; &gt; use std::sync::Mutex; &gt; use std::thread; &gt; use std::time::Duration; &gt; &gt;-use hyper::header::{ContentType, CacheControl, CacheDirective}; &gt;-use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value}; &gt;+use hyper::header::{CacheControl, CacheDirective, ContentType}; &gt; use hyper::method::Method; &gt;-use hyper::Result; &gt;+use hyper::mime::{Attr, Mime, SubLevel, TopLevel, Value}; &gt; use hyper::server::{Handler, Listening, Request, Response, Server}; &gt; use hyper::status::StatusCode; &gt; use hyper::uri::RequestUri::AbsolutePath; &gt;+use hyper::Result; &gt; &gt;-use command::{WebDriverMessage, WebDriverCommand}; &gt;-use error::{WebDriverResult, WebDriverError, ErrorStatus}; &gt;-use httpapi::{WebDriverHttpApi, WebDriverExtensionRoute, VoidWebDriverExtensionRoute}; &gt;+use command::{WebDriverCommand, WebDriverMessage}; &gt;+use error::{ErrorStatus, WebDriverError, WebDriverResult}; &gt;+use httpapi::{VoidWebDriverExtensionRoute, WebDriverExtensionRoute, WebDriverHttpApi}; &gt; use response::{CloseWindowResponse, WebDriverResponse}; &gt; &gt; enum DispatchMessage&lt;U: WebDriverExtensionRoute&gt; { &gt;- HandleWebDriver(WebDriverMessage&lt;U&gt;, Sender&lt;WebDriverResult&lt;WebDriverResponse&gt;&gt;), &gt;- Quit &gt;+ HandleWebDriver( &gt;+ WebDriverMessage&lt;U&gt;, &gt;+ Sender&lt;WebDriverResult&lt;WebDriverResponse&gt;&gt;, &gt;+ ), &gt;+ Quit, &gt; } &gt; &gt; #[derive(Clone, Debug, PartialEq)] &gt; pub struct Session { &gt;- pub id: String &gt;+ pub id: String, &gt; } &gt; &gt; impl Session { &gt; fn new(id: String) -&gt; Session { &gt;- Session { &gt;- id: id &gt;- } &gt;+ Session { id: id } &gt; } &gt; } &gt; &gt;-pub trait WebDriverHandler&lt;U: WebDriverExtensionRoute=VoidWebDriverExtensionRoute&gt; : Send { &gt;- fn handle_command(&amp;mut self, session: &amp;Option&lt;Session&gt;, msg: WebDriverMessage&lt;U&gt;) -&gt; WebDriverResult&lt;WebDriverResponse&gt;; &gt;+pub trait WebDriverHandler&lt;U: WebDriverExtensionRoute = VoidWebDriverExtensionRoute&gt;: Send { &gt;+ fn handle_command( &gt;+ &amp;mut self, &gt;+ session: &amp;Option&lt;Session&gt;, &gt;+ msg: WebDriverMessage&lt;U&gt;, &gt;+ ) -&gt; WebDriverResult&lt;WebDriverResponse&gt;; &gt; fn delete_session(&amp;mut self, session: &amp;Option&lt;Session&gt;); &gt; } &gt; &gt; #[derive(Debug)] &gt;-struct Dispatcher&lt;T: WebDriverHandler&lt;U&gt;, &gt;- U: WebDriverExtensionRoute&gt; { &gt;+struct Dispatcher&lt;T: WebDriverHandler&lt;U&gt;, U: WebDriverExtensionRoute&gt; { &gt; handler: T, &gt; session: Option&lt;Session&gt;, &gt; extension_type: PhantomData&lt;U&gt;, &gt; } &gt; &gt; impl&lt;T: WebDriverHandler&lt;U&gt;, U: WebDriverExtensionRoute&gt; Dispatcher&lt;T, U&gt; { &gt; fn new(handler: T) -&gt; Dispatcher&lt;T, U&gt; { &gt; Dispatcher { &gt;@@ -67,17 +71,19 @@ impl&lt;T: WebDriverHandler&lt;U&gt;, U: WebDriverExtensionRoute&gt; Dispatcher&lt;T, U&gt; { &gt; Ok(_) =&gt; self.handler.handle_command(&amp;self.session, msg), &gt; Err(e) =&gt; Err(e), &gt; }; &gt; &gt; match resp { &gt; Ok(WebDriverResponse::NewSession(ref new_session)) =&gt; { &gt; self.session = Some(Session::new(new_session.sessionId.clone())); &gt; } &gt;- Ok(WebDriverResponse::CloseWindow(CloseWindowResponse { ref window_handles })) =&gt; { &gt;+ Ok(WebDriverResponse::CloseWindow(CloseWindowResponse { &gt;+ ref window_handles, &gt;+ })) =&gt; { &gt; if window_handles.len() == 0 { &gt; debug!("Last window was closed, deleting session"); &gt; self.delete_session(); &gt; } &gt; } &gt; Ok(WebDriverResponse::DeleteSession) =&gt; self.delete_session(), &gt; Err(ref x) if x.delete_session =&gt; self.delete_session(), &gt; _ =&gt; {} &gt;@@ -96,76 +102,73 @@ impl&lt;T: WebDriverHandler&lt;U&gt;, U: WebDriverExtensionRoute&gt; Dispatcher&lt;T, U&gt; { &gt; fn delete_session(&amp;mut self) { &gt; debug!("Deleting session"); &gt; self.handler.delete_session(&amp;self.session); &gt; self.session = None; &gt; } &gt; &gt; fn check_session(&amp;self, msg: &amp;WebDriverMessage&lt;U&gt;) -&gt; WebDriverResult&lt;()&gt; { &gt; match msg.session_id { &gt;- Some(ref msg_session_id) =&gt; { &gt;- match self.session { &gt;- Some(ref existing_session) =&gt; { &gt;- if existing_session.id != *msg_session_id { &gt;- Err(WebDriverError::new( &gt;- ErrorStatus::InvalidSessionId, &gt;- format!("Got unexpected session id {}", &gt;- msg_session_id))) &gt;- } else { &gt;- Ok(()) &gt;- } &gt;- }, &gt;- None =&gt; Ok(()) &gt;+ Some(ref msg_session_id) =&gt; match self.session { &gt;+ Some(ref existing_session) =&gt; { &gt;+ if existing_session.id != *msg_session_id { &gt;+ Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidSessionId, &gt;+ format!("Got unexpected session id {}", msg_session_id), &gt;+ )) &gt;+ } else { &gt;+ Ok(()) &gt;+ } &gt; } &gt;+ None =&gt; Ok(()), &gt; }, &gt; None =&gt; { &gt; match self.session { &gt; Some(_) =&gt; { &gt; match msg.command { &gt; WebDriverCommand::Status =&gt; Ok(()), &gt;- WebDriverCommand::NewSession(_) =&gt; { &gt;- Err(WebDriverError::new( &gt;- ErrorStatus::SessionNotCreated, &gt;- "Session is already started")) &gt;- }, &gt;+ WebDriverCommand::NewSession(_) =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::SessionNotCreated, &gt;+ "Session is already started", &gt;+ )), &gt; _ =&gt; { &gt; //This should be impossible &gt; error!("Got a message with no session id"); &gt; Err(WebDriverError::new( &gt; ErrorStatus::UnknownError, &gt;- "Got a command with no session?!")) &gt;+ "Got a command with no session?!", &gt;+ )) &gt; } &gt; } &gt;- }, &gt;- None =&gt; { &gt;- match msg.command { &gt;- WebDriverCommand::NewSession(_) =&gt; Ok(()), &gt;- WebDriverCommand::Status =&gt; Ok(()), &gt;- _ =&gt; Err(WebDriverError::new( &gt;- ErrorStatus::InvalidSessionId, &gt;- "Tried to run a command before creating a session")) &gt;- } &gt; } &gt;+ None =&gt; match msg.command { &gt;+ WebDriverCommand::NewSession(_) =&gt; Ok(()), &gt;+ WebDriverCommand::Status =&gt; Ok(()), &gt;+ _ =&gt; Err(WebDriverError::new( &gt;+ ErrorStatus::InvalidSessionId, &gt;+ "Tried to run a command before creating a session", &gt;+ )), &gt;+ }, &gt; } &gt; } &gt; } &gt; } &gt; } &gt; &gt; #[derive(Debug)] &gt; struct HttpHandler&lt;U: WebDriverExtensionRoute&gt; { &gt; chan: Mutex&lt;Sender&lt;DispatchMessage&lt;U&gt;&gt;&gt;, &gt;- api: Mutex&lt;WebDriverHttpApi&lt;U&gt;&gt; &gt;+ api: Mutex&lt;WebDriverHttpApi&lt;U&gt;&gt;, &gt; } &gt; &gt;-impl &lt;U: WebDriverExtensionRoute&gt; HttpHandler&lt;U&gt; { &gt;+impl&lt;U: WebDriverExtensionRoute&gt; HttpHandler&lt;U&gt; { &gt; fn new(api: WebDriverHttpApi&lt;U&gt;, chan: Sender&lt;DispatchMessage&lt;U&gt;&gt;) -&gt; HttpHandler&lt;U&gt; { &gt; HttpHandler { &gt; chan: Mutex::new(chan), &gt;- api: Mutex::new(api) &gt;+ api: Mutex::new(api), &gt; } &gt; } &gt; } &gt; &gt; impl&lt;U: WebDriverExtensionRoute&gt; Handler for HttpHandler&lt;U&gt; { &gt; fn handle(&amp;self, req: Request, res: Response) { &gt; let mut req = req; &gt; let mut res = res; &gt;@@ -203,38 +206,37 @@ impl&lt;U: WebDriverExtensionRoute&gt; Handler for HttpHandler&lt;U&gt; { &gt; } &gt; } &gt; Err(_) =&gt; { &gt; error!("Something terrible happened"); &gt; return; &gt; } &gt; } &gt; match recv_res.recv() { &gt;- Ok(data) =&gt; { &gt;- match data { &gt;- Ok(response) =&gt; (StatusCode::Ok, response.to_json_string()), &gt;- Err(err) =&gt; (err.http_status(), err.to_json_string()), &gt;- } &gt;- } &gt;+ Ok(data) =&gt; match data { &gt;+ Ok(response) =&gt; (StatusCode::Ok, response.to_json_string()), &gt;+ Err(err) =&gt; (err.http_status(), err.to_json_string()), &gt;+ }, &gt; Err(e) =&gt; panic!("Error reading response: {:?}", e), &gt; } &gt; } &gt; Err(err) =&gt; (err.http_status(), err.to_json_string()), &gt; }; &gt; &gt; debug!("&lt;- {} {}", status, resp_body); &gt; &gt; { &gt; let resp_status = res.status_mut(); &gt; *resp_status = status; &gt; } &gt;- res.headers_mut() &gt;- .set(ContentType(Mime(TopLevel::Application, &gt;- SubLevel::Json, &gt;- vec![(Attr::Charset, Value::Utf8)]))); &gt;+ res.headers_mut().set(ContentType(Mime( &gt;+ TopLevel::Application, &gt;+ SubLevel::Json, &gt;+ vec![(Attr::Charset, Value::Utf8)], &gt;+ ))); &gt; res.headers_mut() &gt; .set(CacheControl(vec![CacheDirective::NoCache])); &gt; &gt; res.send(&amp;resp_body.as_bytes()).unwrap(); &gt; } &gt; _ =&gt; {} &gt; } &gt; } &gt;diff --git a/toolkit/crashreporter/rust/lib.rs b/toolkit/crashreporter/rust/lib.rs &gt;index d0fc77099b41..d5377ac3da6f 100644 &gt;--- a/toolkit/crashreporter/rust/lib.rs &gt;+++ b/toolkit/crashreporter/rust/lib.rs &gt;@@ -3,23 +3,26 @@ extern crate rustc_demangle; &gt; use rustc_demangle::demangle; &gt; use std::ffi::{CStr, CString}; &gt; use std::ptr; &gt; &gt; /// Demangle `name` as a Rust symbol. &gt; /// &gt; /// The resulting pointer should be freed with `free_demangled_name`. &gt; #[no_mangle] &gt;-pub extern fn rust_demangle(name: *const std::os::raw::c_char) -&gt; *mut std::os::raw::c_char { &gt;- let demangled = format!("{:#}", demangle(&amp;unsafe { CStr::from_ptr(name) }.to_string_lossy())); &gt;+pub extern "C" fn rust_demangle(name: *const std::os::raw::c_char) -&gt; *mut std::os::raw::c_char { &gt;+ let demangled = format!( &gt;+ "{:#}", &gt;+ demangle(&amp;unsafe { CStr::from_ptr(name) }.to_string_lossy()) &gt;+ ); &gt; CString::new(demangled) &gt; .map(|s| s.into_raw()) &gt; .unwrap_or(ptr::null_mut()) &gt; } &gt; &gt; /// Free a string that was returned from `rust_demangle`. &gt; #[no_mangle] &gt;-pub extern fn free_rust_demangled_name(demangled: *mut std::os::raw::c_char) { &gt;+pub extern "C" fn free_rust_demangled_name(demangled: *mut std::os::raw::c_char) { &gt; if demangled != ptr::null_mut() { &gt; // Just take ownership here. &gt; unsafe { CString::from_raw(demangled) }; &gt; } &gt; } &gt;diff --git a/toolkit/library/rust/shared/build.rs b/toolkit/library/rust/shared/build.rs &gt;index afae7d37abf3..e878185f8ec3 100644 &gt;--- a/toolkit/library/rust/shared/build.rs &gt;+++ b/toolkit/library/rust/shared/build.rs &gt;@@ -4,20 +4,24 @@ use rustc_version::{version, Version}; &gt; &gt; fn main() { &gt; let ver = version().unwrap(); &gt; let mut bootstrap = false; &gt; &gt; if ver &gt;= Version::parse("1.24.0").unwrap() &amp;&amp; ver &lt; Version::parse("1.27.0").unwrap() { &gt; println!("cargo:rustc-cfg=feature=\"oom_with_global_alloc\""); &gt; bootstrap = true; &gt;- } else if ver &gt;= Version::parse("1.28.0-alpha").unwrap() &amp;&amp; ver &lt; Version::parse("1.30.0-alpha").unwrap() { &gt;+ } else if ver &gt;= Version::parse("1.28.0-alpha").unwrap() &gt;+ &amp;&amp; ver &lt; Version::parse("1.30.0-alpha").unwrap() &gt;+ { &gt; println!("cargo:rustc-cfg=feature=\"oom_with_hook\""); &gt; bootstrap = true; &gt;- } else if std::env::var("MOZ_AUTOMATION").is_ok() &amp;&amp; ver &gt;= Version::parse("1.30.0-alpha").unwrap() { &gt;+ } else if std::env::var("MOZ_AUTOMATION").is_ok() &gt;+ &amp;&amp; ver &gt;= Version::parse("1.30.0-alpha").unwrap() &gt;+ { &gt; // For the sake of the base-toolchains build we allow building with 1.27, but &gt; // retain this check for newer versions. &gt; panic!("Builds on automation must use a version of rust that supports OOM hooking") &gt; } &gt; &gt; // This is a rather awful thing to do, but we're only doing it on &gt; // versions of rustc that are not going to change the unstable APIs &gt; // we use from under us, all being already released or beta. &gt;diff --git a/toolkit/library/rust/shared/lib.rs b/toolkit/library/rust/shared/lib.rs &gt;index 55c4e97a4d85..de4d9eae41e4 100644 &gt;--- a/toolkit/library/rust/shared/lib.rs &gt;+++ b/toolkit/library/rust/shared/lib.rs &gt;@@ -1,80 +1,83 @@ &gt; // This Source Code Form is subject to the terms of the Mozilla Public &gt; // License, v. 2.0. If a copy of the MPL was not distributed with this &gt; // file, You can obtain one at http://mozilla.org/MPL/2.0/. &gt; &gt;-#![cfg_attr(feature = "oom_with_global_alloc", &gt;- feature(global_allocator, alloc, alloc_system, allocator_api))] &gt;+#![cfg_attr( &gt;+ feature = "oom_with_global_alloc", &gt;+ feature(global_allocator, alloc, alloc_system, allocator_api) &gt;+)] &gt; #![cfg_attr(feature = "oom_with_hook", feature(alloc_error_hook))] &gt; &gt;-#[cfg(feature="servo")] &gt;+#[cfg(feature = "servo")] &gt; extern crate geckoservo; &gt; &gt;-extern crate mp4parse_capi; &gt;-extern crate nsstring; &gt;-extern crate nserror; &gt;-extern crate xpcom; &gt;-extern crate netwerk_helper; &gt;-extern crate prefs_parser; &gt;-extern crate mozurl; &gt;-#[cfg(feature = "quantum_render")] &gt;-extern crate webrender_bindings; &gt;+#[cfg(feature = "cubeb-remoting")] &gt;+extern crate audioipc_client; &gt;+#[cfg(feature = "cubeb-remoting")] &gt;+extern crate audioipc_server; &gt;+extern crate cosec; &gt; #[cfg(feature = "cubeb_pulse_rust")] &gt; extern crate cubeb_pulse; &gt; extern crate encoding_c; &gt; extern crate encoding_glue; &gt;-#[cfg(feature = "cubeb-remoting")] &gt;-extern crate audioipc_client; &gt;-#[cfg(feature = "cubeb-remoting")] &gt;-extern crate audioipc_server; &gt; extern crate env_logger; &gt;-extern crate u2fhid; &gt; extern crate log; &gt;-extern crate cosec; &gt;+extern crate mozurl; &gt;+extern crate mp4parse_capi; &gt;+extern crate netwerk_helper; &gt;+extern crate nserror; &gt;+extern crate nsstring; &gt;+extern crate prefs_parser; &gt; extern crate rsdparsa_capi; &gt;+extern crate u2fhid; &gt;+#[cfg(feature = "quantum_render")] &gt;+extern crate webrender_bindings; &gt;+extern crate xpcom; &gt; &gt; use std::boxed::Box; &gt; use std::env; &gt; use std::ffi::{CStr, CString}; &gt; use std::os::raw::c_char; &gt; use std::panic; &gt; &gt; extern "C" { &gt; fn gfx_critical_note(msg: *const c_char); &gt; } &gt; &gt; struct GeckoLogger { &gt;- logger: env_logger::Logger &gt;+ logger: env_logger::Logger, &gt; } &gt; &gt; impl GeckoLogger { &gt; fn new() -&gt; GeckoLogger { &gt; let mut builder = env_logger::Builder::new(); &gt;- let default_level = if cfg!(debug_assertions) { "warn" } else { "error" }; &gt;+ let default_level = if cfg!(debug_assertions) { &gt;+ "warn" &gt;+ } else { &gt;+ "error" &gt;+ }; &gt; let logger = match env::var("RUST_LOG") { &gt; Ok(v) =&gt; builder.parse(&amp;v).build(), &gt; _ =&gt; builder.parse(default_level).build(), &gt; }; &gt; &gt;- GeckoLogger { &gt;- logger &gt;- } &gt;+ GeckoLogger { logger } &gt; } &gt; &gt; fn init() -&gt; Result&lt;(), log::SetLoggerError&gt; { &gt; let gecko_logger = Self::new(); &gt; &gt; log::set_max_level(gecko_logger.logger.filter()); &gt; log::set_boxed_logger(Box::new(gecko_logger)) &gt; } &gt; &gt; fn should_log_to_gfx_critical_note(record: &amp;log::Record) -&gt; bool { &gt;- if record.level() == log::Level::Error &amp;&amp; &gt;- record.target().contains("webrender") { &gt;+ if record.level() == log::Level::Error &amp;&amp; record.target().contains("webrender") { &gt; true &gt; } else { &gt; false &gt; } &gt; } &gt; &gt; fn maybe_log_to_gfx_critical_note(&amp;self, record: &amp;log::Record) { &gt; if Self::should_log_to_gfx_critical_note(record) { &gt;@@ -92,28 +95,27 @@ impl log::Log for GeckoLogger { &gt; } &gt; &gt; fn log(&amp;self, record: &amp;log::Record) { &gt; // Forward log to gfxCriticalNote, if the log should be in gfx crash log. &gt; self.maybe_log_to_gfx_critical_note(record); &gt; self.logger.log(record); &gt; } &gt; &gt;- fn flush(&amp;self) { } &gt;+ fn flush(&amp;self) {} &gt; } &gt; &gt; #[no_mangle] &gt; pub extern "C" fn GkRust_Init() { &gt; // Initialize logging. &gt; let _ = GeckoLogger::init(); &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern "C" fn GkRust_Shutdown() { &gt;-} &gt;+pub extern "C" fn GkRust_Shutdown() {} &gt; &gt; /// Used to implement `nsIDebug2::RustPanic` for testing purposes. &gt; #[no_mangle] &gt; pub extern "C" fn intentional_panic(message: *const c_char) { &gt; panic!("{}", unsafe { CStr::from_ptr(message) }.to_string_lossy()); &gt; } &gt; &gt; /// Contains the panic message, if set. &gt;@@ -132,19 +134,23 @@ pub extern "C" fn install_rust_panic_hook() { &gt; let default_hook = panic::take_hook(); &gt; panic::set_hook(Box::new(move |info| { &gt; // Try to handle &amp;str/String payloads, which should handle 99% of cases. &gt; let payload = info.payload(); &gt; // We'll hold a raw *const str here, but it will be OK because &gt; // Rust is going to abort the process before the payload could be &gt; // deallocated. &gt; if let Some(s) = payload.downcast_ref::&lt;&amp;str&gt;() { &gt;- unsafe { PANIC_REASON = Some(*s as *const str); } &gt;+ unsafe { &gt;+ PANIC_REASON = Some(*s as *const str); &gt;+ } &gt; } else if let Some(s) = payload.downcast_ref::&lt;String&gt;() { &gt;- unsafe { PANIC_REASON = Some(s.as_str() as *const str); } &gt;+ unsafe { &gt;+ PANIC_REASON = Some(s.as_str() as *const str); &gt;+ } &gt; } else { &gt; // Not the most helpful thing, but seems unlikely to happen &gt; // in practice. &gt; println!("Unhandled panic payload!"); &gt; } &gt; // Fall through to the default hook so we still print the reason and &gt; // backtrace to the console. &gt; default_hook(info); &gt;@@ -217,17 +223,17 @@ mod global_alloc { &gt; } &gt; &gt; #[cfg(feature = "oom_with_global_alloc")] &gt; #[global_allocator] &gt; static HEAP: global_alloc::GeckoHeap = global_alloc::GeckoHeap; &gt; &gt; #[cfg(feature = "oom_with_hook")] &gt; mod oom_hook { &gt;- use std::alloc::{Layout, set_alloc_error_hook}; &gt;+ use std::alloc::{set_alloc_error_hook, Layout}; &gt; &gt; extern "C" { &gt; fn GeckoHandleOOM(size: usize) -&gt; !; &gt; } &gt; &gt; pub fn hook(layout: Layout) { &gt; unsafe { &gt; GeckoHandleOOM(layout.size()); &gt;diff --git a/xpcom/rust/gtest/bench-collections/bench.rs b/xpcom/rust/gtest/bench-collections/bench.rs &gt;index f0ca68ef2d91..632cbd63e399 100644 &gt;--- a/xpcom/rust/gtest/bench-collections/bench.rs &gt;+++ b/xpcom/rust/gtest/bench-collections/bench.rs &gt;@@ -11,80 +11,91 @@ use fnv::FnvHashSet; &gt; use fxhash::FxHashSet; &gt; use std::collections::HashSet; &gt; use std::os::raw::{c_char, c_void}; &gt; use std::slice; &gt; &gt; /// Keep this in sync with Params in Bench.cpp. &gt; #[derive(Debug)] &gt; #[repr(C)] &gt;-pub struct Params &gt;-{ &gt;- config_name: *const c_char, &gt;- num_inserts: usize, &gt;- num_successful_lookups: usize, &gt;- num_failing_lookups: usize, &gt;- num_iterations: usize, &gt;- remove_inserts: bool, &gt;+pub struct Params { &gt;+ config_name: *const c_char, &gt;+ num_inserts: usize, &gt;+ num_successful_lookups: usize, &gt;+ num_failing_lookups: usize, &gt;+ num_iterations: usize, &gt;+ remove_inserts: bool, &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern "C" fn Bench_Rust_HashSet(params: *const Params, vals: *const *const c_void, &gt;- len: usize) { &gt;+pub extern "C" fn Bench_Rust_HashSet( &gt;+ params: *const Params, &gt;+ vals: *const *const c_void, &gt;+ len: usize, &gt;+) { &gt; let hs: HashSet&lt;_&gt; = std::collections::HashSet::default(); &gt; Bench_Rust(hs, params, vals, len); &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern "C" fn Bench_Rust_FnvHashSet(params: *const Params, vals: *const *const c_void, &gt;- len: usize) { &gt;+pub extern "C" fn Bench_Rust_FnvHashSet( &gt;+ params: *const Params, &gt;+ vals: *const *const c_void, &gt;+ len: usize, &gt;+) { &gt; let hs = FnvHashSet::default(); &gt; Bench_Rust(hs, params, vals, len); &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern "C" fn Bench_Rust_FxHashSet(params: *const Params, vals: *const *const c_void, &gt;- len: usize) { &gt;+pub extern "C" fn Bench_Rust_FxHashSet( &gt;+ params: *const Params, &gt;+ vals: *const *const c_void, &gt;+ len: usize, &gt;+) { &gt; let hs = FxHashSet::default(); &gt; Bench_Rust(hs, params, vals, len); &gt; } &gt; &gt; // Keep this in sync with all the other Bench_*() functions. &gt;-fn Bench_Rust&lt;H: std::hash::BuildHasher&gt;(mut hs: HashSet&lt;*const c_void, H&gt;, params: *const Params, &gt;- vals: *const *const c_void, len: usize) { &gt;+fn Bench_Rust&lt;H: std::hash::BuildHasher&gt;( &gt;+ mut hs: HashSet&lt;*const c_void, H&gt;, &gt;+ params: *const Params, &gt;+ vals: *const *const c_void, &gt;+ len: usize, &gt;+) { &gt; let params = unsafe { &amp;*params }; &gt; let vals = unsafe { slice::from_raw_parts(vals, len) }; &gt; &gt; for j in 0..params.num_inserts { &gt; hs.insert(vals[j]); &gt; } &gt; &gt; for _i in 0..params.num_successful_lookups { &gt; for j in 0..params.num_inserts { &gt; assert!(hs.contains(&amp;vals[j])); &gt; } &gt; } &gt; &gt; for _i in 0..params.num_failing_lookups { &gt;- for j in params.num_inserts..params.num_inserts*2 { &gt;+ for j in params.num_inserts..params.num_inserts * 2 { &gt; assert!(!hs.contains(&amp;vals[j])); &gt; } &gt; } &gt; &gt; for _i in 0..params.num_iterations { &gt;- let mut n = 0; &gt;- for _ in hs.iter() { &gt;- n += 1; &gt;- } &gt;- assert!(params.num_inserts == n); &gt;- assert!(hs.len() == n); &gt;+ let mut n = 0; &gt;+ for _ in hs.iter() { &gt;+ n += 1; &gt;+ } &gt;+ assert!(params.num_inserts == n); &gt;+ assert!(hs.len() == n); &gt; } &gt; &gt; if params.remove_inserts { &gt; for j in 0..params.num_inserts { &gt; assert!(hs.remove(&amp;vals[j])); &gt; } &gt; assert!(hs.len() == 0); &gt; } else { &gt; assert!(hs.len() == params.num_inserts); &gt; } &gt; } &gt;- &gt;diff --git a/xpcom/rust/gtest/nsstring/test.rs b/xpcom/rust/gtest/nsstring/test.rs &gt;index 4ab7f46ff3c0..8e148ce9dc98 100644 &gt;--- a/xpcom/rust/gtest/nsstring/test.rs &gt;+++ b/xpcom/rust/gtest/nsstring/test.rs &gt;@@ -1,74 +1,79 @@ &gt; #![allow(non_snake_case)] &gt; &gt; extern crate nsstring; &gt; &gt;-use std::fmt::Write; &gt;+use nsstring::*; &gt; use std::ffi::CString; &gt;+use std::fmt::Write; &gt; use std::os::raw::c_char; &gt;-use nsstring::*; &gt; &gt; fn nonfatal_fail(msg: String) { &gt; extern "C" { &gt; fn GTest_ExpectFailure(message: *const c_char); &gt; } &gt; unsafe { &gt; GTest_ExpectFailure(CString::new(msg).unwrap().as_ptr()); &gt; } &gt; } &gt; &gt; /// This macro checks if the two arguments are equal, and causes a non-fatal &gt; /// GTest test failure if they are not. &gt; macro_rules! expect_eq { &gt; ($x:expr, $y:expr) =&gt; { &gt; match (&amp;$x, &amp;$y) { &gt; (x, y) =&gt; if *x != *y { &gt;- nonfatal_fail(format!("check failed: (`{:?}` == `{:?}`) at {}:{}", &gt;- x, y, file!(), line!())) &gt;- } &gt;+ nonfatal_fail(format!( &gt;+ "check failed: (`{:?}` == `{:?}`) at {}:{}", &gt;+ x, &gt;+ y, &gt;+ file!(), &gt;+ line!() &gt;+ )) &gt;+ }, &gt; } &gt;- } &gt;+ }; &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern fn Rust_StringFromCpp(cs: *const nsACString, s: *const nsAString) { &gt;+pub extern "C" fn Rust_StringFromCpp(cs: *const nsACString, s: *const nsAString) { &gt; unsafe { &gt; expect_eq!(&amp;*cs, "Hello, World!"); &gt; expect_eq!(&amp;*s, "Hello, World!"); &gt; } &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern fn Rust_AssignFromRust(cs: *mut nsACString, s: *mut nsAString) { &gt;+pub extern "C" fn Rust_AssignFromRust(cs: *mut nsACString, s: *mut nsAString) { &gt; unsafe { &gt; (*cs).assign(&amp;nsCString::from("Hello, World!")); &gt; expect_eq!(&amp;*cs, "Hello, World!"); &gt; (*s).assign(&amp;nsString::from("Hello, World!")); &gt; expect_eq!(&amp;*s, "Hello, World!"); &gt; } &gt; } &gt; &gt; extern "C" { &gt; fn Cpp_AssignFromCpp(cs: *mut nsACString, s: *mut nsAString); &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern fn Rust_AssignFromCpp() { &gt;+pub extern "C" fn Rust_AssignFromCpp() { &gt; let mut cs = nsCString::new(); &gt; let mut s = nsString::new(); &gt; unsafe { &gt; Cpp_AssignFromCpp(&amp;mut *cs, &amp;mut *s); &gt; } &gt; expect_eq!(cs, "Hello, World!"); &gt; expect_eq!(s, "Hello, World!"); &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern fn Rust_StringWrite() { &gt;+pub extern "C" fn Rust_StringWrite() { &gt; let mut cs = nsCString::new(); &gt; let mut s = nsString::new(); &gt; &gt; write!(s, "a").unwrap(); &gt; write!(cs, "a").unwrap(); &gt; expect_eq!(s, "a"); &gt; expect_eq!(cs, "a"); &gt; write!(s, "bc").unwrap(); &gt;@@ -77,24 +82,29 @@ pub extern fn Rust_StringWrite() { &gt; expect_eq!(cs, "abc"); &gt; write!(s, "{}", 123).unwrap(); &gt; write!(cs, "{}", 123).unwrap(); &gt; expect_eq!(s, "abc123"); &gt; expect_eq!(cs, "abc123"); &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern fn Rust_FromEmptyRustString() { &gt;+pub extern "C" fn Rust_FromEmptyRustString() { &gt; let mut test = nsString::from("Blah"); &gt; test.assign_utf8(&amp;nsCString::from(String::new())); &gt; assert!(test.is_empty()); &gt; } &gt; &gt; #[no_mangle] &gt;-pub extern fn Rust_WriteToBufferFromRust(cs: *mut nsACString, s: *mut nsAString, fallible_cs: *mut nsACString, fallible_s: *mut nsAString) { &gt;+pub extern "C" fn Rust_WriteToBufferFromRust( &gt;+ cs: *mut nsACString, &gt;+ s: *mut nsAString, &gt;+ fallible_cs: *mut nsACString, &gt;+ fallible_s: *mut nsAString, &gt;+) { &gt; unsafe { &gt; let cs_buf = (*cs).to_mut(); &gt; let s_buf = (*s).to_mut(); &gt; let fallible_cs_buf = (*fallible_cs).fallible_to_mut().unwrap(); &gt; let fallible_s_buf = (*fallible_s).fallible_to_mut().unwrap(); &gt; &gt; cs_buf[0] = b'A'; &gt; cs_buf[1] = b'B'; &gt;diff --git a/xpcom/rust/gtest/xpcom/test.rs b/xpcom/rust/gtest/xpcom/test.rs &gt;index f2931499524f..a8ee9b18d2f6 100644 &gt;--- a/xpcom/rust/gtest/xpcom/test.rs &gt;+++ b/xpcom/rust/gtest/xpcom/test.rs &gt;@@ -4,69 +4,79 @@ &gt; &gt; #![allow(non_snake_case)] &gt; &gt; #[macro_use] &gt; extern crate xpcom; &gt; &gt; extern crate nserror; &gt; &gt;+use nserror::{nsresult, NsresultExt, NS_OK}; &gt;+use std::ffi::{CStr, CString}; &gt; use std::os::raw::c_char; &gt; use std::ptr; &gt;-use std::ffi::{CStr, CString}; &gt; use xpcom::interfaces; &gt;-use nserror::{NsresultExt, nsresult, NS_OK}; &gt; &gt; #[no_mangle] &gt;-pub unsafe extern fn Rust_ObserveFromRust() -&gt; *const interfaces::nsIObserverService { &gt;+pub unsafe extern "C" fn Rust_ObserveFromRust() -&gt; *const interfaces::nsIObserverService { &gt; let obssvc = xpcom::services::get_ObserverService().unwrap(); &gt; &gt; // Define an observer &gt; #[derive(xpcom)] &gt; #[xpimplements(nsIObserver)] &gt; #[refcnt = "nonatomic"] &gt; struct InitObserver { &gt;- run: *mut bool &gt;+ run: *mut bool, &gt; } &gt; impl Observer { &gt; unsafe fn Observe( &gt; &amp;self, &gt; _subject: *const interfaces::nsISupports, &gt; topic: *const c_char, &gt;- _data: *const i16 &gt;+ _data: *const i16, &gt; ) -&gt; nsresult { &gt; *self.run = true; &gt; assert!(CStr::from_ptr(topic).to_str() == Ok("test-rust-observe")); &gt; NS_OK &gt; } &gt; } &gt; &gt; let topic = CString::new("test-rust-observe").unwrap(); &gt; &gt; let mut run = false; &gt;- let observer = Observer::allocate(InitObserver{ run: &amp;mut run }); &gt;- let rv = obssvc.AddObserver(observer.coerce::&lt;interfaces::nsIObserver&gt;(), topic.as_ptr(), false); &gt;+ let observer = Observer::allocate(InitObserver { run: &amp;mut run }); &gt;+ let rv = obssvc.AddObserver( &gt;+ observer.coerce::&lt;interfaces::nsIObserver&gt;(), &gt;+ topic.as_ptr(), &gt;+ false, &gt;+ ); &gt; assert!(rv.succeeded()); &gt; &gt; let rv = obssvc.NotifyObservers(ptr::null(), topic.as_ptr(), ptr::null()); &gt; assert!(rv.succeeded()); &gt; assert!(run, "The observer should have been run!"); &gt; &gt; let rv = obssvc.RemoveObserver(observer.coerce::&lt;interfaces::nsIObserver&gt;(), topic.as_ptr()); &gt; assert!(rv.succeeded()); &gt; &gt;- assert!(observer.coerce::&lt;interfaces::nsISupports&gt;() as *const _== &gt;- &amp;*observer.query_interface::&lt;interfaces::nsISupports&gt;().unwrap() as *const _); &gt;+ assert!( &gt;+ observer.coerce::&lt;interfaces::nsISupports&gt;() as *const _ == &amp;*observer &gt;+ .query_interface::&lt;interfaces::nsISupports&gt;() &gt;+ .unwrap() &gt;+ as *const _ &gt;+ ); &gt; &gt; &amp;*obssvc &gt; } &gt; &gt; #[no_mangle] &gt;-pub unsafe extern fn Rust_ImplementRunnableInRust(it_worked: *mut bool, &gt;- runnable: *mut *const interfaces::nsIRunnable) { &gt;+pub unsafe extern "C" fn Rust_ImplementRunnableInRust( &gt;+ it_worked: *mut bool, &gt;+ runnable: *mut *const interfaces::nsIRunnable, &gt;+) { &gt; // Define a type which implements nsIRunnable in rust. &gt; #[derive(xpcom)] &gt; #[xpimplements(nsIRunnable)] &gt; #[refcnt = "atomic"] &gt; struct InitMyRunnable { &gt; it_worked: *mut bool, &gt; } &gt; &gt;@@ -74,12 +84,15 @@ pub unsafe extern fn Rust_ImplementRunnableInRust(it_worked: *mut bool, &gt; unsafe fn Run(&amp;self) -&gt; nsresult { &gt; *self.it_worked = true; &gt; NS_OK &gt; } &gt; } &gt; &gt; // Create my runnable type, and forget it into the outparameter! &gt; let my_runnable = MyRunnable::allocate(InitMyRunnable { &gt;- it_worked: it_worked &gt;+ it_worked: it_worked, &gt; }); &gt;- my_runnable.query_interface::&lt;interfaces::nsIRunnable&gt;().unwrap().forget(&amp;mut *runnable); &gt;+ my_runnable &gt;+ .query_interface::&lt;interfaces::nsIRunnable&gt;() &gt;+ .unwrap() &gt;+ .forget(&amp;mut *runnable); &gt; } &gt;diff --git a/xpcom/rust/nserror/src/lib.rs b/xpcom/rust/nserror/src/lib.rs &gt;index 94c962962de1..9231b35f8fd4 100644 &gt;--- a/xpcom/rust/nserror/src/lib.rs &gt;+++ b/xpcom/rust/nserror/src/lib.rs &gt;@@ -1,11 +1,11 @@ &gt; extern crate nsstring; &gt; &gt;-use nsstring::{nsCString, nsACString}; &gt;+use nsstring::{nsACString, nsCString}; &gt; &gt; /// The type of errors in gecko. This type is currently a type alias, rather &gt; /// than a newtype, in order to conform to the C ABI. In future versions of rust &gt; /// which support RFC #1758 or similar we may be able to use &gt; /// `#[repr(transparent)]` to get a better API for using nsresult. &gt; /// &gt; /// The most unfortunate thing about this current implementation is that `u32` &gt; /// and `nsresult` unify. &gt;diff --git a/xpcom/rust/xpcom/src/base.rs b/xpcom/rust/xpcom/src/base.rs &gt;index c8104755b99d..9d13cdc95d8d 100644 &gt;--- a/xpcom/rust/xpcom/src/base.rs &gt;+++ b/xpcom/rust/xpcom/src/base.rs &gt;@@ -1,19 +1,15 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt;-use { &gt;- RefCounted, &gt;- RefPtr, &gt;- GetterAddrefs &gt;-}; &gt; use interfaces::nsISupports; &gt; use nserror::NsresultExt; &gt;+use {GetterAddrefs, RefCounted, RefPtr}; &gt; &gt; #[repr(C)] &gt; #[derive(Copy, Clone, Eq, PartialEq)] &gt; /// A "unique identifier". This is modeled after OSF DCE UUIDs. &gt; pub struct nsID(pub u32, pub u16, pub u16, pub [u8; 8]); &gt; &gt; /// Interface IDs &gt; pub type nsIID = nsID; &gt;@@ -21,28 +17,28 @@ pub type nsIID = nsID; &gt; pub type nsCID = nsID; &gt; &gt; /// A type which implements XpCom must follow the following rules: &gt; /// &gt; /// * It must be a legal XPCOM interface. &gt; /// * The result of a QueryInterface or similar call, passing IID, must return a &gt; /// valid reference to an object of the given type. &gt; /// * It must be valid to cast a &amp;self reference to a &amp;nsISupports reference. &gt;-pub unsafe trait XpCom : RefCounted { &gt;+pub unsafe trait XpCom: RefCounted { &gt; const IID: nsIID; &gt; &gt; /// Perform a QueryInterface call on this object, attempting to dynamically &gt; /// cast it to the requested interface type. Returns Some(RefPtr&lt;T&gt;) if the &gt; /// cast succeeded, and None otherwise. &gt; fn query_interface&lt;T: XpCom&gt;(&amp;self) -&gt; Option&lt;RefPtr&lt;T&gt;&gt; { &gt; let mut ga = GetterAddrefs::&lt;T&gt;::new(); &gt; unsafe { &gt;- if (*(self as *const Self as *const nsISupports)).QueryInterface( &gt;- &amp;T::IID, &gt;- ga.void_ptr(), &gt;- ).succeeded() { &gt;+ if (*(self as *const Self as *const nsISupports)) &gt;+ .QueryInterface(&amp;T::IID, ga.void_ptr()) &gt;+ .succeeded() &gt;+ { &gt; ga.refptr() &gt; } else { &gt; None &gt; } &gt; } &gt; } &gt; } &gt;diff --git a/xpcom/rust/xpcom/src/interfaces/idl.rs b/xpcom/rust/xpcom/src/interfaces/idl.rs &gt;index 6065c3b3f4a3..b367b82a31e6 100644 &gt;--- a/xpcom/rust/xpcom/src/interfaces/idl.rs &gt;+++ b/xpcom/rust/xpcom/src/interfaces/idl.rs &gt;@@ -1,12 +1,12 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; #![allow(bad_style)] &gt; &gt;-use *; &gt; use interfaces::*; &gt;+use *; &gt; &gt; // NOTE: This file contains a series of `include!()` invocations, defining all &gt; // idl interfaces directly within this module. &gt; include!(concat!(env!("MOZ_TOPOBJDIR"), "/dist/xpcrs/rt/all.rs")); &gt;diff --git a/xpcom/rust/xpcom/src/interfaces/nonidl.rs b/xpcom/rust/xpcom/src/interfaces/nonidl.rs &gt;index f3050eb931a5..15f4a93dac12 100644 &gt;--- a/xpcom/rust/xpcom/src/interfaces/nonidl.rs &gt;+++ b/xpcom/rust/xpcom/src/interfaces/nonidl.rs &gt;@@ -36,75 +36,145 @@ macro_rules! nonidl { &gt; self.Release(); &gt; } &gt; } &gt; &gt; impl ::std::ops::Deref for $name { &gt; type Target = $crate::interfaces::nsISupports; &gt; #[inline] &gt; fn deref(&amp;self) -&gt; &amp;$crate::interfaces::nsISupports { &gt;- unsafe { &gt;- ::std::mem::transmute(self) &gt;- } &gt;+ unsafe { ::std::mem::transmute(self) } &gt; } &gt; } &gt;- } &gt;+ }; &gt; } &gt; &gt; // Must be kept in sync with nsIDocument.h &gt;-nonidl!(nsIDocument, &gt;- nsID(0xce1f7627, 0x7109, 0x4977, &gt;- [0xba, 0x77, 0x49, 0x0f, 0xfd, 0xe0, 0x7a, 0xaa])); &gt;+nonidl!( &gt;+ nsIDocument, &gt;+ nsID( &gt;+ 0xce1f7627, &gt;+ 0x7109, &gt;+ 0x4977, &gt;+ [0xba, 0x77, 0x49, 0x0f, 0xfd, 0xe0, 0x7a, 0xaa] &gt;+ ) &gt;+); &gt; &gt; // Must be kept in sync with nsINode.h &gt;-nonidl!(nsINode, &gt;- nsID(0x70ba4547, 0x7699, 0x44fc, &gt;- [0xb3, 0x20, 0x52, 0xdb, 0xe3, 0xd1, 0xf9, 0x0a])); &gt;+nonidl!( &gt;+ nsINode, &gt;+ nsID( &gt;+ 0x70ba4547, &gt;+ 0x7699, &gt;+ 0x44fc, &gt;+ [0xb3, 0x20, 0x52, 0xdb, 0xe3, 0xd1, 0xf9, 0x0a] &gt;+ ) &gt;+); &gt; &gt; // Must be kept in sync with nsIContent.h &gt;-nonidl!(nsIContent, &gt;- nsID(0x8e1bab9d, 0x8815, 0x4d2c, &gt;- [0xa2, 0x4d, 0x7a, 0xba, 0x52, 0x39, 0xdc, 0x22])); &gt;+nonidl!( &gt;+ nsIContent, &gt;+ nsID( &gt;+ 0x8e1bab9d, &gt;+ 0x8815, &gt;+ 0x4d2c, &gt;+ [0xa2, 0x4d, 0x7a, 0xba, 0x52, 0x39, 0xdc, 0x22] &gt;+ ) &gt;+); &gt; &gt; // Must be kept in sync with nsIConsoleReportCollector.h &gt;-nonidl!(nsIConsoleReportCollector, &gt;- nsID(0xdd98a481, 0xd2c4, 0x4203, &gt;- [0x8d, 0xfa, 0x85, 0xbf, 0xd7, 0xdc, 0xd7, 0x05])); &gt;+nonidl!( &gt;+ nsIConsoleReportCollector, &gt;+ nsID( &gt;+ 0xdd98a481, &gt;+ 0xd2c4, &gt;+ 0x4203, &gt;+ [0x8d, 0xfa, 0x85, 0xbf, 0xd7, 0xdc, 0xd7, 0x05] &gt;+ ) &gt;+); &gt; &gt; // Must be kept in sync with nsIGlobalObject.h &gt;-nonidl!(nsIGlobalObject, &gt;- nsID(0x11afa8be, 0xd997, 0x4e07, &gt;- [0xa6, 0xa3, 0x6f, 0x87, 0x2e, 0xc3, 0xee, 0x7f])); &gt;+nonidl!( &gt;+ nsIGlobalObject, &gt;+ nsID( &gt;+ 0x11afa8be, &gt;+ 0xd997, &gt;+ 0x4e07, &gt;+ [0xa6, 0xa3, 0x6f, 0x87, 0x2e, 0xc3, 0xee, 0x7f] &gt;+ ) &gt;+); &gt; &gt; // Must be kept in sync with nsIScriptElement.h &gt;-nonidl!(nsIScriptElement, &gt;- nsID(0xe60fca9b, 0x1b96, 0x4e4e, &gt;- [0xa9, 0xb4, 0xdc, 0x98, 0x4f, 0x88, 0x3f, 0x9c])); &gt;+nonidl!( &gt;+ nsIScriptElement, &gt;+ nsID( &gt;+ 0xe60fca9b, &gt;+ 0x1b96, &gt;+ 0x4e4e, &gt;+ [0xa9, 0xb4, 0xdc, 0x98, 0x4f, 0x88, 0x3f, 0x9c] &gt;+ ) &gt;+); &gt; &gt; // Must be kept in sync with nsPIDOMWindow.h &gt;-nonidl!(nsPIDOMWindowOuter, &gt;- nsID(0x769693d4, 0xb009, 0x4fe2, &gt;- [0xaf, 0x18, 0x7d, 0xc8, 0xdf, 0x74, 0x96, 0xdf])); &gt;+nonidl!( &gt;+ nsPIDOMWindowOuter, &gt;+ nsID( &gt;+ 0x769693d4, &gt;+ 0xb009, &gt;+ 0x4fe2, &gt;+ [0xaf, 0x18, 0x7d, 0xc8, 0xdf, 0x74, 0x96, 0xdf] &gt;+ ) &gt;+); &gt; &gt; // Must be kept in sync with nsPIDOMWindow.h &gt;-nonidl!(nsPIDOMWindowInner, &gt;- nsID(0x775dabc9, 0x8f43, 0x4277, &gt;- [0x9a, 0xdb, 0xf1, 0x99, 0x0d, 0x77, 0xcf, 0xfb])); &gt;+nonidl!( &gt;+ nsPIDOMWindowInner, &gt;+ nsID( &gt;+ 0x775dabc9, &gt;+ 0x8f43, &gt;+ 0x4277, &gt;+ [0x9a, 0xdb, 0xf1, 0x99, 0x0d, 0x77, 0xcf, 0xfb] &gt;+ ) &gt;+); &gt; &gt; // Must be kept in sync with nsIScriptContext.h &gt;-nonidl!(nsIScriptContext, &gt;- nsID(0x54cbe9cf, 0x7282, 0x421a, &gt;- [0x91, 0x6f, 0xd0, 0x70, 0x73, 0xde, 0xb8, 0xc0])); &gt;+nonidl!( &gt;+ nsIScriptContext, &gt;+ nsID( &gt;+ 0x54cbe9cf, &gt;+ 0x7282, &gt;+ 0x421a, &gt;+ [0x91, 0x6f, 0xd0, 0x70, 0x73, 0xde, 0xb8, 0xc0] &gt;+ ) &gt;+); &gt; &gt; // Must be kept in sync with nsIScriptGlobalObject.h &gt;-nonidl!(nsIScriptGlobalObject, &gt;- nsID(0x876f83bd, 0x6314, 0x460a, &gt;- [0xa0, 0x45, 0x1c, 0x8f, 0x46, 0x2f, 0xb8, 0xe1])); &gt;+nonidl!( &gt;+ nsIScriptGlobalObject, &gt;+ nsID( &gt;+ 0x876f83bd, &gt;+ 0x6314, &gt;+ 0x460a, &gt;+ [0xa0, 0x45, 0x1c, 0x8f, 0x46, 0x2f, 0xb8, 0xe1] &gt;+ ) &gt;+); &gt; &gt; // Must be kept in sync with nsIScrollObserver.h &gt;-nonidl!(nsIScrollObserver, &gt;- nsID(0xaa5026eb, 0x2f88, 0x4026, &gt;- [0xa4, 0x6b, 0xf4, 0x59, 0x6b, 0x4e, 0xdf, 0x00])); &gt;+nonidl!( &gt;+ nsIScrollObserver, &gt;+ nsID( &gt;+ 0xaa5026eb, &gt;+ 0x2f88, &gt;+ 0x4026, &gt;+ [0xa4, 0x6b, 0xf4, 0x59, 0x6b, 0x4e, 0xdf, 0x00] &gt;+ ) &gt;+); &gt; &gt; // Must be kept in sync with nsIWidget.h &gt;-nonidl!(nsIWidget, &gt;- nsID(0x06396bf6, 0x2dd8, 0x45e5, &gt;- [0xac, 0x45, 0x75, 0x26, 0x53, 0xb1, 0xc9, 0x80])); &gt;+nonidl!( &gt;+ nsIWidget, &gt;+ nsID( &gt;+ 0x06396bf6, &gt;+ 0x2dd8, &gt;+ 0x45e5, &gt;+ [0xac, 0x45, 0x75, 0x26, 0x53, 0xb1, 0xc9, 0x80] &gt;+ ) &gt;+); &gt;diff --git a/xpcom/rust/xpcom/src/lib.rs b/xpcom/rust/xpcom/src/lib.rs &gt;index c75521780b04..f04463630a49 100644 &gt;--- a/xpcom/rust/xpcom/src/lib.rs &gt;+++ b/xpcom/rust/xpcom/src/lib.rs &gt;@@ -7,18 +7,18 @@ &gt; //! &gt; //! For documentation on how to implement XPCOM methods, see the documentation &gt; //! for the [`xpcom_macros`](../xpcom_macros/index.html) crate. &gt; &gt; #![allow(non_snake_case)] &gt; #![allow(non_camel_case_types)] &gt; &gt; extern crate libc; &gt;-extern crate nsstring; &gt; extern crate nserror; &gt;+extern crate nsstring; &gt; &gt; // re-export the xpcom_macros macro &gt; #[macro_use] &gt; #[allow(unused_imports)] &gt; extern crate xpcom_macros; &gt; #[doc(hidden)] &gt; pub use xpcom_macros::*; &gt; &gt;diff --git a/xpcom/rust/xpcom/src/reexports.rs b/xpcom/rust/xpcom/src/reexports.rs &gt;index 623e8a44580e..df6d99905253 100644 &gt;--- a/xpcom/rust/xpcom/src/reexports.rs &gt;+++ b/xpcom/rust/xpcom/src/reexports.rs &gt;@@ -2,17 +2,16 @@ &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt; /// The automatically generated code from `xpcom_macros` depends on some types &gt; /// which are defined in other libraries which `xpcom` depends on, but which may &gt; /// not be `extern crate`-ed into the crate the macros are expanded into. This &gt; /// module re-exports those types from `xpcom` so that they can be used from the &gt; /// macro. &gt;- &gt; // re-export libc so it can be used by the procedural macro. &gt; pub extern crate libc; &gt; &gt; pub use nsstring::{nsACString, nsAString, nsCString, nsString}; &gt; &gt; pub use nserror::{nsresult, NsresultExt, NS_ERROR_NO_INTERFACE, NS_OK}; &gt; &gt; pub use std::ops::Deref; &gt;diff --git a/xpcom/rust/xpcom/src/refptr.rs b/xpcom/rust/xpcom/src/refptr.rs &gt;index 3b1909bbd5e1..b07c432920f0 100644 &gt;--- a/xpcom/rust/xpcom/src/refptr.rs &gt;+++ b/xpcom/rust/xpcom/src/refptr.rs &gt;@@ -1,20 +1,20 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt;+use std::cell::Cell; &gt;+use std::marker::PhantomData; &gt; use std::mem; &gt;-use std::ptr; &gt; use std::ops::Deref; &gt;-use std::marker::PhantomData; &gt;-use std::cell::Cell; &gt;+use std::ptr; &gt; use std::sync::atomic::{self, AtomicUsize, Ordering}; &gt; &gt;-use nserror::{NsresultExt, nsresult, NS_OK}; &gt;+use nserror::{nsresult, NsresultExt, NS_OK}; &gt; &gt; use libc; &gt; &gt; use interfaces::nsrefcnt; &gt; &gt; /// A trait representing a type which can be reference counted invasively. &gt; /// The object is responsible for freeing its backing memory when its &gt; /// reference count reaches 0. &gt;@@ -35,17 +35,17 @@ pub struct RefPtr&lt;T: RefCounted + 'static&gt; { &gt; // I believe that this is "safe enough", as this module is private and &gt; // no other module can read this reference. &gt; _ptr: &amp;'static T, &gt; // As we aren't using Shared&lt;T&gt;, we need to add this phantomdata to &gt; // prevent unsoundness in dropck &gt; _marker: PhantomData&lt;T&gt;, &gt; } &gt; &gt;-impl &lt;T: RefCounted + 'static&gt; RefPtr&lt;T&gt; { &gt;+impl&lt;T: RefCounted + 'static&gt; RefPtr&lt;T&gt; { &gt; /// Construct a new RefPtr from a reference to the refcounted object. &gt; #[inline] &gt; pub fn new(p: &amp;T) -&gt; RefPtr&lt;T&gt; { &gt; unsafe { &gt; p.addref(); &gt; RefPtr { &gt; _ptr: mem::transmute(p), &gt; _marker: PhantomData, &gt;@@ -81,51 +81,51 @@ impl &lt;T: RefCounted + 'static&gt; RefPtr&lt;T&gt; { &gt; /// Write this RefPtr's value into an outparameter. &gt; #[inline] &gt; pub fn forget(self, into: &amp;mut *const T) { &gt; *into = &amp;*self; &gt; mem::forget(self); &gt; } &gt; } &gt; &gt;-impl &lt;T: RefCounted + 'static&gt; Deref for RefPtr&lt;T&gt; { &gt;+impl&lt;T: RefCounted + 'static&gt; Deref for RefPtr&lt;T&gt; { &gt; type Target = T; &gt; #[inline] &gt; fn deref(&amp;self) -&gt; &amp;T { &gt; self._ptr &gt; } &gt; } &gt; &gt;-impl &lt;T: RefCounted + 'static&gt; Drop for RefPtr&lt;T&gt; { &gt;+impl&lt;T: RefCounted + 'static&gt; Drop for RefPtr&lt;T&gt; { &gt; #[inline] &gt; fn drop(&amp;mut self) { &gt; unsafe { &gt; self._ptr.release(); &gt; } &gt; } &gt; } &gt; &gt;-impl &lt;T: RefCounted + 'static&gt; Clone for RefPtr&lt;T&gt; { &gt;+impl&lt;T: RefCounted + 'static&gt; Clone for RefPtr&lt;T&gt; { &gt; #[inline] &gt; fn clone(&amp;self) -&gt; RefPtr&lt;T&gt; { &gt; RefPtr::new(self) &gt; } &gt; } &gt; &gt; /// A helper struct for constructing `RefPtr&lt;T&gt;` from raw pointer outparameters. &gt; /// Holds a `*const T` internally which will be released if non null when &gt; /// destructed, and can be easily transformed into an `Option&lt;RefPtr&lt;T&gt;&gt;`. &gt; /// &gt; /// It many cases it may be easier to use the `getter_addrefs` method. &gt; pub struct GetterAddrefs&lt;T: RefCounted + 'static&gt; { &gt; _ptr: *const T, &gt; _marker: PhantomData&lt;T&gt;, &gt; } &gt; &gt;-impl &lt;T: RefCounted + 'static&gt; GetterAddrefs&lt;T&gt; { &gt;+impl&lt;T: RefCounted + 'static&gt; GetterAddrefs&lt;T&gt; { &gt; /// Create a `GetterAddrefs`, initializing it with the null pointer. &gt; #[inline] &gt; pub fn new() -&gt; GetterAddrefs&lt;T&gt; { &gt; GetterAddrefs { &gt; _ptr: ptr::null(), &gt; _marker: PhantomData, &gt; } &gt; } &gt;@@ -149,23 +149,21 @@ impl &lt;T: RefCounted + 'static&gt; GetterAddrefs&lt;T&gt; { &gt; /// Transform this `GetterAddrefs` into an `Option&lt;RefPtr&lt;T&gt;&gt;`, without &gt; /// performing any addrefs or releases. &gt; #[inline] &gt; pub fn refptr(self) -&gt; Option&lt;RefPtr&lt;T&gt;&gt; { &gt; let p = self._ptr; &gt; // Don't run the destructor because we don't want to release the stored &gt; // pointer. &gt; mem::forget(self); &gt;- unsafe { &gt;- RefPtr::from_raw_dont_addref(p) &gt;- } &gt;+ unsafe { RefPtr::from_raw_dont_addref(p) } &gt; } &gt; } &gt; &gt;-impl &lt;T: RefCounted + 'static&gt; Drop for GetterAddrefs&lt;T&gt; { &gt;+impl&lt;T: RefCounted + 'static&gt; Drop for GetterAddrefs&lt;T&gt; { &gt; #[inline] &gt; fn drop(&amp;mut self) { &gt; if !self._ptr.is_null() { &gt; unsafe { &gt; (*self._ptr).release(); &gt; } &gt; } &gt; } &gt;@@ -185,17 +183,18 @@ impl &lt;T: RefCounted + 'static&gt; Drop for GetterAddrefs&lt;T&gt; { &gt; /// # Usage &gt; /// &gt; /// ``` &gt; /// let x: Result&lt;RefPtr&lt;T&gt;, nsresult&gt; = &gt; /// getter_addrefs(|p| iosvc.NewURI(uri, ptr::null(), ptr::null(), p)); &gt; /// ``` &gt; #[inline] &gt; pub fn getter_addrefs&lt;T: RefCounted, F&gt;(f: F) -&gt; Result&lt;RefPtr&lt;T&gt;, nsresult&gt; &gt;- where F: FnOnce(*mut *const T) -&gt; nsresult &gt;+where &gt;+ F: FnOnce(*mut *const T) -&gt; nsresult, &gt; { &gt; let mut ga = GetterAddrefs::&lt;T&gt;::new(); &gt; let rv = f(unsafe { ga.ptr() }); &gt; if rv.failed() { &gt; return Err(rv); &gt; } &gt; ga.refptr().ok_or(NS_OK) &gt; } &gt;diff --git a/xpcom/rust/xpcom/src/statics.rs b/xpcom/rust/xpcom/src/statics.rs &gt;index 6565035db9af..7af100f9b9c3 100644 &gt;--- a/xpcom/rust/xpcom/src/statics.rs &gt;+++ b/xpcom/rust/xpcom/src/statics.rs &gt;@@ -1,100 +1,83 @@ &gt; /* This Source Code Form is subject to the terms of the Mozilla Public &gt; * License, v. 2.0. If a copy of the MPL was not distributed with this &gt; * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ &gt; &gt;+use nserror::NsresultExt; &gt; use std::ffi::CStr; &gt; use std::ptr; &gt;-use nserror::NsresultExt; &gt;-use { &gt;- RefPtr, &gt;- GetterAddrefs, &gt;- XpCom, &gt;-}; &gt;+use {GetterAddrefs, RefPtr, XpCom}; &gt; &gt;-use interfaces::{ &gt;- nsIComponentManager, &gt;- nsIServiceManager, &gt;- nsIComponentRegistrar, &gt;-}; &gt;+use interfaces::{nsIComponentManager, nsIComponentRegistrar, nsIServiceManager}; &gt; &gt; macro_rules! try_opt { &gt; ($e: expr) =&gt; { &gt; match $e { &gt; Some(x) =&gt; x, &gt; None =&gt; return None, &gt; } &gt;- } &gt;+ }; &gt; } &gt; &gt; /// Get a reference to the global `nsIComponentManager`. &gt; /// &gt; /// Can return `None` during shutdown. &gt; #[inline] &gt; pub fn component_manager() -&gt; Option&lt;RefPtr&lt;nsIComponentManager&gt;&gt; { &gt;- unsafe { &gt;- RefPtr::from_raw(Gecko_GetComponentManager()) &gt;- } &gt;+ unsafe { RefPtr::from_raw(Gecko_GetComponentManager()) } &gt; } &gt; &gt; /// Get a reference to the global `nsIServiceManager`. &gt; /// &gt; /// Can return `None` during shutdown. &gt; #[inline] &gt; pub fn service_manager() -&gt; Option&lt;RefPtr&lt;nsIServiceManager&gt;&gt; { &gt;- unsafe { &gt;- RefPtr::from_raw(Gecko_GetServiceManager()) &gt;- } &gt;+ unsafe { RefPtr::from_raw(Gecko_GetServiceManager()) } &gt; } &gt; &gt; /// Get a reference to the global `nsIComponentRegistrar` &gt; /// &gt; /// Can return `None` during shutdown. &gt; #[inline] &gt; pub fn component_registrar() -&gt; Option&lt;RefPtr&lt;nsIComponentRegistrar&gt;&gt; { &gt;- unsafe { &gt;- RefPtr::from_raw(Gecko_GetComponentRegistrar()) &gt;- } &gt;+ unsafe { RefPtr::from_raw(Gecko_GetComponentRegistrar()) } &gt; } &gt; &gt; /// Helper for calling `nsIComponentManager::CreateInstanceByContractID` on the &gt; /// global `nsIComponentRegistrar`. &gt; /// &gt; /// This method is similar to `do_CreateInstance` in C++. &gt; #[inline] &gt; pub fn create_instance&lt;T: XpCom&gt;(id: &amp;CStr) -&gt; Option&lt;RefPtr&lt;T&gt;&gt; { &gt; unsafe { &gt; let mut ga = GetterAddrefs::&lt;T&gt;::new(); &gt;- if try_opt!(component_manager()).CreateInstanceByContractID( &gt;- id.as_ptr(), &gt;- ptr::null(), &gt;- &amp;T::IID, &gt;- ga.void_ptr(), &gt;- ).succeeded() { &gt;+ if try_opt!(component_manager()) &gt;+ .CreateInstanceByContractID(id.as_ptr(), ptr::null(), &amp;T::IID, ga.void_ptr()) &gt;+ .succeeded() &gt;+ { &gt; ga.refptr() &gt; } else { &gt; None &gt; } &gt; } &gt; } &gt; &gt; /// Helper for calling `nsIServiceManager::GetServiceByContractID` on the global &gt; /// `nsIServiceManager`. &gt; /// &gt; /// This method is similar to `do_GetService` in C++. &gt; #[inline] &gt; pub fn get_service&lt;T: XpCom&gt;(id: &amp;CStr) -&gt; Option&lt;RefPtr&lt;T&gt;&gt; { &gt; unsafe { &gt; let mut ga = GetterAddrefs::&lt;T&gt;::new(); &gt;- if try_opt!(service_manager()).GetServiceByContractID( &gt;- id.as_ptr(), &gt;- &amp;T::IID, &gt;- ga.void_ptr() &gt;- ).succeeded() { &gt;+ if try_opt!(service_manager()) &gt;+ .GetServiceByContractID(id.as_ptr(), &amp;T::IID, ga.void_ptr()) &gt;+ .succeeded() &gt;+ { &gt; ga.refptr() &gt; } else { &gt; None &gt; } &gt; } &gt; } &gt; &gt; extern "C" { &gt;diff --git a/xpcom/rust/xpcom/xpcom_macros/src/lib.rs b/xpcom/rust/xpcom/xpcom_macros/src/lib.rs &gt;index 260d4ca64b18..af71a4e99938 100644 &gt;--- a/xpcom/rust/xpcom/xpcom_macros/src/lib.rs &gt;+++ b/xpcom/rust/xpcom/xpcom_macros/src/lib.rs &gt;@@ -121,17 +121,17 @@ &gt; //! &gt; //! [`xpcom`]: ../xpcom/index.html &gt; //! [`nsIRunnable`]: ../xpcom/struct.nsIRunnable.html &gt; //! [`RefCounted`]: ../xpcom/struct.RefCounted.html &gt; //! [`RefPtr`]: ../xpcom/struct.RefPtr.html &gt; &gt; // NOTE: We use some really big quote! invocations, so we need a high recursion &gt; // limit. &gt;-#![recursion_limit="256"] &gt;+#![recursion_limit = "256"] &gt; &gt; #[macro_use] &gt; extern crate quote; &gt; &gt; #[macro_use] &gt; extern crate syn; &gt; &gt; extern crate proc_macro; &gt;@@ -174,19 +174,21 @@ struct Interface { &gt; name: &amp;'static str, &gt; base: Option&lt;&amp;'static str&gt;, &gt; methods: Result&lt;&amp;'static [Method], &amp;'static str&gt;, &gt; } &gt; &gt; impl Interface { &gt; fn base(&amp;self) -&gt; Result&lt;Option&lt;&amp;'static Interface&gt;, Box&lt;Error&gt;&gt; { &gt; Ok(if let Some(base) = self.base { &gt;- Some(*IFACES.get(base).ok_or_else( &gt;- || format!("Base interface {} does not exist", base) &gt;- )?) &gt;+ Some( &gt;+ *IFACES &gt;+ .get(base) &gt;+ .ok_or_else(|| format!("Base interface {} does not exist", base))?, &gt;+ ) &gt; } else { &gt; None &gt; }) &gt; } &gt; } &gt; &gt; lazy_static! { &gt; /// This item contains the information generated by the procedural macro in &gt;@@ -261,64 +263,73 @@ fn get_bases(attrs: &amp;[Attribute]) -&gt; Result&lt;Vec&lt;&amp;'static Interface&gt;, Box&lt;Error&gt;&gt; &gt; continue; &gt; } &gt; &gt; for item in &amp;attr.nested { &gt; if let NestedMeta::Meta(Meta::Word(ref iface)) = *item { &gt; if let Some(&amp;iface) = IFACES.get(iface.as_ref()) { &gt; inherits.push(iface); &gt; } else { &gt;- Err(format!("Unexpected invalid base interface `{}` in \ &gt;- #[xpimplements(..)]", iface))? &gt;+ Err(format!( &gt;+ "Unexpected invalid base interface `{}` in \ &gt;+ #[xpimplements(..)]", &gt;+ iface &gt;+ ))? &gt; } &gt; } else { &gt; Err("Unexpected non-identifier in #[xpimplements(..)]")? &gt; } &gt; } &gt; } &gt; } &gt; Ok(inherits) &gt; } &gt; &gt; /// Extract the fields list from the input struct. &gt; fn get_fields(di: &amp;DeriveInput) -&gt; Result&lt;&amp;Punctuated&lt;Field, Token![,]&gt;, Box&lt;Error&gt;&gt; { &gt; match di.data { &gt; Data::Struct(DataStruct { &gt;- fields: Fields::Named(ref named), .. &gt;+ fields: Fields::Named(ref named), &gt;+ .. &gt; }) =&gt; Ok(&amp;named.named), &gt; _ =&gt; Err("The initializer struct must be a standard \ &gt;- named value struct definition".into()) &gt;+ named value struct definition" &gt;+ .into()), &gt; } &gt; } &gt; &gt; /// Takes the `Init*` struct in, and generates a `DeriveInput` for the "real" struct. &gt;-fn gen_real_struct(init: &amp;DeriveInput, bases: &amp;[&amp;Interface], refcnt_ty: RefcntKind) -&gt; Result&lt;DeriveInput, Box&lt;Error&gt;&gt; { &gt;+fn gen_real_struct( &gt;+ init: &amp;DeriveInput, &gt;+ bases: &amp;[&amp;Interface], &gt;+ refcnt_ty: RefcntKind, &gt;+) -&gt; Result&lt;DeriveInput, Box&lt;Error&gt;&gt; { &gt; // Determine the name for the real struct based on the name of the &gt; // initializer struct's name. &gt; if !init.ident.as_ref().starts_with("Init") { &gt; Err("The target struct's name must begin with Init")? &gt; } &gt; let name: Ident = init.ident.as_ref()[4..].into(); &gt; let vis = &amp;init.vis; &gt; &gt; let bases = bases.iter().map(|base| { &gt; let ident = Ident::from(format!("__base_{}", base.name)); &gt; let vtable = Ident::from(format!("{}VTable", base.name)); &gt; quote!(#ident : *const xpcom::interfaces::#vtable) &gt;- }); &gt;+ }); &gt; &gt; let fields = get_fields(init)?; &gt; Ok(parse_quote! { &gt;- #[repr(C)] &gt;- #vis struct #name { &gt;- #(#bases,)* &gt;- __refcnt: #refcnt_ty, &gt;- #fields &gt;- } &gt;- }) &gt;+ #[repr(C)] &gt;+ #vis struct #name { &gt;+ #(#bases,)* &gt;+ __refcnt: #refcnt_ty, &gt;+ #fields &gt;+ } &gt;+ }) &gt; } &gt; &gt; /// Generates the `extern "system"` methods which are actually included in the &gt; /// VTable for the given interface. &gt; /// &gt; /// These methods attempt to invoke the `recover_self` method to translate from &gt; /// the passed-in raw pointer to the actual `&amp;self` value, and it is expected to &gt; /// be in scope. &gt;@@ -326,19 +337,23 @@ fn gen_vtable_methods(iface: &amp;Interface) -&gt; Result&lt;Tokens, Box&lt;Error&gt;&gt; { &gt; let base_ty = Ident::from(iface.name); &gt; &gt; let base_methods = if let Some(base) = iface.base()? { &gt; gen_vtable_methods(base)? &gt; } else { &gt; quote!{} &gt; }; &gt; &gt;- let methods = iface.methods &gt;- .map_err(|reason| format!("Interface {} cannot be implemented in rust \ &gt;- because {} is not supported yet", iface.name, reason))?; &gt;+ let methods = iface.methods.map_err(|reason| { &gt;+ format!( &gt;+ "Interface {} cannot be implemented in rust \ &gt;+ because {} is not supported yet", &gt;+ iface.name, reason &gt;+ ) &gt;+ })?; &gt; &gt; let mut method_defs = Vec::new(); &gt; for method in methods { &gt; let name = Ident::from(method.name); &gt; let ret = syn::parse_str::&lt;Type&gt;(method.ret)?; &gt; &gt; let mut params = Vec::new(); &gt; let mut args = Vec::new(); &gt;@@ -364,33 +379,39 @@ fn gen_vtable_methods(iface: &amp;Interface) -&gt; Result&lt;Tokens, Box&lt;Error&gt;&gt; { &gt; }) &gt; } &gt; &gt; /// Generates the VTable for a given base interface. This assumes that the &gt; /// implementations of each of the `extern "system"` methods are in scope. &gt; fn gen_inner_vtable(iface: &amp;Interface) -&gt; Result&lt;Tokens, Box&lt;Error&gt;&gt; { &gt; let vtable_ty = Ident::from(format!("{}VTable", iface.name)); &gt; &gt;- let methods = iface.methods &gt;- .map_err(|reason| format!("Interface {} cannot be implemented in rust \ &gt;- because {} is not supported yet", iface.name, reason))?; &gt;+ let methods = iface.methods.map_err(|reason| { &gt;+ format!( &gt;+ "Interface {} cannot be implemented in rust \ &gt;+ because {} is not supported yet", &gt;+ iface.name, reason &gt;+ ) &gt;+ })?; &gt; &gt; // Generate the vtable for the base interface. &gt; let base_vtable = if let Some(base) = iface.base()? { &gt; let vt = gen_inner_vtable(base)?; &gt; quote!{__base: #vt,} &gt; } else { &gt; quote!{} &gt; }; &gt; &gt; // Include each of the method definitions for this interface. &gt;- let vtable_init = methods.into_iter().map(|method| { &gt;- let name = Ident::from(method.name); &gt;- quote!{ #name : #name , } &gt;- }).collect::&lt;Vec&lt;_&gt;&gt;(); &gt;+ let vtable_init = methods &gt;+ .into_iter() &gt;+ .map(|method| { &gt;+ let name = Ident::from(method.name); &gt;+ quote!{ #name : #name , } &gt;+ }).collect::&lt;Vec&lt;_&gt;&gt;(); &gt; &gt; Ok(quote!(#vtable_ty { &gt; #base_vtable &gt; #(#vtable_init)* &gt; })) &gt; } &gt; &gt; fn gen_root_vtable(name: &amp;Ident, base: &amp;Interface) -&gt; Result&lt;Tokens, Box&lt;Error&gt;&gt; { &gt;@@ -442,23 +463,17 @@ fn gen_casts( &gt; vtable_field: &amp;Ident, &gt; ) -&gt; Result&lt;(Tokens, Tokens), Box&lt;Error&gt;&gt; { &gt; if !seen.insert(iface.name) { &gt; return Ok((quote!{}, quote!{})); &gt; } &gt; &gt; // Generate the cast implementations for the base interfaces. &gt; let (base_qi, base_coerce) = if let Some(base) = iface.base()? { &gt;- gen_casts( &gt;- seen, &gt;- base, &gt;- name, &gt;- coerce_name, &gt;- vtable_field, &gt;- )? &gt;+ gen_casts(seen, base, name, coerce_name, vtable_field)? &gt; } else { &gt; (quote!{}, quote!{}) &gt; }; &gt; &gt; // Add the if statment to QueryInterface for the base class. &gt; let base_name = Ident::from(iface.name); &gt; &gt; let qi = quote! { &gt;@@ -497,25 +512,27 @@ fn gen_casts( &gt; &gt; /// The root xpcom procedural macro definition. &gt; fn xpcom(init: DeriveInput) -&gt; Result&lt;Tokens, Box&lt;Error&gt;&gt; { &gt; if !init.generics.params.is_empty() || !init.generics.where_clause.is_none() { &gt; return Err("Cannot #[derive(xpcom)] on a generic type, due to \ &gt; rust limitations. It is not possible to instantiate \ &gt; a static with a generic type parameter, meaning that \ &gt; generic types cannot have their VTables instantiated \ &gt;- correctly.".into()); &gt;+ correctly." &gt;+ .into()); &gt; } &gt; &gt; let bases = get_bases(&amp;init.attrs)?; &gt; if bases.is_empty() { &gt; return Err("Types with #[derive(xpcom)] must implement at least one \ &gt; interface. Interfaces can be implemented by adding the \ &gt; #[xpimplements(nsIFoo, nsIBar)] attribute to the struct \ &gt;- declaration.".into()); &gt;+ declaration." &gt;+ .into()); &gt; } &gt; &gt; // Determine what reference count type to use, and generate the real struct. &gt; let refcnt_ty = get_refcnt_kind(&amp;init.attrs)?; &gt; let real = gen_real_struct(&amp;init, &amp;bases, refcnt_ty)?; &gt; &gt; let name_init = &amp;init.ident; &gt; let name = &amp;real.ident; &gt;@@ -663,10 +680,11 @@ fn xpcom(init: DeriveInput) -&gt; Result&lt;Tokens, Box&lt;Error&gt;&gt; { &gt; } &gt; } &gt; }) &gt; } &gt; &gt; #[proc_macro_derive(xpcom, attributes(xpimplements, refcnt))] &gt; pub fn xpcom_internal(input: TokenStream) -&gt; TokenStream { &gt; xpcom(parse(input).expect("Invalid derive input")) &gt;- .expect("#[derive(xpcom)] failed").into() &gt;+ .expect("#[derive(xpcom)] failed") &gt;+ .into() &gt; } &gt; </textarea> <iframe id="viewFrame" src="/attachment.cgi?id=9002232" sandbox> &lt;b&gt;You cannot view the attachment while viewing its details because your browser does not support IFRAMEs. &lt;a href="/attachment.cgi?id=9002232"&gt;View the attachment on a separate page&lt;/a&gt;.&lt;/b&gt; </iframe> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH"> <!-- var patchviewerinstalled = 0; var attachment_id = 9002232; if (typeof document.getElementById == "function") { var patchviewerinstalled = 1; document.write('<iframe id="viewDiffFrame" class="bz_default_hidden"><\/iframe>'); document.write('<button type="button" id="viewDiffButton" onclick="viewDiff(attachment_id, patchviewerinstalled);">View Attachment As Diff<\/button>'); document.write('<button type="button" id="viewRawButton" onclick="viewRaw(patchviewerinstalled);" class="bz_default_hidden">View Attachment As Raw<\/button>'); } //--> </script> </div> </div> <div id="attachment_comments_and_flags"> <div id="attachment_flags"> <p><b>Flags:</b></p><span title="Nathan Froyd [:froydnj]">froydnj</span>: feedback+<br> </div> </div> </div> </div> </form> <div id="attachment_actions"><span class="label">Actions:</span> <a href="https://bugzilla-mozilla-org.translate.goog/attachment.cgi?id=9002232&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB">View</a> | <a href="https://bugzilla-mozilla-org.translate.goog/attachment.cgi?id=9002232&amp;action=diff&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB">Diff</a> | <a href="https://bugzilla-mozilla-org.translate.goog/page.cgi?id=splinter.html&amp;ignore&amp;bug=1454764&amp;attachment=9002232&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB">Review</a> </div> <div id="attachment_list"> Attachments on <a class="bz_bug_link bz_status_REOPENED" title="REOPENED - [meta] rustfmt mozilla-central" href="https://bugzilla-mozilla-org.translate.goog/show_bug.cgi?id=1454764&amp;_x_tr_sl=pl&amp;_x_tr_tl=iw&amp;_x_tr_hl=en-GB">bug 1454764</a>: <span class="bz_obsolete"> 9002232 </span> </div> <link rel="stylesheet" href="/static/v20241126.1/extensions/FlagTypeComment/web/styles/ftc.css"> <script nonce="aaZdvjPuygMzJJIGV4IzGWzU8PV7JYAiQptetPKwOW0ha3xH" src="/static/v20241126.1/extensions/FlagTypeComment/web/js/ftc.js"></script> </div> </main> </div> <script>function gtElInit() {var lib = new google.translate.TranslateService();lib.translatePage('pl', 'iw', function () {});}</script> <script src="https://translate.google.com/translate_a/element.js?cb=gtElInit&amp;hl=en-GB&amp;client=wt" type="text/javascript"></script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10