summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaurice Lam <yukl@google.com>2023-03-02 22:57:26 +0000
committerMaurice Lam <yukl@google.com>2023-03-03 00:49:35 +0000
commit23c1e5ff66c23e3872877ab8cf257fe22e8f68f1 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904
parentf5e22e2d97082f303a07f1a282d031561bfed6b4 (diff)
downloadouroboros_macro-23c1e5ff66c23e3872877ab8cf257fe22e8f68f1.tar.gz
Revert "Import ouroboros_macro crate"
Revert submission 2428041-ouroboros-import Reason for revert: b/271004059 Reverted changes: /q/submissionid:2428041-ouroboros-import Change-Id: I3179f731e00e2f93fcc9114b85d6bb760f9e8f3e
-rw-r--r--.cargo_vcs_info.json6
-rw-r--r--Cargo.toml43
-rw-r--r--Cargo.toml.orig22
l---------LICENSE1
-rw-r--r--LICENSE_APACHE202
-rw-r--r--LICENSE_MIT22
-rw-r--r--METADATA19
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--OWNERS1
-rw-r--r--src/covariance_detection.rs142
-rw-r--r--src/generate/constructor.rs202
-rw-r--r--src/generate/derives.rs98
-rw-r--r--src/generate/into_heads.rs81
-rw-r--r--src/generate/mod.rs9
-rw-r--r--src/generate/struc.rs50
-rw-r--r--src/generate/summon_checker.rs62
-rw-r--r--src/generate/try_constructor.rs301
-rw-r--r--src/generate/type_asserts.rs41
-rw-r--r--src/generate/with_all.rs134
-rw-r--r--src/generate/with_each.rs132
-rw-r--r--src/info_structures.rs304
-rw-r--r--src/lib.rs165
-rw-r--r--src/parse.rs271
-rw-r--r--src/utils.rs140
24 files changed, 0 insertions, 2448 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
deleted file mode 100644
index e454f04..0000000
--- a/.cargo_vcs_info.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "git": {
- "sha1": "79bac55f29edbb44f7205246ab5c3f706cbc4647"
- },
- "path_in_vcs": "ouroboros_macro"
-} \ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
deleted file mode 100644
index 52734ba..0000000
--- a/Cargo.toml
+++ /dev/null
@@ -1,43 +0,0 @@
-# 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 = "2018"
-name = "ouroboros_macro"
-version = "0.15.5"
-authors = ["Joshua Maros <joshua-maros@github.com>"]
-description = "Proc macro for ouroboros crate."
-documentation = "https://docs.rs/ouroboros_macro"
-license = "MIT OR Apache-2.0"
-repository = "https://github.com/joshua-maros/ouroboros"
-
-[lib]
-proc-macro = true
-
-[dependencies.Inflector]
-version = "0.11"
-default-features = false
-
-[dependencies.proc-macro-error]
-version = "1.0.4"
-
-[dependencies.proc-macro2]
-version = "1.0"
-
-[dependencies.quote]
-version = "1.0"
-
-[dependencies.syn]
-version = "1.0"
-features = ["full"]
-
-[features]
-std = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
deleted file mode 100644
index 2db8277..0000000
--- a/Cargo.toml.orig
+++ /dev/null
@@ -1,22 +0,0 @@
-[package]
-name = "ouroboros_macro"
-version = "0.15.5"
-authors = ["Joshua Maros <joshua-maros@github.com>"]
-edition = "2018"
-license = "MIT OR Apache-2.0"
-description = "Proc macro for ouroboros crate."
-documentation = "https://docs.rs/ouroboros_macro"
-repository = "https://github.com/joshua-maros/ouroboros"
-
-[lib]
-proc-macro = true
-
-[dependencies]
-Inflector = { version = "0.11", default-features = false }
-proc-macro2 = "1.0"
-proc-macro-error = "1.0.4"
-quote = "1.0"
-syn = { version = "1.0", features = ["full"] }
-
-[features]
-std = []
diff --git a/LICENSE b/LICENSE
deleted file mode 120000
index 6d46dcc..0000000
--- a/LICENSE
+++ /dev/null
@@ -1 +0,0 @@
-LICENSE_MIT \ No newline at end of file
diff --git a/LICENSE_APACHE b/LICENSE_APACHE
deleted file mode 100644
index 574cb18..0000000
--- a/LICENSE_APACHE
+++ /dev/null
@@ -1,202 +0,0 @@
- 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
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright 2021 Joshua Maros
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
diff --git a/LICENSE_MIT b/LICENSE_MIT
deleted file mode 100644
index 9ed5b2a..0000000
--- a/LICENSE_MIT
+++ /dev/null
@@ -1,22 +0,0 @@
-MIT License
-
-Copyright (c) 2021 Joshua Maros
-
-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
deleted file mode 100644
index bdc87ab..0000000
--- a/METADATA
+++ /dev/null
@@ -1,19 +0,0 @@
-name: "ouroboros_macro"
-description: "Proc macro for ouroboros crate."
-third_party {
- url {
- type: HOMEPAGE
- value: "https://crates.io/crates/ouroboros_macro"
- }
- url {
- type: ARCHIVE
- value: "https://static.crates.io/crates/ouroboros_macro/ouroboros_macro-0.15.5.crate"
- }
- version: "0.15.5"
- license_type: NOTICE
- last_upgrade_date {
- year: 2023
- month: 2
- day: 10
- }
-}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/OWNERS b/OWNERS
deleted file mode 100644
index 45dc4dd..0000000
--- a/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include platform/prebuilts/rust:master:/OWNERS
diff --git a/src/covariance_detection.rs b/src/covariance_detection.rs
deleted file mode 100644
index 2f50983..0000000
--- a/src/covariance_detection.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-use quote::ToTokens;
-use syn::{GenericArgument, PathArguments, Type};
-
-use crate::utils::uses_this_lifetime;
-
-const STD_CONTAINER_TYPES: &[&str] = &["Box", "Arc", "Rc"];
-
-/// Returns Some((type_name, element_type)) if the provided type appears to be Box, Arc, or Rc from
-/// the standard library. Returns None if not.
-pub fn apparent_std_container_type(raw_type: &Type) -> Option<(&'static str, &Type)> {
- let tpath = if let Type::Path(x) = raw_type {
- x
- } else {
- return None;
- };
- let segment = if let Some(segment) = tpath.path.segments.last() {
- segment
- } else {
- return None;
- };
- let args = if let PathArguments::AngleBracketed(args) = &segment.arguments {
- args
- } else {
- return None;
- };
- if args.args.len() != 1 {
- return None;
- }
- let arg = args.args.first().unwrap();
- let eltype = if let GenericArgument::Type(x) = arg {
- x
- } else {
- return None;
- };
- for type_name in STD_CONTAINER_TYPES {
- if segment.ident == type_name {
- return Some((type_name, eltype));
- }
- }
- None
-}
-
-/// Returns Some(true or false) if the type is known to be covariant / not covariant.
-pub fn type_is_covariant_over_this_lifetime(ty: &syn::Type) -> Option<bool> {
- use syn::Type::*;
- // If the type never uses the 'this lifetime, we don't have to
- // worry about it not being covariant.
- if !uses_this_lifetime(ty.to_token_stream()) {
- return Some(true);
- }
- match ty {
- Array(arr) => type_is_covariant_over_this_lifetime(&*arr.elem),
- BareFn(f) => {
- debug_assert!(uses_this_lifetime(f.to_token_stream()));
- None
- }
- Group(ty) => type_is_covariant_over_this_lifetime(&ty.elem),
- ImplTrait(..) => None, // Unusable in struct definition.
- Infer(..) => None, // Unusable in struct definition.
- Macro(..) => None, // We don't know what the macro will resolve to.
- Never(..) => None,
- Paren(ty) => type_is_covariant_over_this_lifetime(&ty.elem),
- Path(path) => {
- if let Some(qself) = &path.qself {
- if !type_is_covariant_over_this_lifetime(&qself.ty)? {
- return Some(false);
- }
- }
- let mut all_parameters_are_covariant = false;
- // If the type is Box, Arc, or Rc, we can assume it to be covariant.
- if apparent_std_container_type(ty).is_some() {
- all_parameters_are_covariant = true;
- }
- for segment in path.path.segments.iter() {
- let args = &segment.arguments;
- if let syn::PathArguments::AngleBracketed(args) = &args {
- for arg in args.args.iter() {
- if let syn::GenericArgument::Type(ty) = arg {
- if all_parameters_are_covariant {
- if !type_is_covariant_over_this_lifetime(ty)? {
- return Some(false);
- }
- } else {
- if uses_this_lifetime(ty.to_token_stream()) {
- return None;
- }
- }
- } else if let syn::GenericArgument::Lifetime(lt) = arg {
- if lt.ident.to_string() == "this" && !all_parameters_are_covariant {
- return None;
- }
- }
- }
- } else if let syn::PathArguments::Parenthesized(args) = &args {
- for arg in args.inputs.iter() {
- if uses_this_lifetime(arg.to_token_stream()) {
- return None;
- }
- }
- if let syn::ReturnType::Type(_, ty) = &args.output {
- if uses_this_lifetime(ty.to_token_stream()) {
- return None;
- }
- }
- }
- }
- Some(true)
- }
- Ptr(ptr) => {
- if ptr.mutability.is_some() {
- Some(false)
- } else {
- type_is_covariant_over_this_lifetime(&ptr.elem)
- }
- }
- // Ignore the actual lifetime of the reference because Rust can automatically convert those.
- Reference(rf) => {
- if rf.mutability.is_some() {
- Some(!uses_this_lifetime(rf.elem.to_token_stream()))
- } else {
- type_is_covariant_over_this_lifetime(&rf.elem)
- }
- }
- Slice(sl) => type_is_covariant_over_this_lifetime(&sl.elem),
- TraitObject(..) => None,
- Tuple(tup) => {
- let mut result = Some(true);
- for ty in tup.elems.iter() {
- match type_is_covariant_over_this_lifetime(ty) {
- Some(true) => (),
- Some(false) => return Some(false),
- None => result = None,
- }
- }
- result
- }
- // As of writing this, syn parses all the types we could need. However,
- // just to be safe, return that we don't know if it's covariant.
- Verbatim(..) => None,
- _ => None,
- }
-}
diff --git a/src/generate/constructor.rs b/src/generate/constructor.rs
deleted file mode 100644
index 6ab47bc..0000000
--- a/src/generate/constructor.rs
+++ /dev/null
@@ -1,202 +0,0 @@
-use crate::{
- info_structures::{ArgType, BuilderType, FieldType, Options, StructInfo},
- utils::to_class_case,
-};
-use proc_macro2::{Ident, TokenStream};
-use quote::{format_ident, quote};
-use syn::Error;
-
-pub fn create_builder_and_constructor(
- info: &StructInfo,
- options: Options,
- builder_type: BuilderType,
-) -> Result<(Ident, TokenStream, TokenStream), Error> {
- let struct_name = info.ident.clone();
- let generic_args = info.generic_arguments();
-
- let vis = if options.do_pub_extras {
- info.vis.clone()
- } else {
- syn::parse_quote! { pub(super) }
- };
- let builder_struct_name = match builder_type {
- BuilderType::AsyncSend => format_ident!("{}AsyncSendBuilder", info.ident),
- BuilderType::Async => format_ident!("{}AsyncBuilder", info.ident),
- BuilderType::Sync => format_ident!("{}Builder", info.ident),
- };
- let documentation = format!(
- concat!(
- "Constructs a new instance of this self-referential struct. (See also ",
- "[`{0}::build()`]({0}::build)). Each argument is a field of ",
- "the new struct. Fields that refer to other fields inside the struct are initialized ",
- "using functions instead of directly passing their value. The arguments are as ",
- "follows:\n\n| Argument | Suggested Use |\n| --- | --- |\n",
- ),
- builder_struct_name.to_string()
- );
- let builder_documentation = concat!(
- "A more verbose but stable way to construct self-referencing structs. It is ",
- "comparable to using `StructName { field1: value1, field2: value2 }` rather than ",
- "`StructName::new(value1, value2)`. This has the dual benefit of making your code ",
- "both easier to refactor and more readable. Call [`build()`](Self::build) to ",
- "construct the actual struct. The fields of this struct should be used as follows:\n\n",
- "| Field | Suggested Use |\n| --- | --- |\n",
- )
- .to_owned();
- let build_fn_documentation = format!(
- concat!(
- "Calls [`{0}::new()`]({0}::new) using the provided values. This is preferrable over ",
- "calling `new()` directly for the reasons listed above. "
- ),
- info.ident.to_string()
- );
- let mut doc_table = "".to_owned();
- let mut code: Vec<TokenStream> = Vec::new();
- let mut params: Vec<TokenStream> = Vec::new();
- let mut builder_struct_generic_producers: Vec<_> = info
- .generic_params()
- .iter()
- .map(|param| quote! { #param })
- .collect();
- let mut builder_struct_generic_consumers = info.generic_arguments();
- let mut builder_struct_fields = Vec::new();
- let mut builder_struct_field_names = Vec::new();
-
- // code.push(quote! { let mut result = ::core::mem::MaybeUninit::<Self>::uninit(); });
-
- for field in &info.fields {
- let field_name = &field.name;
-
- let arg_type = field.make_constructor_arg_type(&info, builder_type)?;
- if let ArgType::Plain(plain_type) = arg_type {
- // No fancy builder function, we can just move the value directly into the struct.
- params.push(quote! { #field_name: #plain_type });
- builder_struct_fields.push(quote! { #field_name: #plain_type });
- builder_struct_field_names.push(quote! { #field_name });
- doc_table += &format!(
- "| `{}` | Directly pass in the value this field should contain |\n",
- field_name.to_string()
- );
- } else if let ArgType::TraitBound(bound_type) = arg_type {
- // Trait bounds are much trickier. We need a special syntax to accept them in the
- // contructor, and generic parameters need to be added to the builder struct to make
- // it work.
- let builder_name = field.builder_name();
- params.push(quote! { #builder_name : impl #bound_type });
- doc_table += &format!(
- "| `{}` | Use a function or closure: `(",
- builder_name.to_string()
- );
- let mut builder_args = Vec::new();
- for (index, borrow) in field.borrows.iter().enumerate() {
- let borrowed_name = &info.fields[borrow.index].name;
- builder_args.push(format_ident!("{}_illegal_static_reference", borrowed_name));
- doc_table += &format!(
- "{}: &{}_",
- borrowed_name.to_string(),
- if borrow.mutable { "mut " } else { "" },
- );
- if index < field.borrows.len() - 1 {
- doc_table += ", ";
- }
- }
- doc_table += &format!(") -> {}: _` | \n", field_name.to_string());
- if builder_type.is_async() {
- code.push(quote! { let #field_name = #builder_name (#(#builder_args),*).await; });
- } else {
- code.push(quote! { let #field_name = #builder_name (#(#builder_args),*); });
- }
- let generic_type_name =
- format_ident!("{}Builder_", to_class_case(field_name.to_string().as_str()));
-
- builder_struct_generic_producers.push(quote! { #generic_type_name: #bound_type });
- builder_struct_generic_consumers.push(quote! { #generic_type_name });
- builder_struct_fields.push(quote! { #builder_name: #generic_type_name });
- builder_struct_field_names.push(quote! { #builder_name });
- }
- if field.is_borrowed() {
- let boxed = field.boxed();
- if field.field_type == FieldType::BorrowedMut {
- code.push(quote! { let mut #field_name = #boxed; });
- } else {
- code.push(quote! { let #field_name = #boxed; });
- }
- };
-
- if field.field_type == FieldType::Borrowed {
- code.push(field.make_illegal_static_reference());
- } else if field.field_type == FieldType::BorrowedMut {
- code.push(field.make_illegal_static_mut_reference());
- }
- }
-
- let documentation = if !options.do_no_doc {
- let documentation = documentation + &doc_table;
- quote! {
- #[doc=#documentation]
- }
- } else {
- quote! { #[doc(hidden)] }
- };
-
- let builder_documentation = if !options.do_no_doc {
- let builder_documentation = builder_documentation + &doc_table;
- quote! {
- #[doc=#builder_documentation]
- }
- } else {
- quote! { #[doc(hidden)] }
- };
-
- let constructor_fn = match builder_type {
- BuilderType::AsyncSend => quote! { async fn new_async_send },
- BuilderType::Async => quote! { async fn new_async },
- BuilderType::Sync => quote! { fn new },
- };
- let field_names: Vec<_> = info.fields.iter().map(|field| field.name.clone()).collect();
- let constructor_def = quote! {
- #documentation
- #vis #constructor_fn(#(#params),*) -> #struct_name <#(#generic_args),*> {
- #(#code)*
- Self {
- #(#field_names),*
- }
- }
- };
- let generic_where = &info.generics.where_clause;
- let builder_fn = if builder_type.is_async() {
- quote! { async fn build }
- } else {
- quote! { fn build }
- };
- let builder_code = match builder_type {
- BuilderType::AsyncSend => quote! {
- #struct_name::new_async_send(
- #(self.#builder_struct_field_names),*
- ).await
- },
- BuilderType::Async => quote! {
- #struct_name::new_async(
- #(self.#builder_struct_field_names),*
- ).await
- },
- BuilderType::Sync => quote! {
- #struct_name::new(
- #(self.#builder_struct_field_names),*
- )
- },
- };
- let builder_def = quote! {
- #builder_documentation
- #vis struct #builder_struct_name <#(#builder_struct_generic_producers),*> #generic_where {
- #(#vis #builder_struct_fields),*
- }
- impl<#(#builder_struct_generic_producers),*> #builder_struct_name <#(#builder_struct_generic_consumers),*> #generic_where {
- #[doc=#build_fn_documentation]
- #vis #builder_fn(self) -> #struct_name <#(#generic_args),*> {
- #builder_code
- }
- }
- };
- Ok((builder_struct_name, builder_def, constructor_def))
-}
diff --git a/src/generate/derives.rs b/src/generate/derives.rs
deleted file mode 100644
index 0233a3f..0000000
--- a/src/generate/derives.rs
+++ /dev/null
@@ -1,98 +0,0 @@
-use crate::info_structures::{Derive, StructInfo};
-use proc_macro2::TokenStream;
-use quote::quote;
-use syn::{Error, GenericParam, TypeParamBound};
-
-fn add_trait_bound(param: &GenericParam, bound: &TypeParamBound) -> GenericParam {
- let mut new = param.clone();
- match &mut new {
- GenericParam::Type(t) => t.bounds.push(bound.clone()),
- _ => (),
- }
- new
-}
-
-fn impl_trait(info: &StructInfo, trait_name: TypeParamBound, body: TokenStream) -> TokenStream {
- let generic_params = info.generic_params();
- let generic_params = generic_params
- .into_iter()
- .map(|i| add_trait_bound(i, &trait_name))
- .collect::<Vec<_>>();
- let generic_args = info.generic_arguments();
- let generic_where = &info.generics.where_clause;
- let struct_name = &info.ident;
- quote! {
- impl <#(#generic_params),*> #trait_name for #struct_name <#(#generic_args),*> #generic_where {
- #body
- }
- }
-}
-
-fn impl_debug(info: &StructInfo) -> Result<TokenStream, Error> {
- let fields = info
- .fields
- .iter()
- .filter(|field| !field.is_mutably_borrowed())
- .map(|field| {
- let name = &field.name;
- quote! {
- field(stringify!(#name), &safe_self.#name)
- }
- })
- .collect::<Vec<_>>();
- let trait_name = syn::parse_quote! { ::core::fmt::Debug };
- let struct_name = &info.ident;
- let body = quote! {
- fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
- self.with(|safe_self| {
- f.debug_struct(stringify!(#struct_name))
- #(.#fields)*
- .finish()
- })
- }
- };
- Ok(impl_trait(info, trait_name, body))
-}
-
-fn impl_partial_eq(info: &StructInfo) -> Result<TokenStream, Error> {
- let fields = info
- .fields
- .iter()
- .filter(|field| !field.is_mutably_borrowed())
- .map(|field| {
- let name = &field.name;
- quote! {
- &*safe_self.#name == &*safe_other.#name
- }
- })
- .collect::<Vec<_>>();
- let trait_name = syn::parse_quote! { ::core::cmp::PartialEq };
- let body = quote! {
- fn eq(&self, other: &Self) -> bool {
- self.with(|safe_self| {
- other.with(|safe_other| {
- #(#fields)&&*
- })
- })
- }
- };
- Ok(impl_trait(info, trait_name, body))
-}
-
-fn impl_eq(info: &StructInfo) -> Result<TokenStream, Error> {
- let trait_name = syn::parse_quote! { ::core::cmp::Eq };
- let body = quote! {};
- Ok(impl_trait(info, trait_name, body))
-}
-
-pub fn create_derives(info: &StructInfo) -> Result<TokenStream, Error> {
- let mut impls = Vec::new();
- for derive in &info.derives {
- match derive {
- Derive::Debug => impls.push(impl_debug(info)?),
- Derive::PartialEq => impls.push(impl_partial_eq(info)?),
- Derive::Eq => impls.push(impl_eq(info)?),
- }
- }
- Ok(quote! { #(#impls)* })
-}
diff --git a/src/generate/into_heads.rs b/src/generate/into_heads.rs
deleted file mode 100644
index 5784e46..0000000
--- a/src/generate/into_heads.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-use proc_macro2::TokenStream;
-use quote::quote;
-
-use crate::info_structures::{Options, StructInfo};
-
-/// Returns the Heads struct and a function to convert the original struct into a Heads instance.
-pub fn make_into_heads(info: &StructInfo, options: Options) -> (TokenStream, TokenStream) {
- let visibility = if options.do_pub_extras {
- info.vis.clone()
- } else {
- syn::parse_quote! { pub(super) }
- };
- let mut code = Vec::new();
- let mut field_initializers = Vec::new();
- let mut head_fields = Vec::new();
- // Drop everything in the reverse order of what it was declared in. Fields that come later
- // are only dependent on fields that came before them.
- for field in info.fields.iter().rev() {
- let field_name = &field.name;
- if !field.self_referencing {
- code.push(quote! { let #field_name = self.#field_name; });
- if field.is_borrowed() {
- field_initializers
- .push(quote! { #field_name: ::ouroboros::macro_help::unbox(#field_name) });
- } else {
- field_initializers.push(quote! { #field_name });
- }
- let field_type = &field.typ;
- head_fields.push(quote! { #visibility #field_name: #field_type });
- } else {
- // Heads are fields that do not borrow anything.
- code.push(quote! { ::core::mem::drop(self.#field_name); });
- }
- }
- for (ty, ident) in info.generic_consumers() {
- head_fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> });
- field_initializers.push(quote! { #ident: ::core::marker::PhantomData });
- }
- let documentation = format!(
- concat!(
- "A struct which contains only the ",
- "[head fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) of [`{0}`]({0})."
- ),
- info.ident.to_string()
- );
- let generic_params = info.generic_params();
- let generic_where = &info.generics.where_clause;
- let heads_struct_def = quote! {
- #[doc=#documentation]
- #visibility struct Heads <#generic_params> #generic_where {
- #(#head_fields),*
- }
- };
- let documentation = concat!(
- "This function drops all internally referencing fields and returns only the ",
- "[head fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) of this struct."
- ).to_owned();
-
- let documentation = if !options.do_no_doc {
- quote! {
- #[doc=#documentation]
- }
- } else {
- quote! { #[doc(hidden)] }
- };
-
- let generic_args = info.generic_arguments();
- let into_heads_fn = quote! {
- #documentation
- #[allow(clippy::drop_ref)]
- #[allow(clippy::drop_copy)]
- #[allow(clippy::drop_non_drop)]
- #visibility fn into_heads(self) -> Heads<#(#generic_args),*> {
- #(#code)*
- Heads {
- #(#field_initializers),*
- }
- }
- };
- (heads_struct_def, into_heads_fn)
-}
diff --git a/src/generate/mod.rs b/src/generate/mod.rs
deleted file mode 100644
index 0b229d1..0000000
--- a/src/generate/mod.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod constructor;
-pub mod derives;
-pub mod into_heads;
-pub mod struc;
-pub mod summon_checker;
-pub mod try_constructor;
-pub mod type_asserts;
-pub mod with_all;
-pub mod with_each;
diff --git a/src/generate/struc.rs b/src/generate/struc.rs
deleted file mode 100644
index 9b2ff51..0000000
--- a/src/generate/struc.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use crate::{
- info_structures::StructInfo,
- utils::{self, replace_this_with_lifetime},
-};
-use proc_macro2::TokenStream;
-use quote::quote;
-use syn::Error;
-
-/// Creates the struct that will actually store the data. This involves properly organizing the
-/// fields, collecting metadata about them, reversing the order everything is stored in, and
-/// converting any uses of 'this to 'static.
-pub fn create_actual_struct_def(info: &StructInfo) -> Result<TokenStream, Error> {
- let vis = utils::submodule_contents_visiblity(&info.vis);
- let ident = &info.ident;
- let generics = &info.generics;
-
- let field_defs: Vec<_> = info
- .fields
- .iter()
- // Reverse the order of all fields. We ensure that items in the struct are only dependent
- // on references to items above them. Rust drops items in a struct in forward declaration order.
- // This would cause parents being dropped before children, necessitating the reversal.
- .rev()
- .map(|field| {
- let name = &field.name;
- let ty = field.stored_type();
- quote! {
- #[doc(hidden)]
- #name: #ty
- }
- })
- .collect();
-
- // Create the new struct definition.
- let mut where_clause = quote! {};
- if let Some(clause) = &generics.where_clause {
- where_clause = quote! { #clause };
- }
- let def = quote! {
- #vis struct #ident #generics #where_clause {
- #(#field_defs),*
- }
- };
-
- // Finally, replace the fake 'this lifetime with the one we found.
- let fake_lifetime = info.fake_lifetime();
- let def = replace_this_with_lifetime(quote! { #def }, fake_lifetime.clone());
-
- Ok(def)
-}
diff --git a/src/generate/summon_checker.rs b/src/generate/summon_checker.rs
deleted file mode 100644
index 743c199..0000000
--- a/src/generate/summon_checker.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-use proc_macro2::TokenStream;
-use quote::quote;
-use syn::Error;
-
-use crate::info_structures::{ArgType, BuilderType, StructInfo};
-
-pub fn generate_checker_summoner(info: &StructInfo) -> Result<TokenStream, Error> {
- let mut code: Vec<TokenStream> = Vec::new();
- let mut params: Vec<TokenStream> = Vec::new();
- let mut value_consumers: Vec<TokenStream> = Vec::new();
- let mut template_consumers: Vec<TokenStream> = Vec::new();
- for field in &info.fields {
- let field_name = &field.name;
-
- let arg_type = field.make_constructor_arg_type(&info, BuilderType::Sync)?;
- if let ArgType::Plain(plain_type) = arg_type {
- // No fancy builder function, we can just move the value directly into the struct.
- params.push(quote! { #field_name: #plain_type });
- } else if let ArgType::TraitBound(bound_type) = arg_type {
- // Trait bounds are much trickier. We need a special syntax to accept them in the
- // contructor, and generic parameters need to be added to the builder struct to make
- // it work.
- let builder_name = field.builder_name();
- params.push(quote! { #builder_name : impl #bound_type });
- let mut builder_args = Vec::new();
- for (_, borrow) in field.borrows.iter().enumerate() {
- let borrowed_name = &info.fields[borrow.index].name;
- if borrow.mutable {
- builder_args.push(quote! { &mut #borrowed_name });
- } else {
- builder_args.push(quote! { &#borrowed_name });
- }
- }
- code.push(quote! { let #field_name = #builder_name (#(#builder_args),*); });
- }
- if field.is_mutably_borrowed() {
- code.push(quote! { let mut #field_name = #field_name; });
- } else {
- code.push(quote! { let #field_name = #field_name; });
- value_consumers.push(quote! { #field_name: &#field_name });
- }
- }
- for (_ty, ident) in info.generic_consumers() {
- template_consumers.push(quote! { #ident: ::core::marker::PhantomData });
- }
- let generic_params = info.generic_params();
- let where_clause = &info.generics.where_clause;
- let borrowed_generic_params_inferred = info.borrowed_generic_params_inferred();
- Ok(quote! {
- fn check_if_okay_according_to_checkers<#generic_params>(
- #(#params,)*
- )
- #where_clause
- {
- #(#code;)*
- BorrowedFields::#borrowed_generic_params_inferred {
- #(#value_consumers,)*
- #(#template_consumers,)*
- };
- }
- })
-}
diff --git a/src/generate/try_constructor.rs b/src/generate/try_constructor.rs
deleted file mode 100644
index 4078c56..0000000
--- a/src/generate/try_constructor.rs
+++ /dev/null
@@ -1,301 +0,0 @@
-use crate::{
- info_structures::{ArgType, BuilderType, FieldType, Options, StructInfo},
- utils::to_class_case,
-};
-use proc_macro2::{Ident, TokenStream};
-use quote::{format_ident, quote};
-use syn::Error;
-
-pub fn create_try_builder_and_constructor(
- info: &StructInfo,
- options: Options,
- builder_type: BuilderType,
-) -> Result<(Ident, TokenStream, TokenStream), Error> {
- let struct_name = info.ident.clone();
- let generic_args = info.generic_arguments();
-
- let visibility = if options.do_pub_extras {
- info.vis.clone()
- } else {
- syn::parse_quote! { pub(super) }
- };
- let mut head_recover_code = Vec::new();
- for field in &info.fields {
- if !field.self_referencing {
- let field_name = &field.name;
- head_recover_code.push(quote! { #field_name });
- }
- }
- for (_ty, ident) in info.generic_consumers() {
- head_recover_code.push(quote! { #ident: ::core::marker::PhantomData });
- }
- let mut current_head_index = 0;
-
- let builder_struct_name = match builder_type {
- BuilderType::AsyncSend => format_ident!("{}AsyncSendTryBuilder", info.ident),
- BuilderType::Async => format_ident!("{}AsyncTryBuilder", info.ident),
- BuilderType::Sync => format_ident!("{}TryBuilder", info.ident),
- };
- let documentation = format!(
- concat!(
- "(See also [`{0}::try_build()`]({0}::try_build).) Like [`new`](Self::new), but ",
- "builders for [self-referencing fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) ",
- "can return results. If any of them fail, `Err` is returned. If all of them ",
- "succeed, `Ok` is returned. The arguments are as follows:\n\n",
- "| Argument | Suggested Use |\n| --- | --- |\n",
- ),
- builder_struct_name.to_string()
- );
- let or_recover_documentation = format!(
- concat!(
- "(See also [`{0}::try_build_or_recover()`]({0}::try_build_or_recover).) Like ",
- "[`try_new`](Self::try_new), but all ",
- "[head fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) ",
- "are returned in the case of an error. The arguments are as follows:\n\n",
- "| Argument | Suggested Use |\n| --- | --- |\n",
- ),
- builder_struct_name.to_string()
- );
- let builder_documentation = concat!(
- "A more verbose but stable way to construct self-referencing structs. It is ",
- "comparable to using `StructName { field1: value1, field2: value2 }` rather than ",
- "`StructName::new(value1, value2)`. This has the dual benefit of makin your code ",
- "both easier to refactor and more readable. Call [`try_build()`](Self::try_build) or ",
- "[`try_build_or_recover()`](Self::try_build_or_recover) to ",
- "construct the actual struct. The fields of this struct should be used as follows:\n\n",
- "| Field | Suggested Use |\n| --- | --- |\n",
- )
- .to_owned();
- let build_fn_documentation = format!(
- concat!(
- "Calls [`{0}::try_new()`]({0}::try_new) using the provided values. This is ",
- "preferrable over calling `try_new()` directly for the reasons listed above. "
- ),
- info.ident.to_string()
- );
- let build_or_recover_fn_documentation = format!(
- concat!(
- "Calls [`{0}::try_new_or_recover()`]({0}::try_new_or_recover) using the provided ",
- "values. This is preferrable over calling `try_new_or_recover()` directly for the ",
- "reasons listed above. "
- ),
- info.ident.to_string()
- );
- let mut doc_table = "".to_owned();
- let mut or_recover_code: Vec<TokenStream> = Vec::new();
- let mut params: Vec<TokenStream> = Vec::new();
- let mut builder_struct_generic_producers: Vec<_> = info
- .generic_params()
- .iter()
- .map(|param| quote! { #param })
- .collect();
- let mut builder_struct_generic_consumers = info.generic_arguments();
- let mut builder_struct_fields = Vec::new();
- let mut builder_struct_field_names = Vec::new();
-
- for field in &info.fields {
- let field_name = &field.name;
-
- let arg_type = field.make_try_constructor_arg_type(info, builder_type)?;
- if let ArgType::Plain(plain_type) = arg_type {
- // No fancy builder function, we can just move the value directly into the struct.
- params.push(quote! { #field_name: #plain_type });
- builder_struct_fields.push(quote! { #field_name: #plain_type });
- builder_struct_field_names.push(quote! { #field_name });
- doc_table += &format!(
- "| `{}` | Directly pass in the value this field should contain |\n",
- field_name.to_string()
- );
- if !field.self_referencing {
- if field.is_borrowed() {
- head_recover_code[current_head_index] = quote! {
- #field_name: ::ouroboros::macro_help::unbox(#field_name)
- };
- } else {
- head_recover_code[current_head_index] = quote! { #field_name };
- }
- current_head_index += 1;
- }
- } else if let ArgType::TraitBound(bound_type) = arg_type {
- // Trait bounds are much trickier. We need a special syntax to accept them in the
- // contructor, and generic parameters need to be added to the builder struct to make
- // it work.
- let builder_name = field.builder_name();
- params.push(quote! { #builder_name : impl #bound_type });
- // Ok so hear me out basically without this thing here my IDE thinks the rest of the
- // code is a string and it all turns green.
- {}
- doc_table += &format!(
- "| `{}` | Use a function or closure: `(",
- builder_name.to_string()
- );
- let mut builder_args = Vec::new();
- for (index, borrow) in field.borrows.iter().enumerate() {
- let borrowed_name = &info.fields[borrow.index].name;
- builder_args.push(format_ident!("{}_illegal_static_reference", borrowed_name));
- doc_table += &format!(
- "{}: &{}_",
- borrowed_name.to_string(),
- if borrow.mutable { "mut " } else { "" },
- );
- if index < field.borrows.len() - 1 {
- doc_table += ", ";
- }
- }
- doc_table += &format!(") -> Result<{}: _, Error_>` | \n", field_name.to_string());
- let builder_value = if builder_type.is_async() {
- quote! { #builder_name (#(#builder_args),*).await }
- } else {
- quote! { #builder_name (#(#builder_args),*) }
- };
- or_recover_code.push(quote! {
- let #field_name = match #builder_value {
- ::core::result::Result::Ok(value) => value,
- ::core::result::Result::Err(err)
- => return ::core::result::Result::Err((err, Heads { #(#head_recover_code),* })),
- };
- });
- let generic_type_name =
- format_ident!("{}Builder_", to_class_case(field_name.to_string().as_str()));
-
- builder_struct_generic_producers.push(quote! { #generic_type_name: #bound_type });
- builder_struct_generic_consumers.push(quote! { #generic_type_name });
- builder_struct_fields.push(quote! { #builder_name: #generic_type_name });
- builder_struct_field_names.push(quote! { #builder_name });
- }
- if field.is_borrowed() {
- let boxed = field.boxed();
- if field.field_type == FieldType::BorrowedMut {
- or_recover_code.push(quote! { let mut #field_name = #boxed; });
- } else {
- or_recover_code.push(quote! { let #field_name = #boxed; });
- }
- }
-
- if field.field_type == FieldType::Borrowed {
- or_recover_code.push(field.make_illegal_static_reference());
- } else if field.field_type == FieldType::BorrowedMut {
- or_recover_code.push(field.make_illegal_static_mut_reference());
- }
- }
- let documentation = if !options.do_no_doc {
- let documentation = documentation + &doc_table;
- quote! {
- #[doc=#documentation]
- }
- } else {
- quote! { #[doc(hidden)] }
- };
- let or_recover_documentation = if !options.do_no_doc {
- let or_recover_documentation = or_recover_documentation + &doc_table;
- quote! {
- #[doc=#or_recover_documentation]
- }
- } else {
- quote! { #[doc(hidden)] }
- };
- let builder_documentation = if !options.do_no_doc {
- let builder_documentation = builder_documentation + &doc_table;
- quote! {
- #[doc=#builder_documentation]
- }
- } else {
- quote! { #[doc(hidden)] }
- };
- let or_recover_ident = match builder_type {
- BuilderType::AsyncSend => quote! { try_new_or_recover_async_send },
- BuilderType::Async => quote! { try_new_or_recover_async },
- BuilderType::Sync => quote! { try_new_or_recover },
- };
- let or_recover_constructor_fn = if builder_type.is_async() {
- quote! { async fn #or_recover_ident }
- } else {
- quote! { fn #or_recover_ident }
- };
- let constructor_fn = match builder_type {
- BuilderType::AsyncSend => quote! { async fn try_new_async_send },
- BuilderType::Async => quote! { async fn try_new_async },
- BuilderType::Sync => quote! { fn try_new },
- };
- let constructor_code = if builder_type.is_async() {
- quote! { #struct_name::#or_recover_ident(#(#builder_struct_field_names),*).await.map_err(|(error, _heads)| error) }
- } else {
- quote! { #struct_name::#or_recover_ident(#(#builder_struct_field_names),*).map_err(|(error, _heads)| error) }
- };
- let field_names: Vec<_> = info.fields.iter().map(|field| field.name.clone()).collect();
- let constructor_def = quote! {
- #documentation
- #visibility #constructor_fn<Error_>(#(#params),*) -> ::core::result::Result<#struct_name <#(#generic_args),*>, Error_> {
- #constructor_code
- }
- #or_recover_documentation
- #visibility #or_recover_constructor_fn<Error_>(#(#params),*) -> ::core::result::Result<#struct_name <#(#generic_args),*>, (Error_, Heads<#(#generic_args),*>)> {
- #(#or_recover_code)*
- ::core::result::Result::Ok(Self { #(#field_names),* })
- }
- };
- builder_struct_generic_producers.push(quote! { Error_ });
- builder_struct_generic_consumers.push(quote! { Error_ });
- let generic_where = &info.generics.where_clause;
- let builder_fn = if builder_type.is_async() {
- quote! { async fn try_build }
- } else {
- quote! { fn try_build }
- };
- let or_recover_builder_fn = if builder_type.is_async() {
- quote! { async fn try_build_or_recover }
- } else {
- quote! { fn try_build_or_recover }
- };
- let builder_code = match builder_type {
- BuilderType::AsyncSend => quote! {
- #struct_name::try_new_async_send(
- #(self.#builder_struct_field_names),*
- ).await
- },
- BuilderType::Async => quote! {
- #struct_name::try_new_async(
- #(self.#builder_struct_field_names),*
- ).await
- },
- BuilderType::Sync => quote! {
- #struct_name::try_new(
- #(self.#builder_struct_field_names),*
- )
- },
- };
- let or_recover_builder_code = match builder_type {
- BuilderType::AsyncSend => quote! {
- #struct_name::try_new_or_recover_async_send(
- #(self.#builder_struct_field_names),*
- ).await
- },
- BuilderType::Async => quote! {
- #struct_name::try_new_or_recover_async(
- #(self.#builder_struct_field_names),*
- ).await
- },
- BuilderType::Sync => quote! {
- #struct_name::try_new_or_recover(
- #(self.#builder_struct_field_names),*
- )
- },
- };
- let builder_def = quote! {
- #builder_documentation
- #visibility struct #builder_struct_name <#(#builder_struct_generic_producers),*> #generic_where {
- #(#visibility #builder_struct_fields),*
- }
- impl<#(#builder_struct_generic_producers),*> #builder_struct_name <#(#builder_struct_generic_consumers),*> #generic_where {
- #[doc=#build_fn_documentation]
- #visibility #builder_fn(self) -> ::core::result::Result<#struct_name <#(#generic_args),*>, Error_> {
- #builder_code
- }
- #[doc=#build_or_recover_fn_documentation]
- #visibility #or_recover_builder_fn(self) -> ::core::result::Result<#struct_name <#(#generic_args),*>, (Error_, Heads<#(#generic_args),*>)> {
- #or_recover_builder_code
- }
- }
- };
- Ok((builder_struct_name, builder_def, constructor_def))
-}
diff --git a/src/generate/type_asserts.rs b/src/generate/type_asserts.rs
deleted file mode 100644
index 3c8c7d1..0000000
--- a/src/generate/type_asserts.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use proc_macro2::TokenStream;
-use quote::{format_ident, quote};
-use syn::GenericParam;
-
-use crate::{
- covariance_detection::apparent_std_container_type, info_structures::StructInfo,
- utils::replace_this_with_lifetime,
-};
-
-pub fn make_type_asserts(info: &StructInfo) -> TokenStream {
- let mut checks = Vec::new();
- let fake_lifetime = if let Some(GenericParam::Lifetime(param)) = info.generic_params().first() {
- param.lifetime.ident.clone()
- } else {
- format_ident!("static")
- };
- for field in &info.fields {
- let field_type = &field.typ;
- if let Some((std_type, _eltype)) = apparent_std_container_type(field_type) {
- let checker_name = match std_type {
- "Box" => "is_std_box_type",
- "Arc" => "is_std_arc_type",
- "Rc" => "is_std_rc_type",
- _ => unreachable!(),
- };
- let checker_name = format_ident!("{}", checker_name);
- let static_field_type =
- replace_this_with_lifetime(quote! { #field_type }, fake_lifetime.clone());
- checks.push(quote! {
- ::ouroboros::macro_help::CheckIfTypeIsStd::<#static_field_type>::#checker_name();
- });
- }
- }
- let generic_params = info.generic_params();
- let generic_where = &info.generics.where_clause;
- quote! {
- fn type_asserts <#generic_params>() #generic_where {
- #(#checks)*
- }
- }
-}
diff --git a/src/generate/with_all.rs b/src/generate/with_all.rs
deleted file mode 100644
index e6a2665..0000000
--- a/src/generate/with_all.rs
+++ /dev/null
@@ -1,134 +0,0 @@
-use crate::info_structures::{FieldType, Options, StructInfo};
-use proc_macro2::{Span, TokenStream};
-use quote::quote;
-use syn::{Error, Lifetime, WhereClause};
-
-pub fn make_with_all_function(
- info: &StructInfo,
- options: Options,
-) -> Result<(TokenStream, TokenStream), Error> {
- let visibility = if options.do_pub_extras {
- info.vis.clone()
- } else {
- syn::parse_quote! { pub(super) }
- };
- let mut fields = Vec::new();
- let mut field_assignments = Vec::new();
- let mut mut_fields = Vec::new();
- let mut mut_field_assignments = Vec::new();
- // I don't think the reverse is necessary but it does make the expanded code more uniform.
- for field in info.fields.iter().rev() {
- let field_name = &field.name;
- let field_type = &field.typ;
- if field.field_type == FieldType::Tail {
- fields.push(quote! { #visibility #field_name: &'outer_borrow #field_type });
- field_assignments.push(quote! { #field_name: &self.#field_name });
- mut_fields.push(quote! { #visibility #field_name: &'outer_borrow mut #field_type });
- mut_field_assignments.push(quote! { #field_name: &mut self.#field_name });
- } else if field.field_type == FieldType::Borrowed {
- let ass = quote! { #field_name: unsafe {
- ::ouroboros::macro_help::change_lifetime(
- &*self.#field_name
- )
- } };
- fields.push(quote! { #visibility #field_name: &'this #field_type });
- field_assignments.push(ass.clone());
- mut_fields.push(quote! { #visibility #field_name: &'this #field_type });
- mut_field_assignments.push(ass);
- } else if field.field_type == FieldType::BorrowedMut {
- // Add nothing because we cannot borrow something that has already been mutably
- // borrowed.
- }
- }
-
- for (ty, ident) in info.generic_consumers() {
- fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> });
- mut_fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> });
- field_assignments.push(quote! { #ident: ::core::marker::PhantomData });
- mut_field_assignments.push(quote! { #ident: ::core::marker::PhantomData });
- }
- let new_generic_params = info.borrowed_generic_params();
- let new_generic_args = info.borrowed_generic_arguments();
-
- let struct_documentation = format!(
- concat!(
- "A struct for holding immutable references to all ",
- "[tail and immutably borrowed fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) in an instance of ",
- "[`{0}`]({0})."
- ),
- info.ident.to_string()
- );
- let mut_struct_documentation = format!(
- concat!(
- "A struct for holding mutable references to all ",
- "[tail fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) in an instance of ",
- "[`{0}`]({0})."
- ),
- info.ident.to_string()
- );
- let ltname = format!("'{}", info.fake_lifetime());
- let lifetime = Lifetime::new(&ltname, Span::call_site());
- let generic_where = if let Some(clause) = &info.generics.where_clause {
- let mut clause = clause.clone();
- let extra: WhereClause = syn::parse_quote! { where #lifetime: 'this };
- clause
- .predicates
- .push(extra.predicates.first().unwrap().clone());
- clause
- } else {
- syn::parse_quote! { where #lifetime: 'this }
- };
- let struct_defs = quote! {
- #[doc=#struct_documentation]
- #visibility struct BorrowedFields #new_generic_params #generic_where { #(#fields),* }
- #[doc=#mut_struct_documentation]
- #visibility struct BorrowedMutFields #new_generic_params #generic_where { #(#mut_fields),* }
- };
- let borrowed_fields_type = quote! { BorrowedFields<#(#new_generic_args),*> };
- let borrowed_mut_fields_type = quote! { BorrowedMutFields<#(#new_generic_args),*> };
- let documentation = concat!(
- "This method provides immutable references to all ",
- "[tail and immutably borrowed fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions).",
- );
- let mut_documentation = concat!(
- "This method provides mutable references to all ",
- "[tail fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions).",
- );
- let documentation = if !options.do_no_doc {
- quote! {
- #[doc=#documentation]
- }
- } else {
- quote! { #[doc(hidden)] }
- };
- let mut_documentation = if !options.do_no_doc {
- quote! {
- #[doc=#mut_documentation]
- }
- } else {
- quote! { #[doc(hidden)] }
- };
- let fn_defs = quote! {
- #documentation
- #[inline(always)]
- #visibility fn with <'outer_borrow, ReturnType>(
- &'outer_borrow self,
- user: impl for<'this> ::core::ops::FnOnce(#borrowed_fields_type) -> ReturnType
- ) -> ReturnType {
- user(BorrowedFields {
- #(#field_assignments),*
- })
- }
- #mut_documentation
- #[inline(always)]
- #visibility fn with_mut <'outer_borrow, ReturnType>(
- &'outer_borrow mut self,
- user: impl for<'this> ::core::ops::FnOnce(#borrowed_mut_fields_type) -> ReturnType
- ) -> ReturnType {
- user(BorrowedMutFields {
- #(#mut_field_assignments),*
- })
- }
- };
- Ok((struct_defs, fn_defs))
-}
diff --git a/src/generate/with_each.rs b/src/generate/with_each.rs
deleted file mode 100644
index 8985857..0000000
--- a/src/generate/with_each.rs
+++ /dev/null
@@ -1,132 +0,0 @@
-use crate::info_structures::{FieldType, Options, StructInfo};
-use proc_macro2::TokenStream;
-use quote::{format_ident, quote};
-use syn::Error;
-
-pub fn make_with_functions(info: &StructInfo, options: Options) -> Result<Vec<TokenStream>, Error> {
- let mut users = Vec::new();
- for field in &info.fields {
- let visibility = &field.vis;
- let field_name = &field.name;
- let field_type = &field.typ;
- // If the field is not a tail, we need to serve up the same kind of reference that other
- // fields in the struct may have borrowed to ensure safety.
- if field.field_type == FieldType::Tail {
- let user_name = format_ident!("with_{}", &field.name);
- let documentation = format!(
- concat!(
- "Provides an immutable reference to `{0}`. This method was generated because ",
- "`{0}` is a [tail field](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions)."
- ),
- field.name.to_string()
- );
- let documentation = if !options.do_no_doc {
- quote! {
- #[doc=#documentation]
- }
- } else {
- quote! { #[doc(hidden)] }
- };
- users.push(quote! {
- #documentation
- #[inline(always)]
- #visibility fn #user_name <'outer_borrow, ReturnType>(
- &'outer_borrow self,
- user: impl for<'this> ::core::ops::FnOnce(&'outer_borrow #field_type) -> ReturnType,
- ) -> ReturnType {
- user(&self. #field_name)
- }
- });
- if field.covariant == Some(true) {
- let borrower_name = format_ident!("borrow_{}", &field.name);
- users.push(quote! {
- #documentation
- #[inline(always)]
- #visibility fn #borrower_name<'this>(
- &'this self,
- ) -> &'this #field_type {
- &self.#field_name
- }
- });
- } else if field.covariant.is_none() {
- field.covariance_error();
- }
- // If it is not borrowed at all it's safe to allow mutably borrowing it.
- let user_name = format_ident!("with_{}_mut", &field.name);
- let documentation = format!(
- concat!(
- "Provides a mutable reference to `{0}`. This method was generated because ",
- "`{0}` is a [tail field](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions). ",
- "No `borrow_{0}_mut` function was generated because Rust's borrow checker is ",
- "currently unable to guarantee that such a method would be used safely."
- ),
- field.name.to_string()
- );
- let documentation = if !options.do_no_doc {
- quote! {
- #[doc=#documentation]
- }
- } else {
- quote! { #[doc(hidden)] }
- };
- users.push(quote! {
- #documentation
- #[inline(always)]
- #visibility fn #user_name <'outer_borrow, ReturnType>(
- &'outer_borrow mut self,
- user: impl for<'this> ::core::ops::FnOnce(&'outer_borrow mut #field_type) -> ReturnType,
- ) -> ReturnType {
- user(&mut self. #field_name)
- }
- });
- } else if field.field_type == FieldType::Borrowed {
- let user_name = format_ident!("with_{}", &field.name);
- let documentation = format!(
- concat!(
- "Provides limited immutable access to `{0}`. This method was generated ",
- "because the contents of `{0}` are immutably borrowed by other fields."
- ),
- field.name.to_string()
- );
- let documentation = if !options.do_no_doc {
- quote! {
- #[doc=#documentation]
- }
- } else {
- quote! { #[doc(hidden)] }
- };
- users.push(quote! {
- #documentation
- #[inline(always)]
- #visibility fn #user_name <'outer_borrow, ReturnType>(
- &'outer_borrow self,
- user: impl for<'this> ::core::ops::FnOnce(&'outer_borrow #field_type) -> ReturnType,
- ) -> ReturnType {
- user(&*self.#field_name)
- }
- });
- if field.self_referencing {
- if field.covariant == Some(false) {
- // Skip the other functions, they will cause compiler errors.
- continue;
- } else if field.covariant.is_none() {
- field.covariance_error();
- }
- }
- let borrower_name = format_ident!("borrow_{}", &field.name);
- users.push(quote! {
- #documentation
- #[inline(always)]
- #visibility fn #borrower_name<'this>(
- &'this self,
- ) -> &'this #field_type {
- &*self.#field_name
- }
- });
- } else if field.field_type == FieldType::BorrowedMut {
- // Do not generate anything becaue if it is borrowed mutably once, we should not be able
- // to get any other kinds of references to it.
- }
- }
- Ok(users)
-}
diff --git a/src/info_structures.rs b/src/info_structures.rs
deleted file mode 100644
index 05dc734..0000000
--- a/src/info_structures.rs
+++ /dev/null
@@ -1,304 +0,0 @@
-use crate::utils::{make_generic_arguments, make_generic_consumers, replace_this_with_lifetime};
-use proc_macro2::{Ident, TokenStream};
-use quote::{format_ident, quote, ToTokens};
-use syn::{
- punctuated::Punctuated, token::Comma, Attribute, ConstParam, Error, GenericParam, Generics,
- LifetimeDef, Type, TypeParam, Visibility,
-};
-
-#[derive(Clone, Copy)]
-pub struct Options {
- pub do_no_doc: bool,
- pub do_pub_extras: bool,
-}
-
-#[derive(Clone, Copy, PartialEq)]
-pub enum FieldType {
- /// Not borrowed by other parts of the struct.
- Tail,
- /// Immutably borrowed by at least one other field.
- Borrowed,
- /// Mutably borrowed by one other field.
- BorrowedMut,
-}
-
-impl FieldType {
- pub fn is_tail(self) -> bool {
- self == Self::Tail
- }
-}
-
-#[derive(Clone)]
-pub struct BorrowRequest {
- pub index: usize,
- pub mutable: bool,
-}
-
-#[derive(Clone)]
-pub enum Derive {
- Debug,
- PartialEq,
- Eq,
-}
-
-#[derive(Copy, Clone)]
-pub enum BuilderType {
- Sync,
- Async,
- AsyncSend,
-}
-
-impl BuilderType {
- pub fn is_async(&self) -> bool {
- match self {
- BuilderType::Sync => false,
- _ => true,
- }
- }
-}
-
-#[derive(Clone)]
-pub struct StructInfo {
- pub derives: Vec<Derive>,
- pub ident: Ident,
- pub generics: Generics,
- pub vis: Visibility,
- pub fields: Vec<StructFieldInfo>,
- pub first_lifetime: Ident,
- pub attributes: Vec<Attribute>,
-}
-
-impl StructInfo {
- // The lifetime to use in place of 'this for internal implementations,
- // should never be exposed to the user.
- pub fn fake_lifetime(&self) -> Ident {
- return self.first_lifetime.clone();
- }
-
- pub fn generic_params(&self) -> &Punctuated<GenericParam, Comma> {
- &self.generics.params
- }
-
- /// Same as generic_params but with 'this and 'outer_borrow prepended.
- pub fn borrowed_generic_params(&self) -> TokenStream {
- if self.generic_params().is_empty() {
- quote! { <'outer_borrow, 'this> }
- } else {
- let mut new_generic_params = self.generic_params().clone();
- new_generic_params.insert(0, syn::parse_quote! { 'this });
- new_generic_params.insert(0, syn::parse_quote! { 'outer_borrow });
- quote! { <#new_generic_params> }
- }
- }
-
- /// Same as generic_params but without bounds and with '_ prepended twice.
- pub fn borrowed_generic_params_inferred(&self) -> TokenStream {
- use GenericParam::*;
- let params = self.generic_params().iter().map(|p| match p {
- Type(TypeParam { ident, .. }) | Const(ConstParam { ident, .. }) => {
- ident.to_token_stream()
- }
- Lifetime(LifetimeDef { lifetime, .. }) => lifetime.to_token_stream(),
- });
- quote! { <'_, '_, #(#params,)*> }
- }
-
- pub fn generic_arguments(&self) -> Vec<TokenStream> {
- make_generic_arguments(&self.generics)
- }
-
- /// Same as generic_arguments but with 'outer_borrow and 'this prepended.
- pub fn borrowed_generic_arguments(&self) -> Vec<TokenStream> {
- let mut args = self.generic_arguments();
- args.insert(0, quote! { 'this });
- args.insert(0, quote! { 'outer_borrow });
- args
- }
-
- pub fn generic_consumers(&self) -> impl Iterator<Item = (TokenStream, Ident)> {
- make_generic_consumers(&self.generics)
- }
-}
-
-#[derive(Clone)]
-pub struct StructFieldInfo {
- pub name: Ident,
- pub typ: Type,
- pub field_type: FieldType,
- pub vis: Visibility,
- pub borrows: Vec<BorrowRequest>,
- /// If this is true and borrows is empty, the struct will borrow from self in the future but
- /// does not require a builder to be initialized. It should not be able to be removed from the
- /// struct with into_heads.
- pub self_referencing: bool,
- /// If it is None, the user has not specified whether or not the field is covariant. If this is
- /// Some(false), we should avoid making borrow_* or borrow_*_mut functions as they will not
- /// be able to compile.
- pub covariant: Option<bool>,
-}
-
-#[derive(Clone)]
-pub enum ArgType {
- /// Used when the initial value of a field can be passed directly into the constructor.
- Plain(TokenStream),
- /// Used when a field requires self references and thus requires something that implements
- /// a builder function trait instead of a simple plain type.
- TraitBound(TokenStream),
-}
-
-impl StructFieldInfo {
- pub fn builder_name(&self) -> Ident {
- format_ident!("{}_builder", self.name)
- }
-
- pub fn illegal_ref_name(&self) -> Ident {
- format_ident!("{}_illegal_static_reference", self.name)
- }
-
- pub fn is_borrowed(&self) -> bool {
- self.field_type != FieldType::Tail
- }
-
- pub fn is_mutably_borrowed(&self) -> bool {
- self.field_type == FieldType::BorrowedMut
- }
-
- pub fn boxed(&self) -> TokenStream {
- let name = &self.name;
- quote! { ::ouroboros::macro_help::aliasable_boxed(#name) }
- }
-
- pub fn stored_type(&self) -> TokenStream {
- let t = &self.typ;
- if self.is_borrowed() {
- quote! { ::ouroboros::macro_help::AliasableBox<#t> }
- } else {
- quote! { #t }
- }
- }
-
- /// Returns code which takes a variable with the same name and type as this field and turns it
- /// into a static reference to its dereffed contents.
- pub fn make_illegal_static_reference(&self) -> TokenStream {
- let field_name = &self.name;
- let ref_name = self.illegal_ref_name();
- quote! {
- let #ref_name = unsafe {
- ::ouroboros::macro_help::change_lifetime(&*#field_name)
- };
- }
- }
-
- /// Like make_illegal_static_reference, but provides a mutable reference instead.
- pub fn make_illegal_static_mut_reference(&self) -> TokenStream {
- let field_name = &self.name;
- let ref_name = self.illegal_ref_name();
- quote! {
- let #ref_name = unsafe {
- ::ouroboros::macro_help::change_lifetime_mut(&mut *#field_name)
- };
- }
- }
-
- /// Generates an error requesting that the user explicitly specify whether or not the
- /// field's type is covariant.
- pub fn covariance_error(&self) {
- let error = concat!(
- "Ouroboros cannot automatically determine if this type is covariant.\n\n",
- "If it is covariant, it should be legal to convert any instance of that type to an ",
- "instance of that type where all usages of 'this are replaced with a smaller ",
- "lifetime. For example, Box<&'this i32> is covariant because it is legal to use it as ",
- "a Box<&'a i32> where 'this: 'a. In contrast, Fn(&'this i32) cannot be used as ",
- "Fn(&'a i32).\n\n",
- "To resolve this error, add #[covariant] or #[not_covariant] to the field.\n",
- );
- proc_macro_error::emit_error!(self.typ, error);
- }
-
- pub fn make_constructor_arg_type_impl(
- &self,
- info: &StructInfo,
- make_builder_return_type: impl FnOnce() -> TokenStream,
- ) -> Result<ArgType, Error> {
- let field_type = &self.typ;
- let fake_lifetime = info.fake_lifetime();
- if self.borrows.is_empty() {
- // Even if self_referencing is true, as long as borrows is empty, we don't need to use a
- // builder to construct it.
- let field_type =
- replace_this_with_lifetime(field_type.into_token_stream(), fake_lifetime.clone());
- Ok(ArgType::Plain(quote! { #field_type }))
- } else {
- let mut field_builder_params = Vec::new();
- for borrow in &self.borrows {
- if borrow.mutable {
- let field = &info.fields[borrow.index];
- let field_type = &field.typ;
- field_builder_params.push(quote! {
- &'this mut #field_type
- });
- } else {
- let field = &info.fields[borrow.index];
- let field_type = &field.typ;
- field_builder_params.push(quote! {
- &'this #field_type
- });
- }
- }
- let return_type = make_builder_return_type();
- let bound = quote! { for<'this> ::core::ops::FnOnce(#(#field_builder_params),*) -> #return_type };
- Ok(ArgType::TraitBound(bound))
- }
- }
-
- /// Returns a trait bound if `for_field` refers to any other fields, and a plain type if not. This
- /// is the type used in the constructor to initialize the value of `for_field`.
- pub fn make_constructor_arg_type(
- &self,
- info: &StructInfo,
- builder_type: BuilderType,
- ) -> Result<ArgType, Error> {
- let field_type = &self.typ;
- let return_ty_constructor = || match builder_type {
- BuilderType::AsyncSend => {
- quote! {
- ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box<
- dyn ::core::future::Future<Output=#field_type> + ::core::marker::Send + 'this>>
- }
- }
- BuilderType::Async => {
- quote! { ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box<
- dyn ::core::future::Future<Output=#field_type> + 'this>> }
- }
- BuilderType::Sync => quote! { #field_type },
- };
- self.make_constructor_arg_type_impl(info, return_ty_constructor)
- }
-
- /// Like make_constructor_arg_type, but used for the try_new constructor.
- pub fn make_try_constructor_arg_type(
- &self,
- info: &StructInfo,
- builder_type: BuilderType,
- ) -> Result<ArgType, Error> {
- let field_type = &self.typ;
- let return_ty_constructor = || match builder_type {
- BuilderType::AsyncSend => {
- quote! {
- ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box<
- dyn ::core::future::Future<Output=::core::result::Result<#field_type, Error_>>
- + ::core::marker::Send + 'this>>
- }
- }
- BuilderType::Async => {
- quote! {
- ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box<
- dyn ::core::future::Future<Output=::core::result::Result<#field_type, Error_>>
- + 'this>>
- }
- }
- BuilderType::Sync => quote! { ::core::result::Result<#field_type, Error_> },
- };
- self.make_constructor_arg_type_impl(info, return_ty_constructor)
- }
-}
diff --git a/src/lib.rs b/src/lib.rs
deleted file mode 100644
index cd12419..0000000
--- a/src/lib.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-extern crate proc_macro;
-
-mod covariance_detection;
-mod generate;
-mod info_structures;
-mod parse;
-mod utils;
-
-use crate::{
- generate::{
- constructor::create_builder_and_constructor, derives::create_derives,
- into_heads::make_into_heads, struc::create_actual_struct_def,
- summon_checker::generate_checker_summoner,
- try_constructor::create_try_builder_and_constructor, type_asserts::make_type_asserts,
- with_all::make_with_all_function, with_each::make_with_functions,
- },
- info_structures::Options,
- parse::parse_struct,
-};
-use inflector::Inflector;
-use info_structures::BuilderType;
-use proc_macro::TokenStream;
-use proc_macro2::TokenStream as TokenStream2;
-use proc_macro2::TokenTree;
-use proc_macro_error::proc_macro_error;
-use quote::{format_ident, quote};
-use syn::{Error, ItemStruct};
-
-fn self_referencing_impl(
- original_struct_def: &ItemStruct,
- options: Options,
-) -> Result<TokenStream, Error> {
- let struct_name = &original_struct_def.ident;
- let mod_name = format_ident!("ouroboros_impl_{}", struct_name.to_string().to_snake_case());
- let visibility = &original_struct_def.vis;
-
- let info = parse_struct(original_struct_def)?;
-
- let actual_struct_def = create_actual_struct_def(&info)?;
-
- let borrowchk_summoner = generate_checker_summoner(&info)?;
-
- let (builder_struct_name, builder_def, constructor_def) =
- create_builder_and_constructor(&info, options, BuilderType::Sync)?;
- let (async_builder_struct_name, async_builder_def, async_constructor_def) =
- create_builder_and_constructor(&info, options, BuilderType::Async)?;
- let (async_send_builder_struct_name, async_send_builder_def, async_send_constructor_def) =
- create_builder_and_constructor(&info, options, BuilderType::AsyncSend)?;
- let (try_builder_struct_name, try_builder_def, try_constructor_def) =
- create_try_builder_and_constructor(&info, options, BuilderType::Sync)?;
- let (async_try_builder_struct_name, async_try_builder_def, async_try_constructor_def) =
- create_try_builder_and_constructor(&info, options, BuilderType::Async)?;
- let (async_send_try_builder_struct_name, async_send_try_builder_def, async_send_try_constructor_def) =
- create_try_builder_and_constructor(&info, options, BuilderType::AsyncSend)?;
-
- let with_defs = make_with_functions(&info, options)?;
- let (with_all_struct_defs, with_all_fn_defs) = make_with_all_function(&info, options)?;
- let (heads_struct_def, into_heads_fn) = make_into_heads(&info, options);
-
- let impls = create_derives(&info)?;
-
- // These check that types like Box, Arc, and Rc refer to those types in the std lib and have not
- // been overridden.
- let type_asserts_def = make_type_asserts(&info);
-
- let extra_visibility = if options.do_pub_extras {
- visibility.clone()
- } else {
- syn::Visibility::Inherited
- };
-
- let generic_params = info.generic_params();
- let generic_args = info.generic_arguments();
- let generic_where = &info.generics.where_clause;
- Ok(TokenStream::from(quote! {
- #[doc="Encapsulates implementation details for a self-referencing struct. This module is only visible when using --document-private-items."]
- mod #mod_name {
- use super::*;
- #[doc="The self-referencing struct."]
- #actual_struct_def
- #borrowchk_summoner
- #builder_def
- #async_builder_def
- #async_send_builder_def
- #try_builder_def
- #async_try_builder_def
- #async_send_try_builder_def
- #with_all_struct_defs
- #heads_struct_def
- #impls
- impl <#generic_params> #struct_name <#(#generic_args),*> #generic_where {
- #constructor_def
- #async_constructor_def
- #async_send_constructor_def
- #try_constructor_def
- #async_try_constructor_def
- #async_send_try_constructor_def
- #(#with_defs)*
- #with_all_fn_defs
- #into_heads_fn
- }
- #type_asserts_def
- }
- #visibility use #mod_name :: #struct_name;
- #extra_visibility use #mod_name :: #builder_struct_name;
- #extra_visibility use #mod_name :: #async_builder_struct_name;
- #extra_visibility use #mod_name :: #async_send_builder_struct_name;
- #extra_visibility use #mod_name :: #try_builder_struct_name;
- #extra_visibility use #mod_name :: #async_try_builder_struct_name;
- #extra_visibility use #mod_name :: #async_send_try_builder_struct_name;
- }))
-}
-
-#[proc_macro_error]
-#[proc_macro_attribute]
-pub fn self_referencing(attr: TokenStream, item: TokenStream) -> TokenStream {
- let mut options = Options {
- do_no_doc: false,
- do_pub_extras: false,
- };
- let mut expecting_comma = false;
- for token in <TokenStream as std::convert::Into<TokenStream2>>::into(attr).into_iter() {
- if let TokenTree::Ident(ident) = &token {
- if expecting_comma {
- return Error::new(token.span(), "Unexpected identifier, expected comma.")
- .to_compile_error()
- .into();
- }
- match &ident.to_string()[..] {
- "no_doc" => options.do_no_doc = true,
- "pub_extras" => options.do_pub_extras = true,
- _ => {
- return Error::new_spanned(
- &ident,
- "Unknown identifier, expected 'no_doc' or 'pub_extras'.",
- )
- .to_compile_error()
- .into()
- }
- }
- expecting_comma = true;
- } else if let TokenTree::Punct(punct) = &token {
- if !expecting_comma {
- return Error::new(token.span(), "Unexpected punctuation, expected identifier.")
- .to_compile_error()
- .into();
- }
- if punct.as_char() != ',' {
- return Error::new(token.span(), "Unknown punctuation, expected comma.")
- .to_compile_error()
- .into();
- }
- expecting_comma = false;
- } else {
- return Error::new(token.span(), "Unknown syntax, expected identifier.")
- .to_compile_error()
- .into();
- }
- }
- let original_struct_def: ItemStruct = syn::parse_macro_input!(item);
- match self_referencing_impl(&original_struct_def, options) {
- Ok(content) => content,
- Err(err) => err.to_compile_error().into(),
- }
-}
diff --git a/src/parse.rs b/src/parse.rs
deleted file mode 100644
index 546aa7c..0000000
--- a/src/parse.rs
+++ /dev/null
@@ -1,271 +0,0 @@
-use proc_macro2::{Delimiter, Span, TokenTree};
-use quote::format_ident;
-use syn::{spanned::Spanned, Attribute, Error, Fields, GenericParam, ItemStruct};
-
-use crate::{
- covariance_detection::type_is_covariant_over_this_lifetime,
- info_structures::{BorrowRequest, Derive, FieldType, StructFieldInfo, StructInfo},
- utils::submodule_contents_visiblity,
-};
-
-fn handle_borrows_attr(
- field_info: &mut [StructFieldInfo],
- attr: &Attribute,
- borrows: &mut Vec<BorrowRequest>,
-) -> Result<(), Error> {
- let mut borrow_mut = false;
- let mut waiting_for_comma = false;
- let tokens = attr.tokens.clone();
- let possible_error = Error::new_spanned(&tokens, "Invalid syntax for borrows() macro.");
- let tokens = if let Some(TokenTree::Group(group)) = tokens.into_iter().next() {
- group.stream()
- } else {
- return Err(possible_error);
- };
- for token in tokens {
- if let TokenTree::Ident(ident) = token {
- if waiting_for_comma {
- return Err(Error::new_spanned(&ident, "Expected comma."));
- }
- let istr = ident.to_string();
- if istr == "mut" {
- if borrow_mut {
- return Err(Error::new_spanned(&ident, "Unexpected double 'mut'"));
- }
- borrow_mut = true;
- } else {
- let index = field_info.iter().position(|item| item.name == istr);
- let index = if let Some(v) = index {
- v
- } else {
- return Err(Error::new_spanned(
- &ident,
- concat!(
- "Unknown identifier, make sure that it is spelled ",
- "correctly and defined above the location it is borrowed."
- ),
- ));
- };
- if borrow_mut {
- if field_info[index].field_type == FieldType::Borrowed {
- return Err(Error::new_spanned(
- &ident,
- "Cannot borrow mutably, this field was previously borrowed immutably.",
- ));
- }
- if field_info[index].field_type == FieldType::BorrowedMut {
- return Err(Error::new_spanned(&ident, "Cannot borrow mutably twice."));
- }
- field_info[index].field_type = FieldType::BorrowedMut;
- } else {
- if field_info[index].field_type == FieldType::BorrowedMut {
- return Err(Error::new_spanned(
- &ident,
- "Cannot borrow as immutable as it was previously borrowed mutably.",
- ));
- }
- field_info[index].field_type = FieldType::Borrowed;
- }
- borrows.push(BorrowRequest {
- index,
- mutable: borrow_mut,
- });
- waiting_for_comma = true;
- borrow_mut = false;
- }
- } else if let TokenTree::Punct(punct) = token {
- if punct.as_char() == ',' {
- if waiting_for_comma {
- waiting_for_comma = false;
- } else {
- return Err(Error::new_spanned(&punct, "Unexpected extra comma."));
- }
- } else {
- return Err(Error::new_spanned(
- &punct,
- "Unexpected punctuation, expected comma or identifier.",
- ));
- }
- } else {
- return Err(Error::new_spanned(
- &token,
- "Unexpected token, expected comma or identifier.",
- ));
- }
- }
- Ok(())
-}
-
-fn parse_derive_token(token: &TokenTree) -> Result<Option<Derive>, Error> {
- match token {
- TokenTree::Ident(ident) => match &ident.to_string()[..] {
- "Debug" => Ok(Some(Derive::Debug)),
- "PartialEq" => Ok(Some(Derive::PartialEq)),
- "Eq" => Ok(Some(Derive::Eq)),
- _ => Err(Error::new(
- ident.span(),
- format!("{} cannot be derived for self-referencing structs", ident),
- )),
- },
- TokenTree::Punct(..) => Ok(None),
- _ => Err(Error::new(token.span(), "bad syntax")),
- }
-}
-
-fn parse_derive_attribute(attr: &Attribute) -> Result<Vec<Derive>, Error> {
- let body = &attr.tokens;
- if let Some(TokenTree::Group(body)) = body.clone().into_iter().next() {
- if body.delimiter() != Delimiter::Parenthesis {
- panic!("TODO: nice error, bad define syntax")
- }
- let mut derives = Vec::new();
- for token in body.stream().into_iter() {
- if let Some(derive) = parse_derive_token(&token)? {
- derives.push(derive);
- }
- }
- Ok(derives)
- } else {
- Err(Error::new(attr.span(), "bad syntax"))
- }
-}
-
-pub fn parse_struct(def: &ItemStruct) -> Result<StructInfo, Error> {
- let vis = def.vis.clone();
- let generics = def.generics.clone();
- let mut actual_struct_def = def.clone();
- actual_struct_def.vis = vis.clone();
- let mut fields = Vec::new();
- match &mut actual_struct_def.fields {
- Fields::Named(def_fields) => {
- for field in &mut def_fields.named {
- let mut borrows = Vec::new();
- let mut self_referencing = false;
- let mut covariant = type_is_covariant_over_this_lifetime(&field.ty);
- let mut remove_attrs = Vec::new();
- for (index, attr) in field.attrs.iter().enumerate() {
- let path = &attr.path;
- if path.leading_colon.is_some() {
- continue;
- }
- if path.segments.len() != 1 {
- continue;
- }
- if path.segments.first().unwrap().ident == "borrows" {
- if self_referencing {
- panic!("TODO: Nice error, used #[borrows()] twice.");
- }
- self_referencing = true;
- handle_borrows_attr(&mut fields[..], attr, &mut borrows)?;
- remove_attrs.push(index);
- }
- if path.segments.first().unwrap().ident == "covariant" {
- if covariant.is_some() {
- panic!("TODO: Nice error, covariance specified twice.");
- }
- covariant = Some(true);
- remove_attrs.push(index);
- }
- if path.segments.first().unwrap().ident == "not_covariant" {
- if covariant.is_some() {
- panic!("TODO: Nice error, covariance specified twice.");
- }
- covariant = Some(false);
- remove_attrs.push(index);
- }
- }
- // We should not be able to access the field outside of the hidden module where
- // everything is generated.
- let with_vis = submodule_contents_visiblity(&field.vis.clone());
- fields.push(StructFieldInfo {
- name: field.ident.clone().expect("Named field has no name."),
- typ: field.ty.clone(),
- field_type: FieldType::Tail,
- vis: with_vis,
- borrows,
- self_referencing,
- covariant,
- });
- }
- }
- Fields::Unnamed(_fields) => {
- return Err(Error::new(
- Span::call_site(),
- "Tuple structs are not supported yet.",
- ))
- }
- Fields::Unit => {
- return Err(Error::new(
- Span::call_site(),
- "Unit structs cannot be self-referential.",
- ))
- }
- }
- if fields.len() < 2 {
- return Err(Error::new(
- Span::call_site(),
- "Self-referencing structs must have at least 2 fields.",
- ));
- }
- let mut has_non_tail = false;
- for field in &fields {
- if !field.field_type.is_tail() {
- has_non_tail = true;
- break;
- }
- }
- if !has_non_tail {
- return Err(Error::new(
- Span::call_site(),
- &format!(
- concat!(
- "Self-referencing struct cannot be made entirely of tail fields, try adding ",
- "#[borrows({0})] to a field defined after {0}."
- ),
- fields[0].name
- ),
- ));
- }
- let first_lifetime = if let Some(GenericParam::Lifetime(param)) = generics.params.first() {
- param.lifetime.ident.clone()
- } else {
- format_ident!("static")
- };
- let mut attributes = Vec::new();
- let mut derives = Vec::new();
- for attr in &def.attrs {
- let p = &attr.path.segments;
- if p.len() == 0 {
- return Err(Error::new(p.span(), &format!("Unsupported attribute")));
- }
- let name = p[0].ident.to_string();
- let good = match &name[..] {
- "clippy" | "allow" | "deny" | "doc" => true,
- _ => false,
- };
- if good {
- attributes.push(attr.clone())
- } else if name == "derive" {
- if derives.len() > 0 {
- return Err(Error::new(
- attr.span(),
- "Multiple derive attributes not allowed",
- ));
- } else {
- derives = parse_derive_attribute(attr)?;
- }
- } else {
- return Err(Error::new(p.span(), &format!("Unsupported attribute")));
- }
- }
-
- return Ok(StructInfo {
- derives,
- ident: def.ident.clone(),
- generics: def.generics.clone(),
- fields,
- vis,
- first_lifetime,
- attributes,
- });
-}
diff --git a/src/utils.rs b/src/utils.rs
deleted file mode 100644
index 5bbae6c..0000000
--- a/src/utils.rs
+++ /dev/null
@@ -1,140 +0,0 @@
-use inflector::Inflector;
-use proc_macro2::{Group, Ident, TokenStream, TokenTree};
-use quote::{format_ident, quote};
-use syn::{GenericParam, Generics, Visibility};
-
-/// Makes phantom data definitions so that we don't get unused template parameter errors.
-pub fn make_generic_consumers(generics: &Generics) -> impl Iterator<Item = (TokenStream, Ident)> {
- generics
- .params
- .clone()
- .into_iter()
- .map(|param| match param {
- GenericParam::Type(ty) => {
- let ident = &ty.ident;
- (
- quote! { #ident },
- format_ident!(
- "_consume_template_type_{}",
- ident.to_string().to_snake_case()
- ),
- )
- }
- GenericParam::Lifetime(lt) => {
- let lifetime = &lt.lifetime;
- let ident = &lifetime.ident;
- (
- quote! { &#lifetime () },
- format_ident!("_consume_template_lifetime_{}", ident),
- )
- }
- GenericParam::Const(..) => unimplemented!(),
- })
-}
-
-// Takes the generics parameters from the original struct and turns them into arguments.
-pub fn make_generic_arguments(generics: &Generics) -> Vec<TokenStream> {
- let mut arguments = Vec::new();
- for generic in generics.params.clone() {
- match generic {
- GenericParam::Type(typ) => {
- let ident = &typ.ident;
- arguments.push(quote! { #ident });
- }
- GenericParam::Lifetime(lt) => {
- let lifetime = &lt.lifetime;
- arguments.push(quote! { #lifetime });
- }
- GenericParam::Const(_) => unimplemented!("Const generics are not supported yet."),
- }
- }
- arguments
-}
-
-pub fn uses_this_lifetime(input: TokenStream) -> bool {
- for token in input.into_iter() {
- match token {
- TokenTree::Ident(ident) => {
- if ident == "this" {
- return true;
- }
- }
- TokenTree::Group(group) => {
- if uses_this_lifetime(group.stream()) {
- return true;
- }
- }
- _ => (),
- }
- }
- false
-}
-
-pub fn replace_this_with_lifetime(input: TokenStream, lifetime: Ident) -> TokenStream {
- input
- .into_iter()
- .map(|token| match &token {
- TokenTree::Ident(ident) => {
- if ident == "this" {
- TokenTree::Ident(lifetime.clone())
- } else {
- token
- }
- }
- TokenTree::Group(group) => TokenTree::Group(Group::new(
- group.delimiter(),
- replace_this_with_lifetime(group.stream(), lifetime.clone()),
- )),
- _ => token,
- })
- .collect()
-}
-
-pub fn submodule_contents_visiblity(original_visibility: &Visibility) -> Visibility {
- match original_visibility {
- // inherited: allow parent of inner submodule to see
- Visibility::Inherited => syn::parse_quote! { pub(super) },
- // restricted: add an extra super if needed
- Visibility::Restricted(ref restricted) => {
- let is_first_component_super = restricted
- .path
- .segments
- .first()
- .map(|segm| segm.ident == "super")
- .unwrap_or(false);
- if restricted.path.leading_colon.is_none() && is_first_component_super {
- let mut new_visibility = restricted.clone();
- new_visibility.in_token = Some(
- restricted
- .in_token
- .clone()
- .unwrap_or_else(|| syn::parse_quote! { in }),
- );
- new_visibility.path.segments = std::iter::once(syn::parse_quote! { super })
- .chain(restricted.path.segments.iter().cloned())
- .collect();
- Visibility::Restricted(new_visibility)
- } else {
- original_visibility.clone()
- }
- }
- // others are absolute, can use them as-is
- _ => original_visibility.clone(),
- }
-}
-
-/// Functionality inspired by `Inflector`, reimplemented here to avoid the
-/// `regex` dependency.
-pub fn to_class_case(s: &str) -> String {
- s.split('_')
- .flat_map(|word| {
- let mut chars = word.chars();
- let first = chars.next();
- // Unicode allows for a single character to become multiple characters when converting between cases.
- first
- .into_iter()
- .flat_map(|c| c.to_uppercase())
- .chain(chars.flat_map(|c| c.to_lowercase()))
- })
- .collect()
-}