summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Walbran <qwandor@google.com>2023-06-01 18:33:01 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-06-01 18:33:01 +0000
commitf8a943cdca7ef229f7873a3d68dac287fb6d8b59 (patch)
treecd28798ac383620be052e5394e2e0fbaea4a5a62
parent62404015ee301bd9a3a957ddcd7c8f1a24507134 (diff)
parentd918ea90ceed140f589ea8b5775c2fb656e6f971 (diff)
downloadlinkme-impl-f8a943cdca7ef229f7873a3d68dac287fb6d8b59.tar.gz
Initial import am: 2bee81a675 am: d918ea90ce
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/linkme-impl/+/2608747 Change-Id: Ie33d33eac2859a69b726fcafe87a3c22bd0e65fe Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo_vcs_info.json6
-rw-r--r--Android.bp20
-rw-r--r--Cargo.toml39
-rw-r--r--Cargo.toml.orig24
-rw-r--r--LICENSE176
-rw-r--r--LICENSE-APACHE176
-rw-r--r--LICENSE-MIT23
-rw-r--r--METADATA20
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--OWNERS1
-rw-r--r--cargo2android.json6
-rw-r--r--src/args.rs27
-rw-r--r--src/attr.rs37
-rw-r--r--src/declaration.rs300
-rw-r--r--src/element.rs241
-rw-r--r--src/hash.rs42
-rw-r--r--src/lib.rs32
-rw-r--r--src/linker.rs82
18 files changed, 1252 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..a449620
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+ "git": {
+ "sha1": "a0c3cdd977aefdf6674754ca8b1dc4aa41a7f0ae"
+ },
+ "path_in_vcs": "impl"
+} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..b7b8d0d
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,20 @@
+// This file is generated by cargo2android.py --config cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
+
+
+
+rust_proc_macro {
+ name: "liblinkme_impl",
+ crate_name: "linkme_impl",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.3.9",
+ srcs: ["src/lib.rs"],
+ edition: "2021",
+ rustlibs: [
+ "libproc_macro2",
+ "libquote",
+ "libsyn",
+ ],
+ product_available: true,
+ vendor_available: true,
+}
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..90491a7
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,39 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.62"
+name = "linkme-impl"
+version = "0.3.9"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+description = "Implementation detail of the linkme crate"
+documentation = "https://docs.rs/linkme"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/dtolnay/linkme"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[lib]
+proc-macro = true
+
+[dependencies.proc-macro2]
+version = "1.0.2"
+
+[dependencies.quote]
+version = "1.0"
+
+[dependencies.syn]
+version = "2.0"
+
+[features]
+used_linker = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..694b1c2
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,24 @@
+[package]
+name = "linkme-impl"
+version = "0.3.9"
+authors = ["David Tolnay <dtolnay@gmail.com>"]
+description = "Implementation detail of the linkme crate"
+documentation = "https://docs.rs/linkme"
+edition = "2021"
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/dtolnay/linkme"
+rust-version = "1.62"
+
+[lib]
+proc-macro = true
+
+[features]
+used_linker = []
+
+[dependencies]
+proc-macro2 = "1.0.2"
+quote = "1.0"
+syn = "2.0"
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1b5ec8b
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,176 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644
index 0000000..1b5ec8b
--- /dev/null
+++ b/LICENSE-APACHE
@@ -0,0 +1,176 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..f2c68f8
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,20 @@
+name: "linkme-impl"
+description: "Safe cross-platform linker shenanigans"
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://crates.io/crates/linkme-impl"
+ }
+ url {
+ type: ARCHIVE
+ value: "https://static.crates.io/crates/linkme/linkme-impl-0.3.9.crate"
+ }
+ version: "0.3.9"
+ # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2023
+ month: 5
+ day: 9
+ }
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..45dc4dd
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:master:/OWNERS
diff --git a/cargo2android.json b/cargo2android.json
new file mode 100644
index 0000000..3224ff7
--- /dev/null
+++ b/cargo2android.json
@@ -0,0 +1,6 @@
+{
+ "dependencies": true,
+ "device": true,
+ "run": true,
+ "test": true
+} \ No newline at end of file
diff --git a/src/args.rs b/src/args.rs
new file mode 100644
index 0000000..cdb2bfc
--- /dev/null
+++ b/src/args.rs
@@ -0,0 +1,27 @@
+use syn::parse::{Error, Parse, ParseStream, Result};
+use syn::{LitInt, Path, Token};
+
+pub enum Args {
+ None,
+ Path(Path),
+ PathPos(Path, usize),
+}
+
+impl Parse for Args {
+ fn parse(input: ParseStream) -> Result<Self> {
+ if input.is_empty() {
+ return Ok(Args::None);
+ }
+ let path: Path = input.parse()?;
+ if input.is_empty() {
+ return Ok(Args::Path(path));
+ }
+ input.parse::<Token![,]>()?;
+ let lit: LitInt = input.parse()?;
+ let pos: usize = lit.base10_parse()?;
+ if pos > 9999 {
+ return Err(Error::new(lit.span(), "maximum 9999 is supported"));
+ }
+ Ok(Args::PathPos(path, pos))
+ }
+}
diff --git a/src/attr.rs b/src/attr.rs
new file mode 100644
index 0000000..dca1511
--- /dev/null
+++ b/src/attr.rs
@@ -0,0 +1,37 @@
+use syn::parse::{Error, Result};
+use syn::{parse_quote, Attribute, Path};
+
+// #[linkme(crate = path::to::linkme)]
+pub(crate) fn linkme_path(attrs: &mut Vec<Attribute>) -> Result<Path> {
+ let mut linkme_path = None;
+ let mut errors: Option<Error> = None;
+
+ attrs.retain(|attr| {
+ if !attr.path().is_ident("linkme") {
+ return true;
+ }
+ if let Err(err) = attr.parse_nested_meta(|meta| {
+ if meta.path.is_ident("crate") {
+ if linkme_path.is_some() {
+ return Err(meta.error("duplicate linkme crate attribute"));
+ }
+ let path = meta.value()?.call(Path::parse_mod_style)?;
+ linkme_path = Some(path);
+ Ok(())
+ } else {
+ Err(meta.error("unsupported linkme attribute"))
+ }
+ }) {
+ match &mut errors {
+ None => errors = Some(err),
+ Some(errors) => errors.combine(err),
+ }
+ }
+ false
+ });
+
+ match errors {
+ None => Ok(linkme_path.unwrap_or_else(|| parse_quote!(::linkme))),
+ Some(errors) => Err(errors),
+ }
+}
diff --git a/src/declaration.rs b/src/declaration.rs
new file mode 100644
index 0000000..7543bad
--- /dev/null
+++ b/src/declaration.rs
@@ -0,0 +1,300 @@
+use crate::{attr, linker};
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use syn::parse::{Parse, ParseStream, Result};
+use syn::{
+ bracketed, Attribute, Error, GenericArgument, Ident, Lifetime, PathArguments, Token, Type,
+ Visibility,
+};
+
+struct Declaration {
+ attrs: Vec<Attribute>,
+ vis: Visibility,
+ ident: Ident,
+ ty: Type,
+}
+
+impl Parse for Declaration {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ input.parse::<Token![static]>()?;
+ let mut_token: Option<Token![mut]> = input.parse()?;
+ if let Some(mut_token) = mut_token {
+ return Err(Error::new_spanned(
+ mut_token,
+ "static mut is not supported by distributed_slice",
+ ));
+ }
+ let ident: Ident = input.parse()?;
+ input.parse::<Token![:]>()?;
+ let ty: Type = input.parse()?;
+ input.parse::<Token![=]>()?;
+
+ let content;
+ bracketed!(content in input);
+ content.parse::<Token![..]>()?;
+
+ input.parse::<Token![;]>()?;
+
+ Ok(Declaration {
+ attrs,
+ vis,
+ ident,
+ ty,
+ })
+ }
+}
+
+pub fn expand(input: TokenStream) -> TokenStream {
+ let msg = "distributed_slice is not implemented for this platform";
+ let error = Error::new_spanned(&input, msg);
+ let unsupported_platform = error.to_compile_error();
+
+ let decl: Declaration = match syn::parse2(input) {
+ Ok(decl) => decl,
+ Err(err) => return err.to_compile_error(),
+ };
+
+ let mut attrs = decl.attrs;
+ let vis = decl.vis;
+ let ident = decl.ident;
+ let mut ty = decl.ty;
+ let name = ident.to_string();
+
+ let linkme_path = match attr::linkme_path(&mut attrs) {
+ Ok(path) => path,
+ Err(err) => return err.to_compile_error(),
+ };
+
+ populate_static_lifetimes(&mut ty);
+
+ let used = if cfg!(feature = "used_linker") {
+ quote!(#[used(linker)])
+ } else {
+ quote!(#[used])
+ };
+
+ let linux_section = linker::linux::section(&ident);
+ let linux_section_start = linker::linux::section_start(&ident);
+ let linux_section_stop = linker::linux::section_stop(&ident);
+ let linux_dupcheck = linux_section.replacen("linkme", "linkm2", 1);
+ let linux_dupcheck_start = linux_section_start.replacen("linkme", "linkm2", 1);
+ let linux_dupcheck_stop = linux_section_stop.replacen("linkme", "linkm2", 1);
+
+ let macho_section = linker::macho::section(&ident);
+ let macho_section_start = linker::macho::section_start(&ident);
+ let macho_section_stop = linker::macho::section_stop(&ident);
+ let macho_dupcheck = macho_section.replacen("linkme", "linkm2", 1);
+ let macho_dupcheck_start = macho_section_start.replacen("linkme", "linkm2", 1);
+ let macho_dupcheck_stop = macho_section_stop.replacen("linkme", "linkm2", 1);
+
+ let windows_section = linker::windows::section(&ident);
+ let windows_section_start = linker::windows::section_start(&ident);
+ let windows_section_stop = linker::windows::section_stop(&ident);
+ let windows_dupcheck = windows_section.replacen("linkme", "linkm2", 1);
+ let windows_dupcheck_start = windows_section_start.replacen("linkme", "linkm2", 1);
+ let windows_dupcheck_stop = windows_section_stop.replacen("linkme", "linkm2", 1);
+
+ let illumos_section = linker::illumos::section(&ident);
+ let illumos_section_start = linker::illumos::section_start(&ident);
+ let illumos_section_stop = linker::illumos::section_stop(&ident);
+ let illumos_dupcheck = illumos_section.replacen("linkme", "linkm2", 1);
+ let illumos_dupcheck_start = illumos_section_start.replacen("linkme", "linkm2", 1);
+ let illumos_dupcheck_stop = illumos_section_stop.replacen("linkme", "linkm2", 1);
+
+ let freebsd_section = linker::freebsd::section(&ident);
+ let freebsd_section_start = linker::freebsd::section_start(&ident);
+ let freebsd_section_stop = linker::freebsd::section_stop(&ident);
+ let freebsd_dupcheck = freebsd_section.replacen("linkme", "linkm2", 1);
+ let freebsd_dupcheck_start = freebsd_section_start.replacen("linkme", "linkm2", 1);
+ let freebsd_dupcheck_stop = freebsd_section_stop.replacen("linkme", "linkm2", 1);
+
+ let call_site = Span::call_site();
+ let link_section_macro_str = format!("_linkme_macro_{}", ident);
+ let link_section_macro = Ident::new(&link_section_macro_str, call_site);
+
+ quote! {
+ #(#attrs)*
+ #vis static #ident: #linkme_path::DistributedSlice<#ty> = {
+ #[cfg(any(
+ target_os = "none",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "tvos",
+ target_os = "illumos",
+ target_os = "freebsd",
+ ))]
+ extern "Rust" {
+ #[cfg_attr(any(target_os = "none", target_os = "linux"), link_name = #linux_section_start)]
+ #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_section_start)]
+ #[cfg_attr(target_os = "illumos", link_name = #illumos_section_start)]
+ #[cfg_attr(target_os = "freebsd", link_name = #freebsd_section_start)]
+ static LINKME_START: <#ty as #linkme_path::__private::Slice>::Element;
+
+ #[cfg_attr(any(target_os = "none", target_os = "linux"), link_name = #linux_section_stop)]
+ #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_section_stop)]
+ #[cfg_attr(target_os = "illumos", link_name = #illumos_section_stop)]
+ #[cfg_attr(target_os = "freebsd", link_name = #freebsd_section_stop)]
+ static LINKME_STOP: <#ty as #linkme_path::__private::Slice>::Element;
+
+ #[cfg_attr(any(target_os = "none", target_os = "linux"), link_name = #linux_dupcheck_start)]
+ #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_dupcheck_start)]
+ #[cfg_attr(target_os = "illumos", link_name = #illumos_dupcheck_start)]
+ #[cfg_attr(target_os = "freebsd", link_name = #freebsd_dupcheck_start)]
+ static DUPCHECK_START: #linkme_path::__private::usize;
+
+ #[cfg_attr(any(target_os = "none", target_os = "linux"), link_name = #linux_dupcheck_stop)]
+ #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_dupcheck_stop)]
+ #[cfg_attr(target_os = "illumos", link_name = #illumos_dupcheck_stop)]
+ #[cfg_attr(target_os = "freebsd", link_name = #freebsd_dupcheck_stop)]
+ static DUPCHECK_STOP: #linkme_path::__private::usize;
+ }
+
+ #[cfg(target_os = "windows")]
+ #[link_section = #windows_section_start]
+ static LINKME_START: [<#ty as #linkme_path::__private::Slice>::Element; 0] = [];
+
+ #[cfg(target_os = "windows")]
+ #[link_section = #windows_section_stop]
+ static LINKME_STOP: [<#ty as #linkme_path::__private::Slice>::Element; 0] = [];
+
+ #[cfg(target_os = "windows")]
+ #[link_section = #windows_dupcheck_start]
+ static DUPCHECK_START: () = ();
+
+ #[cfg(target_os = "windows")]
+ #[link_section = #windows_dupcheck_stop]
+ static DUPCHECK_STOP: () = ();
+
+ #used
+ #[cfg(any(target_os = "none", target_os = "linux", target_os = "illumos", target_os = "freebsd"))]
+ #[cfg_attr(any(target_os = "none", target_os = "linux"), link_section = #linux_section)]
+ #[cfg_attr(target_os = "illumos", link_section = #illumos_section)]
+ #[cfg_attr(target_os = "freebsd", link_section = #freebsd_section)]
+ static mut LINKME_PLEASE: [<#ty as #linkme_path::__private::Slice>::Element; 0] = [];
+
+ #used
+ #[cfg_attr(any(target_os = "none", target_os = "linux"), link_section = #linux_dupcheck)]
+ #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_section = #macho_dupcheck)]
+ #[cfg_attr(target_os = "windows", link_section = #windows_dupcheck)]
+ #[cfg_attr(target_os = "illumos", link_section = #illumos_dupcheck)]
+ #[cfg_attr(target_os = "freebsd", link_section = #freebsd_dupcheck)]
+ static DUPCHECK: #linkme_path::__private::usize = 1;
+
+ #[cfg(not(any(
+ target_os = "none",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "tvos",
+ target_os = "windows",
+ target_os = "illumos",
+ target_os = "freebsd",
+ )))]
+ #unsupported_platform
+
+ #linkme_path::__private::assert!(
+ #linkme_path::__private::mem::size_of::<<#ty as #linkme_path::__private::Slice>::Element>() > 0,
+ );
+
+ unsafe {
+ #linkme_path::DistributedSlice::private_new(
+ #name,
+ &LINKME_START,
+ &LINKME_STOP,
+ &DUPCHECK_START,
+ &DUPCHECK_STOP,
+ )
+ }
+ };
+
+ #[doc(hidden)]
+ #[macro_export]
+ macro_rules! #link_section_macro {
+ (
+ #![linkme_macro = $macro:path]
+ #![linkme_sort_key = $key:tt]
+ $item:item
+ ) => {
+ $macro ! {
+ #![linkme_linux_section = concat!(#linux_section, $key)]
+ #![linkme_macho_section = concat!(#macho_section, $key)]
+ #![linkme_windows_section = concat!(#windows_section, $key)]
+ #![linkme_illumos_section = concat!(#illumos_section, $key)]
+ #![linkme_freebsd_section = concat!(#freebsd_section, $key)]
+ $item
+ }
+ };
+ (
+ #![linkme_linux_section = $linux_section:expr]
+ #![linkme_macho_section = $macho_section:expr]
+ #![linkme_windows_section = $windows_section:expr]
+ #![linkme_illumos_section = $illumos_section:expr]
+ #![linkme_freebsd_section = $freebsd_section:expr]
+ $item:item
+ ) => {
+ #used
+ #[cfg_attr(any(target_os = "none", target_os = "linux"), link_section = $linux_section)]
+ #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_section = $macho_section)]
+ #[cfg_attr(target_os = "windows", link_section = $windows_section)]
+ #[cfg_attr(target_os = "illumos", link_section = $illumos_section)]
+ #[cfg_attr(target_os = "freebsd", link_section = $freebsd_section)]
+ $item
+ };
+ ($item:item) => {
+ #used
+ #[cfg_attr(any(target_os = "none", target_os = "linux"), link_section = #linux_section)]
+ #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_section = #macho_section)]
+ #[cfg_attr(target_os = "windows", link_section = #windows_section)]
+ #[cfg_attr(target_os = "illumos", link_section = #illumos_section)]
+ #[cfg_attr(target_os = "freebsd", link_section = #freebsd_section)]
+ $item
+ };
+ }
+
+ #[doc(hidden)]
+ #vis use #link_section_macro as #ident;
+ }
+}
+
+fn populate_static_lifetimes(ty: &mut Type) {
+ match ty {
+ Type::Array(ty) => populate_static_lifetimes(&mut ty.elem),
+ Type::Group(ty) => populate_static_lifetimes(&mut ty.elem),
+ Type::Paren(ty) => populate_static_lifetimes(&mut ty.elem),
+ Type::Path(ty) => {
+ if let Some(qself) = &mut ty.qself {
+ populate_static_lifetimes(&mut qself.ty);
+ }
+ for segment in &mut ty.path.segments {
+ if let PathArguments::AngleBracketed(segment) = &mut segment.arguments {
+ for arg in &mut segment.args {
+ if let GenericArgument::Type(arg) = arg {
+ populate_static_lifetimes(arg);
+ }
+ }
+ }
+ }
+ }
+ Type::Ptr(ty) => populate_static_lifetimes(&mut ty.elem),
+ Type::Reference(ty) => {
+ if ty.lifetime.is_none() {
+ ty.lifetime = Some(Lifetime::new("'static", ty.and_token.span));
+ }
+ populate_static_lifetimes(&mut ty.elem);
+ }
+ Type::Slice(ty) => populate_static_lifetimes(&mut ty.elem),
+ Type::Tuple(ty) => ty.elems.iter_mut().for_each(populate_static_lifetimes),
+ Type::ImplTrait(_)
+ | Type::Infer(_)
+ | Type::Macro(_)
+ | Type::Never(_)
+ | Type::TraitObject(_)
+ | Type::BareFn(_)
+ | Type::Verbatim(_) => {}
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+ _ => unimplemented!("unknown Type"),
+ }
+}
diff --git a/src/element.rs b/src/element.rs
new file mode 100644
index 0000000..7c85e30
--- /dev/null
+++ b/src/element.rs
@@ -0,0 +1,241 @@
+use crate::attr;
+use proc_macro2::{Span, TokenStream, TokenTree};
+use quote::{format_ident, quote, quote_spanned};
+use std::iter::FromIterator;
+use syn::parse::{Error, Parse, ParseStream, Result};
+use syn::punctuated::Punctuated;
+use syn::{
+ braced, parenthesized, parse_quote, Abi, Attribute, BareFnArg, BoundLifetimes, GenericParam,
+ Generics, Ident, Path, ReturnType, Token, Type, TypeBareFn, Visibility, WhereClause,
+};
+
+pub struct Element {
+ attrs: Vec<Attribute>,
+ vis: Visibility,
+ ident: Ident,
+ ty: Type,
+ expr: TokenStream,
+ orig_item: Option<TokenStream>,
+ start_span: Span,
+ end_span: Span,
+}
+
+impl Parse for Element {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+ let item = input.cursor();
+ let vis: Visibility = input.parse()?;
+ let static_token: Option<Token![static]> = input.parse()?;
+ if static_token.is_some() {
+ let mut_token: Option<Token![mut]> = input.parse()?;
+ if let Some(mut_token) = mut_token {
+ return Err(Error::new_spanned(
+ mut_token,
+ "static mut is not supported by distributed_slice",
+ ));
+ }
+ let ident: Ident = input.parse()?;
+ input.parse::<Token![:]>()?;
+ let start_span = input.span();
+ let ty: Type = input.parse()?;
+ let end_span = quote!(#ty).into_iter().last().unwrap().span();
+ input.parse::<Token![=]>()?;
+ let mut expr_semi = Vec::from_iter(input.parse::<TokenStream>()?);
+ if let Some(tail) = expr_semi.pop() {
+ syn::parse2::<Token![;]>(TokenStream::from(tail))?;
+ }
+ let expr = TokenStream::from_iter(expr_semi);
+ Ok(Element {
+ attrs,
+ vis,
+ ident,
+ ty,
+ expr,
+ orig_item: None,
+ start_span,
+ end_span,
+ })
+ } else {
+ let constness: Option<Token![const]> = input.parse()?;
+ let asyncness: Option<Token![async]> = input.parse()?;
+ let unsafety: Option<Token![unsafe]> = input.parse()?;
+ let abi: Option<Abi> = input.parse()?;
+ let fn_token: Token![fn] = input.parse().map_err(|_| {
+ Error::new_spanned(
+ item.token_stream(),
+ "distributed element must be either static or function item",
+ )
+ })?;
+ let ident: Ident = input.parse()?;
+ let generics: Generics = input.parse()?;
+
+ let content;
+ let paren_token = parenthesized!(content in input);
+ let mut inputs = Punctuated::new();
+ while !content.is_empty() {
+ content.parse::<Option<Token![mut]>>()?;
+ let ident = if let Some(wild) = content.parse::<Option<Token![_]>>()? {
+ Ident::from(wild)
+ } else {
+ content.parse()?
+ };
+ let colon_token: Token![:] = content.parse()?;
+ let ty: Type = content.parse()?;
+ inputs.push_value(BareFnArg {
+ attrs: Vec::new(),
+ name: Some((ident, colon_token)),
+ ty,
+ });
+ if !content.is_empty() {
+ let comma: Token![,] = content.parse()?;
+ inputs.push_punct(comma);
+ }
+ }
+
+ let output: ReturnType = input.parse()?;
+ let where_clause: Option<WhereClause> = input.parse()?;
+
+ let content;
+ braced!(content in input);
+ content.parse::<TokenStream>()?;
+
+ if let Some(constness) = constness {
+ return Err(Error::new_spanned(
+ constness,
+ "const fn distributed slice element is not supported",
+ ));
+ }
+
+ if let Some(asyncness) = asyncness {
+ return Err(Error::new_spanned(
+ asyncness,
+ "async fn distributed slice element is not supported",
+ ));
+ }
+
+ let lifetimes = if generics.params.is_empty() {
+ None
+ } else {
+ let mut bound = BoundLifetimes {
+ for_token: Token![for](generics.lt_token.unwrap().span),
+ lt_token: generics.lt_token.unwrap(),
+ lifetimes: Punctuated::new(),
+ gt_token: generics.gt_token.unwrap(),
+ };
+ for param in generics.params.into_pairs() {
+ let (param, punct) = param.into_tuple();
+ if let GenericParam::Lifetime(_) = param {
+ bound.lifetimes.push_value(param);
+ if let Some(punct) = punct {
+ bound.lifetimes.push_punct(punct);
+ }
+ } else {
+ return Err(Error::new_spanned(
+ param,
+ "cannot have generic parameters on distributed slice element",
+ ));
+ }
+ }
+ Some(bound)
+ };
+
+ if let Some(where_clause) = where_clause {
+ return Err(Error::new_spanned(
+ where_clause,
+ "where-clause is not allowed on distributed slice elements",
+ ));
+ }
+
+ let start_span = item.span();
+ let end_span = quote!(#output)
+ .into_iter()
+ .last()
+ .as_ref()
+ .map_or(paren_token.span.close(), TokenTree::span);
+ let mut original_attrs = attrs;
+ let linkme_path = attr::linkme_path(&mut original_attrs)?;
+
+ let attrs = vec![
+ parse_quote! {
+ #[allow(non_upper_case_globals)]
+ },
+ parse_quote! {
+ #[linkme(crate = #linkme_path)]
+ },
+ ];
+ let vis = Visibility::Inherited;
+ let expr = parse_quote!(#ident);
+ let ty = Type::BareFn(TypeBareFn {
+ lifetimes,
+ unsafety,
+ abi,
+ fn_token,
+ paren_token,
+ inputs,
+ variadic: None,
+ output,
+ });
+ let ident = format_ident!("_LINKME_ELEMENT_{}", ident);
+ let item = item.token_stream();
+ let orig_item = Some(quote!(
+ #(#original_attrs)*
+ #item
+ ));
+
+ Ok(Element {
+ attrs,
+ vis,
+ ident,
+ ty,
+ expr,
+ orig_item,
+ start_span,
+ end_span,
+ })
+ }
+ }
+}
+
+pub fn expand(path: Path, pos: impl Into<Option<usize>>, input: Element) -> TokenStream {
+ let pos = pos.into();
+ do_expand(path, pos, input)
+}
+
+fn do_expand(path: Path, pos: Option<usize>, input: Element) -> TokenStream {
+ let mut attrs = input.attrs;
+ let vis = input.vis;
+ let ident = input.ident;
+ let ty = input.ty;
+ let expr = input.expr;
+ let orig_item = input.orig_item;
+
+ let linkme_path = match attr::linkme_path(&mut attrs) {
+ Ok(path) => path,
+ Err(err) => return err.to_compile_error(),
+ };
+
+ let sort_key = pos.into_iter().map(|pos| format!("{:04}", pos));
+
+ let new = quote_spanned!(input.start_span=> __new);
+ let uninit = quote_spanned!(input.end_span=> #new());
+
+ quote! {
+ #path ! {
+ #(
+ #![linkme_macro = #path]
+ #![linkme_sort_key = #sort_key]
+ )*
+ #(#attrs)*
+ #vis static #ident : #ty = {
+ unsafe fn __typecheck(_: #linkme_path::__private::Void) {
+ let #new = #linkme_path::__private::value::<#ty>;
+ #linkme_path::DistributedSlice::private_typecheck(#path, #uninit)
+ }
+
+ #expr
+ };
+ }
+
+ #orig_item
+ }
+}
diff --git a/src/hash.rs b/src/hash.rs
new file mode 100644
index 0000000..b8e5aea
--- /dev/null
+++ b/src/hash.rs
@@ -0,0 +1,42 @@
+use std::collections::hash_map;
+use std::fmt::{self, Display, Write};
+use std::hash::{Hash, Hasher};
+use syn::Ident;
+
+// 8-character symbol hash consisting of a-zA-Z0-9. We use 8 character because
+// Mach-O section specifiers are restricted to at most 16 characters (see
+// https://github.com/dtolnay/linkme/issues/35) and we leave room for a
+// linkme-specific prefix.
+pub(crate) struct Symbol(u64);
+
+pub(crate) fn hash(ident: &Ident) -> Symbol {
+ let mut hasher = hash_map::DefaultHasher::new();
+ ident.hash(&mut hasher);
+ Symbol(hasher.finish())
+}
+
+impl Display for Symbol {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ // log(62^8)/log(2) is 47.6 so we have enough bits in the 64-bit
+ // standard library hash to produce a good distribution over 8 digits
+ // from a 62-character alphabet.
+ let mut remainder = self.0;
+ for _ in 0..8 {
+ let digit = (remainder % 62) as u8;
+ remainder /= 62;
+ formatter.write_char(match digit {
+ 0..=25 => b'a' + digit,
+ 26..=51 => b'A' + digit - 26,
+ 52..=61 => b'0' + digit - 52,
+ _ => unreachable!(),
+ } as char)?;
+ }
+ Ok(())
+ }
+}
+
+#[test]
+fn test_hash() {
+ let ident = Ident::new("EXAMPLE", proc_macro2::Span::call_site());
+ assert_eq!(hash(&ident).to_string(), "0GPSzIoo");
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..d08aba8
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,32 @@
+#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
+#![allow(
+ clippy::cast_possible_truncation, // https://github.com/rust-lang/rust-clippy/issues/7486
+ clippy::needless_pass_by_value,
+ clippy::too_many_lines,
+ clippy::uninlined_format_args,
+)]
+
+mod args;
+mod attr;
+mod declaration;
+mod element;
+mod hash;
+mod linker;
+
+use crate::args::Args;
+use crate::hash::hash;
+use proc_macro::TokenStream;
+use syn::parse_macro_input;
+
+#[proc_macro_attribute]
+pub fn distributed_slice(args: TokenStream, input: TokenStream) -> TokenStream {
+ let args = parse_macro_input!(args as Args);
+
+ let expanded = match args {
+ Args::None => declaration::expand(parse_macro_input!(input)),
+ Args::Path(path) => element::expand(path, None, parse_macro_input!(input)),
+ Args::PathPos(path, pos) => element::expand(path, pos, parse_macro_input!(input)),
+ };
+
+ TokenStream::from(expanded)
+}
diff --git a/src/linker.rs b/src/linker.rs
new file mode 100644
index 0000000..75affe2
--- /dev/null
+++ b/src/linker.rs
@@ -0,0 +1,82 @@
+pub mod linux {
+ use syn::Ident;
+
+ pub fn section(ident: &Ident) -> String {
+ format!("linkme_{}", ident)
+ }
+
+ pub fn section_start(ident: &Ident) -> String {
+ format!("__start_linkme_{}", ident)
+ }
+
+ pub fn section_stop(ident: &Ident) -> String {
+ format!("__stop_linkme_{}", ident)
+ }
+}
+
+pub mod freebsd {
+ use syn::Ident;
+
+ pub fn section(ident: &Ident) -> String {
+ format!("linkme_{}", ident)
+ }
+
+ pub fn section_start(ident: &Ident) -> String {
+ format!("__start_linkme_{}", ident)
+ }
+
+ pub fn section_stop(ident: &Ident) -> String {
+ format!("__stop_linkme_{}", ident)
+ }
+}
+
+pub mod macho {
+ use syn::Ident;
+
+ pub fn section(ident: &Ident) -> String {
+ format!(
+ "__DATA,__linkme{},regular,no_dead_strip",
+ crate::hash(ident),
+ )
+ }
+
+ pub fn section_start(ident: &Ident) -> String {
+ format!("\x01section$start$__DATA$__linkme{}", crate::hash(ident))
+ }
+
+ pub fn section_stop(ident: &Ident) -> String {
+ format!("\x01section$end$__DATA$__linkme{}", crate::hash(ident))
+ }
+}
+
+pub mod windows {
+ use syn::Ident;
+
+ pub fn section(ident: &Ident) -> String {
+ format!(".linkme_{}$b", ident)
+ }
+
+ pub fn section_start(ident: &Ident) -> String {
+ format!(".linkme_{}$a", ident)
+ }
+
+ pub fn section_stop(ident: &Ident) -> String {
+ format!(".linkme_{}$c", ident)
+ }
+}
+
+pub mod illumos {
+ use syn::Ident;
+
+ pub fn section(ident: &Ident) -> String {
+ format!("set_linkme_{}", ident)
+ }
+
+ pub fn section_start(ident: &Ident) -> String {
+ format!("__start_set_linkme_{}", ident)
+ }
+
+ pub fn section_stop(ident: &Ident) -> String {
+ format!("__stop_set_linkme_{}", ident)
+ }
+}