├── .gitignore ├── Cargo.toml ├── publish.sh ├── examples ├── src │ ├── fail_tests │ │ ├── double_mutable_borrow.stderr │ │ ├── borrow_before_declaration.rs │ │ ├── double_mutable_borrow.rs │ │ ├── borrow_before_declaration.stderr │ │ ├── auto_covariant.rs │ │ ├── use_after_free.rs │ │ ├── move_ref_outside_closure.rs │ │ ├── use_after_free.stderr │ │ ├── use_moved_ref_after_free.rs │ │ ├── use_moved_ref_after_free.stderr │ │ ├── borrowchk_custom_drop.stderr │ │ ├── refuse_non_std_box.rs │ │ ├── refuse_non_std_box.stderr │ │ ├── borrowchk_external_lifetime.stderr │ │ ├── swap_refs_for_use_after_free.rs │ │ ├── borrowchk_external_lifetime.rs │ │ ├── swap_refs_for_use_after_free.stderr │ │ ├── auto_covariant.stderr │ │ ├── borrowchk_custom_drop.rs │ │ └── move_ref_outside_closure.stderr │ ├── lib.rs │ └── ok_tests.rs ├── Cargo.toml ├── LICENSE_MIT └── LICENSE_APACHE ├── ouroboros_macro ├── src │ ├── generate │ │ ├── mod.rs │ │ ├── drop.rs │ │ ├── type_asserts.rs │ │ ├── summon_checker.rs │ │ ├── struc.rs │ │ ├── derives.rs │ │ ├── into_heads.rs │ │ ├── with.rs │ │ ├── with_mut.rs │ │ ├── with_each.rs │ │ ├── constructor.rs │ │ └── try_constructor.rs │ ├── covariance_detection.rs │ ├── utils.rs │ ├── lib.rs │ ├── parse.rs │ └── info_structures.rs ├── Cargo.toml ├── LICENSE_MIT └── LICENSE_APACHE ├── ouroboros ├── Cargo.toml ├── LICENSE_MIT ├── LICENSE_APACHE └── src │ └── lib.rs ├── LICENSE_MIT ├── .github └── workflows │ └── default.yml ├── README.md └── LICENSE_APACHE /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | scratch 4 | .DS_Store -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "examples", 5 | "ouroboros", 6 | "ouroboros_macro", 7 | ] 8 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | cd ouroboros_macro 4 | cargo publish 5 | sleep 30 6 | cd ../ouroboros 7 | cargo publish 8 | sleep 30 9 | cd ../examples 10 | cargo publish 11 | -------------------------------------------------------------------------------- /examples/src/fail_tests/double_mutable_borrow.stderr: -------------------------------------------------------------------------------- 1 | error: Cannot borrow mutably twice. 2 | --> $DIR/double_mutable_borrow.rs:6:26 3 | | 4 | 6 | #[borrows(mut a, mut a)] 5 | | ^ 6 | -------------------------------------------------------------------------------- /examples/src/fail_tests/borrow_before_declaration.rs: -------------------------------------------------------------------------------- 1 | use ouroboros::self_referencing; 2 | 3 | #[self_referencing] 4 | struct S { 5 | #[borrows(a)] 6 | b: &'this i32, 7 | a: i32, 8 | } 9 | 10 | fn main() { } 11 | -------------------------------------------------------------------------------- /examples/src/fail_tests/double_mutable_borrow.rs: -------------------------------------------------------------------------------- 1 | use ouroboros::self_referencing; 2 | 3 | #[self_referencing] 4 | struct S { 5 | a: Box, 6 | #[borrows(mut a, mut a)] 7 | b: &'this i32, 8 | } 9 | 10 | fn main() { } 11 | -------------------------------------------------------------------------------- /examples/src/fail_tests/borrow_before_declaration.stderr: -------------------------------------------------------------------------------- 1 | error: Unknown identifier, make sure that it is spelled correctly and defined above the location it is borrowed. 2 | --> $DIR/borrow_before_declaration.rs:5:15 3 | | 4 | 5 | #[borrows(a)] 5 | | ^ 6 | -------------------------------------------------------------------------------- /examples/src/fail_tests/auto_covariant.rs: -------------------------------------------------------------------------------- 1 | use ouroboros::self_referencing; 2 | 3 | struct NotGuaranteedCovariant<'a> { 4 | data: &'a (), 5 | } 6 | 7 | #[self_referencing] 8 | struct Test { 9 | data: (), 10 | #[borrows(data)] 11 | field: NotGuaranteedCovariant<'this> 12 | } -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod constructor; 2 | pub mod derives; 3 | pub mod drop; 4 | pub mod into_heads; 5 | pub mod struc; 6 | pub mod summon_checker; 7 | pub mod try_constructor; 8 | pub mod type_asserts; 9 | pub mod with; 10 | pub mod with_each; 11 | pub mod with_mut; 12 | -------------------------------------------------------------------------------- /examples/src/fail_tests/use_after_free.rs: -------------------------------------------------------------------------------- 1 | use ouroboros::self_referencing; 2 | 3 | #[self_referencing] 4 | struct BoxAndRef { 5 | data: i32, 6 | #[borrows(data)] 7 | data_ref: &'this i32, 8 | } 9 | 10 | fn main() { 11 | let instance = BoxAndRefBuilder { 12 | data: 12, 13 | data_ref_builder: |dref| dref, 14 | }.build(); 15 | let data_ref = instance.with_data_ref(|dref| *dref); 16 | drop(instance); 17 | println!("{:?}", data_ref); 18 | } 19 | -------------------------------------------------------------------------------- /examples/src/fail_tests/move_ref_outside_closure.rs: -------------------------------------------------------------------------------- 1 | use ouroboros::self_referencing; 2 | 3 | #[self_referencing] 4 | struct BoxAndRef { 5 | data: i32, 6 | #[borrows(data)] 7 | data_ref: &'this i32, 8 | } 9 | 10 | fn main() { 11 | let instance = BoxAndRefBuilder { 12 | data: 12, 13 | data_ref_builder: |dref| dref, 14 | }.build(); 15 | let mut stored_ref: Option<&'static i32> = None; 16 | instance.with_data_ref(|dref| stored_ref = Some(*dref)); 17 | } 18 | -------------------------------------------------------------------------------- /examples/src/fail_tests/use_after_free.stderr: -------------------------------------------------------------------------------- 1 | error[E0505]: cannot move out of `instance` because it is borrowed 2 | --> src/fail_tests/use_after_free.rs:16:10 3 | | 4 | 15 | let data_ref = instance.with_data_ref(|dref| *dref); 5 | | ------------------------------------ borrow of `instance` occurs here 6 | 16 | drop(instance); 7 | | ^^^^^^^^ move out of `instance` occurs here 8 | 17 | println!("{:?}", data_ref); 9 | | -------- borrow later used here 10 | -------------------------------------------------------------------------------- /examples/src/fail_tests/use_moved_ref_after_free.rs: -------------------------------------------------------------------------------- 1 | use ouroboros::self_referencing; 2 | 3 | #[self_referencing] 4 | struct BoxAndRef { 5 | data: i32, 6 | #[borrows(data)] 7 | data_ref: &'this i32, 8 | } 9 | 10 | fn main() { 11 | let instance = BoxAndRefBuilder { 12 | data: 12, 13 | data_ref_builder: |dref| dref, 14 | }.build(); 15 | let mut stored_ref: Option<&i32> = None; 16 | instance.with_data_ref(|dref| stored_ref = Some(*dref)); 17 | drop(instance); 18 | println!("{:?}", stored_ref); 19 | } 20 | -------------------------------------------------------------------------------- /examples/src/fail_tests/use_moved_ref_after_free.stderr: -------------------------------------------------------------------------------- 1 | error[E0505]: cannot move out of `instance` because it is borrowed 2 | --> src/fail_tests/use_moved_ref_after_free.rs:17:10 3 | | 4 | 16 | instance.with_data_ref(|dref| stored_ref = Some(*dref)); 5 | | ------------------------------------------------------- borrow of `instance` occurs here 6 | 17 | drop(instance); 7 | | ^^^^^^^^ move out of `instance` occurs here 8 | 18 | println!("{:?}", stored_ref); 9 | | ---------- borrow later used here 10 | -------------------------------------------------------------------------------- /examples/src/fail_tests/borrowchk_custom_drop.stderr: -------------------------------------------------------------------------------- 1 | error[E0597]: `bar` does not live long enough 2 | --> src/fail_tests/borrowchk_custom_drop.rs:7:1 3 | | 4 | 7 | #[self_referencing] 5 | | ^^^^^^^^^^^^^^^^^^- 6 | | | | 7 | | | `bar` dropped here while still borrowed 8 | | | borrow might be used here, when `bar` is dropped and runs the `Drop` code for type `Bar` 9 | | borrowed value does not live long enough 10 | | 11 | = note: this error originates in the attribute macro `self_referencing` (in Nightly builds, run with -Z macro-backtrace for more info) 12 | -------------------------------------------------------------------------------- /ouroboros_macro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ouroboros_macro" 3 | version = "0.18.5" 4 | authors = ["Josh "] 5 | edition = "2018" 6 | license = "MIT OR Apache-2.0" 7 | description = "Proc macro for ouroboros crate." 8 | documentation = "https://docs.rs/ouroboros_macro" 9 | repository = "https://github.com/someguynamedjosh/ouroboros" 10 | 11 | [lib] 12 | proc-macro = true 13 | 14 | [dependencies] 15 | heck = "0.5" 16 | proc-macro2 = "1.0" 17 | proc-macro2-diagnostics = "0.10" 18 | quote = "1.0" 19 | syn = { version = "2.0", features = ["full"] } 20 | 21 | [features] 22 | std = [] 23 | -------------------------------------------------------------------------------- /ouroboros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ouroboros" 3 | version = "0.18.5" 4 | authors = ["Josh "] 5 | edition = "2018" 6 | license = "MIT OR Apache-2.0" 7 | description = "Easy, safe self-referential struct generation." 8 | readme = "../README.md" 9 | documentation = "https://docs.rs/ouroboros" 10 | repository = "https://github.com/someguynamedjosh/ouroboros" 11 | 12 | [dependencies] 13 | aliasable = "0.1.3" 14 | ouroboros_macro = { version = "0.18.5", path = "../ouroboros_macro" } 15 | static_assertions = "1.1.0" 16 | 17 | [features] 18 | default = ["std"] 19 | std = ["ouroboros_macro/std"] 20 | -------------------------------------------------------------------------------- /examples/src/fail_tests/refuse_non_std_box.rs: -------------------------------------------------------------------------------- 1 | use ouroboros::self_referencing; 2 | use std::ops::Deref; 3 | 4 | struct Box(T); 5 | 6 | impl Box { 7 | pub fn new(data: T) -> Self { 8 | Self(data) 9 | } 10 | } 11 | 12 | impl Deref for Box { 13 | type Target = T; 14 | fn deref(&self) -> &T { 15 | &self.0 16 | } 17 | } 18 | 19 | #[self_referencing] 20 | struct Simple { 21 | data: Box, 22 | #[borrows(data)] 23 | data_ref: &'this String, 24 | } 25 | 26 | fn main() { 27 | let simple = Simple::new(Box::new(format!("Hello world")), |data_ref| data_ref); 28 | } 29 | -------------------------------------------------------------------------------- /examples/src/fail_tests/refuse_non_std_box.stderr: -------------------------------------------------------------------------------- 1 | error[E0599]: no function or associated item named `is_std_box_type` found for struct `CheckIfTypeIsStd>` in the current scope 2 | --> src/fail_tests/refuse_non_std_box.rs:19:1 3 | | 4 | 19 | #[self_referencing] 5 | | ^^^^^^^^^^^^^^^^^^^ function or associated item not found in `CheckIfTypeIsStd>` 6 | | 7 | = note: the function or associated item was found for 8 | - `CheckIfTypeIsStd>` 9 | = note: this error originates in the attribute macro `self_referencing` (in Nightly builds, run with -Z macro-backtrace for more info) 10 | -------------------------------------------------------------------------------- /examples/src/fail_tests/borrowchk_external_lifetime.stderr: -------------------------------------------------------------------------------- 1 | error[E0597]: `o` does not live long enough 2 | --> src/fail_tests/borrowchk_external_lifetime.rs:3:1 3 | | 4 | 3 | #[self_referencing] 5 | | ^^^^^^^^^^^^^^^^^^- 6 | | | | 7 | | | `o` dropped here while still borrowed 8 | | borrowed value does not live long enough 9 | | argument requires that `o` is borrowed for `'a` 10 | 4 | pub struct S<'a> { 11 | | -- lifetime `'a` defined here 12 | | 13 | = note: this error originates in the attribute macro `self_referencing` (in Nightly builds, run with -Z macro-backtrace for more info) 14 | -------------------------------------------------------------------------------- /examples/src/fail_tests/swap_refs_for_use_after_free.rs: -------------------------------------------------------------------------------- 1 | use ouroboros::self_referencing; 2 | 3 | pub struct PrintStrRef<'a>(&'a str); 4 | 5 | impl Drop for PrintStrRef<'_> { 6 | fn drop(&mut self) { 7 | println!("Dropping {}", self.0); 8 | } 9 | } 10 | 11 | #[self_referencing] 12 | pub struct Tricky { 13 | data1: String, 14 | #[borrows(data1)] 15 | #[covariant] 16 | ref1: PrintStrRef<'this>, 17 | data2: String, 18 | } 19 | 20 | fn main() { 21 | let mut t = Tricky::new( 22 | "A".to_owned(), 23 | |a| PrintStrRef(a), 24 | "B".to_owned(), 25 | ); 26 | t.with_mut(|fields| { 27 | *fields.ref1 = PrintStrRef(fields.data2); 28 | }); 29 | drop(t); 30 | } 31 | -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/drop.rs: -------------------------------------------------------------------------------- 1 | use crate::info_structures::StructInfo; 2 | use proc_macro2::TokenStream; 3 | use quote::quote; 4 | use syn::Error; 5 | 6 | pub fn create_drop_impl(info: &StructInfo) -> Result { 7 | let ident = &info.ident; 8 | let generics = &info.generics; 9 | let generic_args = info.generic_arguments(); 10 | 11 | let mut where_clause = quote! {}; 12 | if let Some(clause) = &generics.where_clause { 13 | where_clause = quote! { #clause }; 14 | } 15 | Ok(quote! { 16 | impl #generics ::core::ops::Drop for #ident<#(#generic_args,)*> #where_clause { 17 | fn drop(&mut self) { 18 | unsafe { self.actual_data.assume_init_drop() }; 19 | } 20 | } 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /examples/src/fail_tests/borrowchk_external_lifetime.rs: -------------------------------------------------------------------------------- 1 | use ouroboros::self_referencing; 2 | 3 | #[self_referencing] 4 | pub struct S<'a> { 5 | o: String, 6 | 7 | #[borrows(o)] 8 | c: &'a &'this (), 9 | 10 | e: &'a (), 11 | } 12 | 13 | fn main() { 14 | #[allow(clippy::needless_lifetimes)] 15 | fn bar<'a>(x: &'a ()) -> &'a str { 16 | let s = SBuilder { 17 | o: "Hello World!".to_owned(), 18 | c_builder: |_| &&(), 19 | e: x, 20 | } 21 | .build(); 22 | let r = s.with(f); 23 | return r; 24 | 25 | fn f<'outer_borrow, 'this, 'a>( 26 | b: ouroboros_impl_s::BorrowedFields<'outer_borrow, 'this, 'a>, 27 | ) -> &'a str { 28 | b.o 29 | } 30 | } 31 | 32 | let s = bar(&()); 33 | println!("{}", s); // use-after-free :-) 34 | } 35 | -------------------------------------------------------------------------------- /examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ouroboros_examples" 3 | version = "0.18.5" 4 | authors = ["Josh "] 5 | edition = "2018" 6 | license = "MIT OR Apache-2.0" 7 | description = "Examples for the ouroboros crate." 8 | documentation = "https://docs.rs/ouroboros_examples" 9 | repository = "https://github.com/someguynamedjosh/ouroboros" 10 | 11 | [package.metadata.docs.rs] 12 | rustdoc-args = ["--document-private-items"] 13 | 14 | [lib] 15 | 16 | [features] 17 | default = ["std"] 18 | # Disables any tests that are not compatible or not intended to run under Miri 19 | miri = [] 20 | std = [] 21 | 22 | [dependencies] 23 | ouroboros = { version = "0.18.5", path = "../ouroboros" } 24 | tokio = { version = "1.27.0", features = [ "macros", "rt" ], optional = true } 25 | 26 | [dev-dependencies] 27 | rustversion = "1.0.11" 28 | trybuild = "=1.0.85" 29 | tokio = { version = "1.25.0", features = [ "macros", "rt" ] } 30 | -------------------------------------------------------------------------------- /examples/src/fail_tests/swap_refs_for_use_after_free.stderr: -------------------------------------------------------------------------------- 1 | error[E0597]: `t` does not live long enough 2 | --> src/fail_tests/swap_refs_for_use_after_free.rs:26:5 3 | | 4 | 26 | / t.with_mut(|fields| { 5 | 27 | | *fields.ref1 = PrintStrRef(fields.data2); 6 | 28 | | }); 7 | | | ^ 8 | | | | 9 | | |______borrowed value does not live long enough 10 | | argument requires that `t` is borrowed for `'static` 11 | 29 | drop(t); 12 | 30 | } 13 | | - `t` dropped here while still borrowed 14 | 15 | error[E0505]: cannot move out of `t` because it is borrowed 16 | --> src/fail_tests/swap_refs_for_use_after_free.rs:29:10 17 | | 18 | 26 | / t.with_mut(|fields| { 19 | 27 | | *fields.ref1 = PrintStrRef(fields.data2); 20 | 28 | | }); 21 | | | - 22 | | | | 23 | | |______borrow of `t` occurs here 24 | | argument requires that `t` is borrowed for `'static` 25 | 29 | drop(t); 26 | | ^ move out of `t` occurs here 27 | -------------------------------------------------------------------------------- /examples/src/fail_tests/auto_covariant.stderr: -------------------------------------------------------------------------------- 1 | error: Ouroboros cannot automatically determine if this type is covariant. 2 | 3 | As an example, a Box<&'this ()> is covariant because it can be used as a 4 | Box<&'smaller ()> for any lifetime smaller than 'this. In contrast, 5 | a Fn(&'this ()) is not covariant because it cannot be used as a 6 | Fn(&'smaller ()). In general, values that are safe to use with smaller 7 | lifetimes than they were defined with are covariant, breaking this 8 | guarantee means the value is not covariant. 9 | 10 | To resolve this error, add #[covariant] or #[not_covariant] to the field. 11 | --> src/fail_tests/auto_covariant.rs:11:12 12 | | 13 | 11 | field: NotGuaranteedCovariant<'this> 14 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 15 | 16 | error[E0601]: `main` function not found in crate `$CRATE` 17 | --> src/fail_tests/auto_covariant.rs:12:2 18 | | 19 | 12 | } 20 | | ^ consider adding a `main` function to `$DIR/src/fail_tests/auto_covariant.rs` 21 | -------------------------------------------------------------------------------- /examples/src/fail_tests/borrowchk_custom_drop.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | 3 | use ouroboros::self_referencing; 4 | 5 | struct Bar<'a>(RefCell<(Option<&'a Bar<'a>>, String)>); 6 | 7 | #[self_referencing] 8 | struct Foo { 9 | owner: (), 10 | #[borrows(owner)] 11 | #[not_covariant] 12 | bar: Bar<'this>, 13 | #[borrows(bar)] 14 | #[not_covariant] 15 | baz: &'this Bar<'this>, 16 | } 17 | 18 | impl Drop for Bar<'_> { 19 | fn drop(&mut self) { 20 | let r1 = self.0.get_mut(); 21 | let string_ref_1 = &mut r1.1; 22 | let mut r2 = r1.0.unwrap().0.borrow_mut(); 23 | let string_ref_2 = &mut r2.1; 24 | 25 | let s = &string_ref_1[..]; 26 | string_ref_2.clear(); 27 | string_ref_2.shrink_to_fit(); 28 | println!("{}", s); // prints garbage :-), use-after free 29 | } 30 | } 31 | 32 | fn main() { 33 | Foo::new( 34 | (), 35 | |_| Bar(RefCell::new((None, "Hello World!".to_owned()))), 36 | |bar| { 37 | bar.0.borrow_mut().0 = Some(bar); 38 | bar 39 | }, 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE_MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Josh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /examples/LICENSE_MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Josh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /ouroboros/LICENSE_MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Josh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /ouroboros_macro/LICENSE_MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Josh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /examples/src/fail_tests/move_ref_outside_closure.stderr: -------------------------------------------------------------------------------- 1 | error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements 2 | --> src/fail_tests/move_ref_outside_closure.rs:16:48 3 | | 4 | 16 | instance.with_data_ref(|dref| stored_ref = Some(*dref)); 5 | | ^^^^^^^^^^^ 6 | | 7 | note: first, the lifetime cannot outlive the anonymous lifetime #1 defined here... 8 | --> src/fail_tests/move_ref_outside_closure.rs:16:28 9 | | 10 | 16 | instance.with_data_ref(|dref| stored_ref = Some(*dref)); 11 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 | note: ...so that reference does not outlive borrowed content 13 | --> src/fail_tests/move_ref_outside_closure.rs:16:53 14 | | 15 | 16 | instance.with_data_ref(|dref| stored_ref = Some(*dref)); 16 | | ^^^^^ 17 | = note: but, the lifetime must be valid for the static lifetime... 18 | note: ...so that the expression is assignable 19 | --> src/fail_tests/move_ref_outside_closure.rs:16:48 20 | | 21 | 16 | instance.with_data_ref(|dref| stored_ref = Some(*dref)); 22 | | ^^^^^^^^^^^ 23 | = note: expected `Option<&'static i32>` 24 | found `Option<&i32>` 25 | -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/type_asserts.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | use quote::{format_ident, quote}; 3 | use syn::GenericParam; 4 | 5 | use crate::{ 6 | covariance_detection::apparent_std_container_type, info_structures::StructInfo, 7 | utils::replace_this_with_lifetime, 8 | }; 9 | 10 | pub fn make_type_asserts(info: &StructInfo) -> TokenStream { 11 | let mut checks = Vec::new(); 12 | let fake_lifetime = if let Some(GenericParam::Lifetime(param)) = info.generic_params().first() { 13 | param.lifetime.ident.clone() 14 | } else { 15 | format_ident!("static") 16 | }; 17 | for field in &info.fields { 18 | let field_type = &field.typ; 19 | if let Some((std_type, _eltype)) = apparent_std_container_type(field_type) { 20 | let checker_name = match std_type { 21 | "Box" => "is_std_box_type", 22 | "Arc" => "is_std_arc_type", 23 | "Rc" => "is_std_rc_type", 24 | _ => unreachable!(), 25 | }; 26 | let checker_name = format_ident!("{}", checker_name); 27 | let static_field_type = 28 | replace_this_with_lifetime(quote! { #field_type }, fake_lifetime.clone()); 29 | checks.push(quote! { 30 | ::ouroboros::macro_help::CheckIfTypeIsStd::<#static_field_type>::#checker_name(); 31 | }); 32 | } 33 | } 34 | let generic_params = info.generic_params(); 35 | let generic_where = &info.generics.where_clause; 36 | quote! { 37 | fn type_asserts <#generic_params>() #generic_where { 38 | #(#checks)* 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.github/workflows/default.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | RUST: ["1.63", stable, beta, nightly] 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Set Rust version 21 | run: rustup default ${{ matrix.RUST }} 22 | - name: Build 23 | run: cargo build --verbose 24 | - name: Run tests 25 | run: cargo test --verbose 26 | 27 | no-std-test: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v4 31 | - name: Build 32 | run: cargo build --verbose --no-default-features 33 | - name: Check under no_std 34 | run: | 35 | # aarch64-unknown-none is Tier 2, has no `std`, but does have atomic pointers. 36 | rustup target add aarch64-unknown-none 37 | cargo check --verbose --target aarch64-unknown-none --no-default-features 38 | 39 | miri-test: 40 | runs-on: ubuntu-latest 41 | steps: 42 | - uses: actions/checkout@v4 43 | - name: Setup MIRI-Compatible Toolchain 44 | run: | 45 | MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) 46 | echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" 47 | rustup set profile minimal 48 | rustup default "$MIRI_NIGHTLY" 49 | rustup component add miri 50 | - name: Run tests with MIRI 51 | working-directory: examples 52 | run: cargo miri test --features="miri" 53 | -------------------------------------------------------------------------------- /examples/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | extern crate alloc; 4 | use alloc::boxed::Box; 5 | 6 | use ouroboros::self_referencing; 7 | 8 | #[cfg(test)] 9 | mod ok_tests; 10 | 11 | pub struct Ext<'this, T, const REV: bool>(&'this Box); 12 | 13 | #[self_referencing(pub_extras)] 14 | pub struct WithConstParam { 15 | data: core::cell::RefCell, 16 | #[borrows(data)] 17 | #[not_covariant] 18 | dref: Option>>, 19 | } 20 | 21 | #[self_referencing] 22 | /// A simple struct which contains an `i32` and a `&'this i32`. 23 | pub struct DataAndRef { 24 | data: i32, 25 | #[borrows(data)] 26 | data_ref: &'this i32, 27 | } 28 | 29 | #[self_referencing()] 30 | #[allow(clippy::redundant_allocation)] 31 | /// A chain of references, where c references b which references a. 32 | pub struct Chain { 33 | a: i32, 34 | #[borrows(a)] 35 | b: &'this i32, 36 | #[borrows(b)] 37 | c: &'this i32, 38 | } 39 | 40 | #[self_referencing] 41 | /// The example provided in the documentation. 42 | pub struct DocumentationExample { 43 | int_data: i32, 44 | float_data: f32, 45 | #[borrows(int_data)] 46 | int_reference: &'this i32, 47 | #[borrows(mut float_data)] 48 | float_reference: &'this mut f32, 49 | } 50 | 51 | #[self_referencing(no_doc)] 52 | /// This struct is created using `#[self_referencing(no_doc)]` so the generated methods and 53 | /// builders are hidden from documentation. 54 | pub struct Undocumented { 55 | data: Box, 56 | #[borrows(data)] 57 | data_ref: &'this i32, 58 | } 59 | 60 | /// This struct demonstrates how visibility can be controlled. The struct 61 | /// is defined with the following code: 62 | /// ```rust 63 | /// # use ouroboros::self_referencing; 64 | /// #[self_referencing(pub_extras)] 65 | /// pub struct Visibility { 66 | /// private_field: Box, 67 | /// #[borrows(private_field)] 68 | /// pub public_field: &'this i32, 69 | /// #[borrows(private_field)] 70 | /// pub(crate) pub_crate_field: &'this i32, 71 | /// } 72 | /// ``` 73 | /// By using `pub_extras`, the visibility of items not related to any particular 74 | /// field like `with_mut` or `VisibilityBuilder` is made public to match the 75 | /// visibility of the original struct definition. Without adding this option, 76 | /// these items would only be visible in the module where the struct is 77 | /// declared. 78 | #[self_referencing(pub_extras)] 79 | pub struct Visibility { 80 | private_field: Box, 81 | #[borrows(private_field)] 82 | pub public_field: &'this i32, 83 | #[borrows(private_field)] 84 | pub(crate) pub_crate_field: &'this i32, 85 | } 86 | -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/summon_checker.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | use quote::quote; 3 | use syn::Error; 4 | 5 | use crate::info_structures::{ArgType, BuilderType, StructInfo}; 6 | 7 | pub fn generate_checker_summoner(info: &StructInfo) -> Result { 8 | let mut code: Vec = Vec::new(); 9 | let mut params: Vec = Vec::new(); 10 | let mut value_consumers: Vec = Vec::new(); 11 | let mut template_consumers: Vec = Vec::new(); 12 | for field in &info.fields { 13 | let field_name = &field.name; 14 | 15 | let arg_type = field.make_constructor_arg_type(info, BuilderType::Sync)?; 16 | if let ArgType::Plain(plain_type) = arg_type { 17 | // No fancy builder function, we can just move the value directly into the struct. 18 | params.push(quote! { #field_name: #plain_type }); 19 | } else if let ArgType::TraitBound(bound_type) = arg_type { 20 | // Trait bounds are much trickier. We need a special syntax to accept them in the 21 | // constructor, and generic parameters need to be added to the builder struct to make 22 | // it work. 23 | let builder_name = field.builder_name(); 24 | params.push(quote! { #builder_name : impl #bound_type }); 25 | let mut builder_args = Vec::new(); 26 | for (_, borrow) in field.borrows.iter().enumerate() { 27 | let borrowed_name = &info.fields[borrow.index].name; 28 | if borrow.mutable { 29 | builder_args.push(quote! { &mut #borrowed_name }); 30 | } else { 31 | builder_args.push(quote! { &#borrowed_name }); 32 | } 33 | } 34 | code.push(quote! { let #field_name = #builder_name (#(#builder_args),*); }); 35 | } 36 | if field.is_mutably_borrowed() { 37 | code.push(quote! { let mut #field_name = #field_name; }); 38 | } else { 39 | code.push(quote! { let #field_name = #field_name; }); 40 | value_consumers.push(quote! { #field_name: &#field_name }); 41 | } 42 | } 43 | for (_ty, ident) in info.generic_consumers() { 44 | template_consumers.push(quote! { #ident: ::core::marker::PhantomData }); 45 | } 46 | let generic_params = info.generic_params(); 47 | let where_clause = &info.generics.where_clause; 48 | let borrowed_generic_params_inferred = info.borrowed_generic_params_inferred(); 49 | Ok(quote! { 50 | fn check_if_okay_according_to_checkers<#generic_params>( 51 | #(#params,)* 52 | ) 53 | #where_clause 54 | { 55 | #(#code;)* 56 | BorrowedFields::#borrowed_generic_params_inferred { 57 | #(#value_consumers,)* 58 | #(#template_consumers,)* 59 | }; 60 | } 61 | }) 62 | } 63 | -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/struc.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | info_structures::StructInfo, 3 | utils::{self, replace_this_with_lifetime}, 4 | }; 5 | use proc_macro2::TokenStream; 6 | use quote::quote; 7 | use syn::Error; 8 | 9 | /// Creates the struct that will actually store the data. 10 | pub fn create_actual_struct_def(info: &StructInfo) -> Result { 11 | let visibility = utils::submodule_contents_visibility(&info.vis); 12 | let mut fields = Vec::new(); 13 | for (ty, ident) in info.generic_consumers() { 14 | fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> }); 15 | } 16 | let generic_params = info.generic_params(); 17 | let generic_args = info.generic_arguments(); 18 | let generic_where = &info.generics.where_clause; 19 | let ident = &info.ident; 20 | let internal_ident = &info.internal_ident; 21 | Ok(quote! { 22 | #[repr(transparent)] 23 | #visibility struct #ident <#generic_params> #generic_where { 24 | actual_data: ::core::mem::MaybeUninit<#internal_ident<#(#generic_args),*>>, 25 | } 26 | }) 27 | } 28 | 29 | /// Creates a struct with fields like the original struct. Instances of the 30 | /// "actual" struct are reinterpreted as instances of the "internal" struct 31 | /// whenever data needs to be accessed. (This gets around the problem that 32 | /// references passed to functions must be valid through the entire function, 33 | /// but references *created* inside a function can be considered invalid 34 | /// whenever, even during the duration of the function.) 35 | pub fn create_internal_struct_def(info: &StructInfo) -> Result { 36 | let ident = &info.internal_ident; 37 | let generics = &info.generics; 38 | 39 | let field_defs: Vec<_> = info 40 | .fields 41 | .iter() 42 | // Reverse the order of all fields. We ensure that items in the struct are only dependent 43 | // on references to items above them. Rust drops items in a struct in forward declaration order. 44 | // This would cause parents being dropped before children, necessitating the reversal. 45 | .rev() 46 | .map(|field| { 47 | let name = &field.name; 48 | let ty = field.stored_type(); 49 | quote! { 50 | #[doc(hidden)] 51 | #name: #ty 52 | } 53 | }) 54 | .collect(); 55 | 56 | // Create the new struct definition. 57 | let mut where_clause = quote! {}; 58 | if let Some(clause) = &generics.where_clause { 59 | where_clause = quote! { #clause }; 60 | } 61 | let def = quote! { 62 | struct #ident #generics #where_clause { 63 | #(#field_defs),* 64 | } 65 | }; 66 | 67 | // Finally, replace the fake 'this lifetime with the one we found. 68 | let fake_lifetime = info.fake_lifetime(); 69 | let def = replace_this_with_lifetime(quote! { #def }, fake_lifetime.clone()); 70 | 71 | Ok(def) 72 | } 73 | -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/derives.rs: -------------------------------------------------------------------------------- 1 | use crate::info_structures::{Derive, StructInfo}; 2 | use proc_macro2::TokenStream; 3 | use quote::quote; 4 | use syn::{Error, GenericParam, TypeParamBound}; 5 | 6 | fn add_trait_bound(param: &GenericParam, bound: &TypeParamBound) -> GenericParam { 7 | let mut new = param.clone(); 8 | 9 | if let GenericParam::Type(t) = &mut new { 10 | t.bounds.push(bound.clone()) 11 | } 12 | 13 | new 14 | } 15 | 16 | fn impl_trait(info: &StructInfo, trait_name: TypeParamBound, body: TokenStream) -> TokenStream { 17 | let generic_params = info.generic_params(); 18 | let generic_params = generic_params 19 | .into_iter() 20 | .map(|i| add_trait_bound(i, &trait_name)) 21 | .collect::>(); 22 | let generic_args = info.generic_arguments(); 23 | let generic_where = &info.generics.where_clause; 24 | let struct_name = &info.ident; 25 | quote! { 26 | impl <#(#generic_params),*> #trait_name for #struct_name <#(#generic_args),*> #generic_where { 27 | #body 28 | } 29 | } 30 | } 31 | 32 | fn impl_debug(info: &StructInfo) -> Result { 33 | let fields = info 34 | .fields 35 | .iter() 36 | .filter(|field| !field.is_mutably_borrowed()) 37 | .map(|field| { 38 | let name = &field.name; 39 | quote! { 40 | field(stringify!(#name), &safe_self.#name) 41 | } 42 | }) 43 | .collect::>(); 44 | let trait_name = syn::parse_quote! { ::core::fmt::Debug }; 45 | let struct_name = &info.ident; 46 | let body = quote! { 47 | fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { 48 | self.with(|safe_self| { 49 | f.debug_struct(stringify!(#struct_name)) 50 | #(.#fields)* 51 | .finish() 52 | }) 53 | } 54 | }; 55 | Ok(impl_trait(info, trait_name, body)) 56 | } 57 | 58 | fn impl_partial_eq(info: &StructInfo) -> Result { 59 | let fields = info 60 | .fields 61 | .iter() 62 | .filter(|field| !field.is_mutably_borrowed()) 63 | .map(|field| { 64 | let name = &field.name; 65 | quote! { 66 | &*safe_self.#name == &*safe_other.#name 67 | } 68 | }) 69 | .collect::>(); 70 | let trait_name = syn::parse_quote! { ::core::cmp::PartialEq }; 71 | let body = quote! { 72 | fn eq(&self, other: &Self) -> bool { 73 | self.with(|safe_self| { 74 | other.with(|safe_other| { 75 | #(#fields)&&* 76 | }) 77 | }) 78 | } 79 | }; 80 | Ok(impl_trait(info, trait_name, body)) 81 | } 82 | 83 | fn impl_eq(info: &StructInfo) -> Result { 84 | let trait_name = syn::parse_quote! { ::core::cmp::Eq }; 85 | let body = quote! {}; 86 | Ok(impl_trait(info, trait_name, body)) 87 | } 88 | 89 | pub fn create_derives(info: &StructInfo) -> Result { 90 | let mut impls = Vec::new(); 91 | for derive in &info.derives { 92 | match derive { 93 | Derive::Debug => impls.push(impl_debug(info)?), 94 | Derive::PartialEq => impls.push(impl_partial_eq(info)?), 95 | Derive::Eq => impls.push(impl_eq(info)?), 96 | } 97 | } 98 | Ok(quote! { #(#impls)* }) 99 | } 100 | -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/into_heads.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | use quote::quote; 3 | 4 | use crate::info_structures::{Options, StructInfo}; 5 | 6 | /// Returns the Heads struct and a function to convert the original struct into a Heads instance. 7 | pub fn make_into_heads(info: &StructInfo, options: Options) -> (TokenStream, TokenStream) { 8 | let visibility = if options.do_pub_extras { 9 | info.vis.clone() 10 | } else { 11 | syn::parse_quote! { pub(super) } 12 | }; 13 | let mut code = Vec::new(); 14 | let mut field_initializers = Vec::new(); 15 | let mut head_fields = Vec::new(); 16 | let internal_struct = &info.internal_ident; 17 | // Drop everything in the reverse order of what it was declared in. Fields that come later 18 | // are only dependent on fields that came before them. 19 | for field in info.fields.iter().rev() { 20 | let field_name = &field.name; 21 | if field.self_referencing { 22 | // Heads are fields that do not borrow anything. 23 | code.push(quote! { ::core::mem::drop(this.#field_name); }); 24 | } else { 25 | code.push(quote! { let #field_name = this.#field_name; }); 26 | if field.is_borrowed() { 27 | field_initializers 28 | .push(quote! { #field_name: ::ouroboros::macro_help::unbox(#field_name) }); 29 | } else { 30 | field_initializers.push(quote! { #field_name }); 31 | } 32 | let field_type = &field.typ; 33 | head_fields.push(quote! { #visibility #field_name: #field_type }); 34 | } 35 | } 36 | for (ty, ident) in info.generic_consumers() { 37 | head_fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> }); 38 | field_initializers.push(quote! { #ident: ::core::marker::PhantomData }); 39 | } 40 | let documentation = format!( 41 | concat!( 42 | "A struct which contains only the ", 43 | "[head fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) of [`{0}`]({0})." 44 | ), 45 | info.ident.to_string() 46 | ); 47 | let generic_params = info.generic_params(); 48 | let generic_where = &info.generics.where_clause; 49 | let heads_struct_def = quote! { 50 | #[doc=#documentation] 51 | #visibility struct Heads <#generic_params> #generic_where { 52 | #(#head_fields),* 53 | } 54 | }; 55 | let documentation = concat!( 56 | "This function drops all internally referencing fields and returns only the ", 57 | "[head fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) of this struct." 58 | ).to_owned(); 59 | 60 | let documentation = if !options.do_no_doc { 61 | quote! { 62 | #[doc=#documentation] 63 | } 64 | } else { 65 | quote! { #[doc(hidden)] } 66 | }; 67 | 68 | let generic_args = info.generic_arguments(); 69 | let into_heads_fn = quote! { 70 | #documentation 71 | #[allow(clippy::drop_ref)] 72 | #[allow(clippy::drop_copy)] 73 | #[allow(clippy::drop_non_drop)] 74 | #visibility fn into_heads(self) -> Heads<#(#generic_args),*> { 75 | let this_ptr = &self as *const _; 76 | let this: #internal_struct<#(#generic_args),*> = unsafe { ::core::mem::transmute_copy(&*this_ptr) }; 77 | ::core::mem::forget(self); 78 | #(#code)* 79 | Heads { 80 | #(#field_initializers),* 81 | } 82 | } 83 | }; 84 | (heads_struct_def, into_heads_fn) 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ouroboros 2 | 3 | [![Ouroboros on Crates.IO](https://img.shields.io/crates/v/ouroboros)](https://crates.io/crates/ouroboros) 4 | [![Documentation](https://img.shields.io/badge/documentation-link-success)](https://docs.rs/ouroboros) 5 | 6 | Easy self-referential struct generation for Rust. 7 | Dual licensed under MIT / Apache 2.0. 8 | 9 | ```rust 10 | use ouroboros::self_referencing; 11 | 12 | #[self_referencing] 13 | struct MyStruct { 14 | int_data: i32, 15 | float_data: f32, 16 | #[borrows(int_data)] 17 | // the 'this lifetime is created by the #[self_referencing] macro 18 | // and should be used on all references marked by the #[borrows] macro 19 | int_reference: &'this i32, 20 | #[borrows(mut float_data)] 21 | float_reference: &'this mut f32, 22 | } 23 | 24 | fn main() { 25 | // The builder is created by the #[self_referencing] macro 26 | // and is used to create the struct 27 | let mut my_value = MyStructBuilder { 28 | int_data: 42, 29 | float_data: 3.14, 30 | 31 | // Note that the name of the field in the builder 32 | // is the name of the field in the struct + `_builder` 33 | // ie: {field_name}_builder 34 | // the closure that assigns the value for the field will be passed 35 | // a reference to the field(s) defined in the #[borrows] macro 36 | 37 | int_reference_builder: |int_data: &i32| int_data, 38 | float_reference_builder: |float_data: &mut f32| float_data, 39 | }.build(); 40 | 41 | // The fields in the original struct can not be accessed directly 42 | // The builder creates accessor methods which are called borrow_{field_name}() 43 | 44 | // Prints 42 45 | println!("{:?}", my_value.borrow_int_data()); 46 | // Prints 3.14 47 | println!("{:?}", my_value.borrow_float_reference()); 48 | // Sets the value of float_data to 84.0 49 | my_value.with_mut(|fields| { 50 | **fields.float_reference = (**fields.int_reference as f32) * 2.0; 51 | }); 52 | 53 | // We can hold on to this reference... 54 | let int_ref = *my_value.borrow_int_reference(); 55 | println!("{:?}", *int_ref); 56 | // As long as the struct is still alive. 57 | drop(my_value); 58 | // This will cause an error! 59 | // println!("{:?}", *int_ref); 60 | } 61 | ``` 62 | 63 | Since the macro this crate provides adds lots of public functions to structs it is used on (each wrapping a particular unsafe operation in a safe way), it is not recommended to use this macro on types exposed to users of a library. Instead, it is expected that this macro will be used on an internal struct, then wrapped with a friendly struct that the library exports: 64 | 65 | ```rust 66 | // The extra wrapper methods are only added to this struct. 67 | #[self_referencing] 68 | struct Internal { 69 | // ... 70 | } 71 | 72 | // This struct is free to provide a nicer interface that is not polluted by the 73 | // extra functions #[self_referencing] adds. 74 | pub struct Friendly { 75 | internal: Internal, 76 | } 77 | 78 | impl Friendly { 79 | pub fn new(/* ... */) -> Self { 80 | // Complicated code here... 81 | } 82 | 83 | pub fn do_the_thing(&self) -> T { 84 | // More complicated code here.... 85 | } 86 | } 87 | ``` 88 | 89 | While this crate is `no_std` compatible, it still requires the `alloc` crate. 90 | 91 | Version notes: 92 | - Version `0.18.0` now correctly refuses to compile unsound usages of `with_mut`, but requires Rust 1.63 or later. 93 | - Version `0.17.0` reintroduces type parameter support, but requires at least 94 | version 1.60 of the Rust toolchain. 95 | - Version `0.16.0` fixes a potential soundness issue but removes template 96 | parameter support. 97 | - Version `0.13.0` and later contain checks for additional situations which 98 | cause undefined behavior if not caught. 99 | - Version `0.11.0` and later place restrictions on derive macros, earlier 100 | versions allowed using them in ways which could lead to undefined behavior if 101 | not used properly. 102 | - Version `0.10.0` and later automatically box every field. This is done 103 | to prevent undefined behavior, but has the side effect of making the library 104 | easier to work with. 105 | 106 | Tests are located in the examples/ folder because they need to be in a crate 107 | outside of `ouroboros` for the `self_referencing` macro to work properly. 108 | -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/with.rs: -------------------------------------------------------------------------------- 1 | use crate::info_structures::{FieldType, Options, StructInfo}; 2 | use proc_macro2::{Span, TokenStream}; 3 | use quote::quote; 4 | use syn::{Error, Lifetime, WhereClause}; 5 | 6 | pub fn make_with_all_function( 7 | info: &StructInfo, 8 | options: Options, 9 | ) -> Result<(TokenStream, TokenStream), Error> { 10 | let visibility = if options.do_pub_extras { 11 | info.vis.clone() 12 | } else { 13 | syn::parse_quote! { pub(super) } 14 | }; 15 | let mut fields = Vec::new(); 16 | let mut field_assignments = Vec::new(); 17 | // I don't think the reverse is necessary but it does make the expanded code more uniform. 18 | for field in info.fields.iter().rev() { 19 | let field_name = &field.name; 20 | let field_type = &field.typ; 21 | if field.field_type == FieldType::Tail { 22 | fields.push(quote! { #visibility #field_name: &'outer_borrow #field_type }); 23 | field_assignments.push(quote! { #field_name: &this.#field_name }); 24 | } else if field.field_type == FieldType::Borrowed { 25 | let ass = quote! { #field_name: unsafe { 26 | ::ouroboros::macro_help::change_lifetime( 27 | &*this.#field_name 28 | ) 29 | } }; 30 | fields.push(quote! { #visibility #field_name: &'this #field_type }); 31 | field_assignments.push(ass.clone()); 32 | } else if field.field_type == FieldType::BorrowedMut { 33 | // Add nothing because we cannot borrow something that has already been mutably 34 | // borrowed. 35 | } 36 | } 37 | 38 | for (ty, ident) in info.generic_consumers() { 39 | fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> }); 40 | field_assignments.push(quote! { #ident: ::core::marker::PhantomData }); 41 | } 42 | let new_generic_params = info.borrowed_generic_params(); 43 | let new_generic_args = info.borrowed_generic_arguments(); 44 | 45 | let struct_documentation = format!( 46 | concat!( 47 | "A struct for holding immutable references to all ", 48 | "[tail and immutably borrowed fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) in an instance of ", 49 | "[`{0}`]({0})." 50 | ), 51 | info.ident.to_string() 52 | ); 53 | let ltname = format!("'{}", info.fake_lifetime()); 54 | let lifetime = Lifetime::new(<name, Span::call_site()); 55 | let generic_where = if let Some(clause) = &info.generics.where_clause { 56 | let mut clause = clause.clone(); 57 | let extra: WhereClause = syn::parse_quote! { where #lifetime: 'this }; 58 | clause 59 | .predicates 60 | .push(extra.predicates.first().unwrap().clone()); 61 | let extra: WhereClause = syn::parse_quote! { where 'this: 'outer_borrow }; 62 | clause 63 | .predicates 64 | .push(extra.predicates.first().unwrap().clone()); 65 | clause 66 | } else { 67 | syn::parse_quote! { where #lifetime: 'this, 'this: 'outer_borrow } 68 | }; 69 | let struct_defs = quote! { 70 | #[doc=#struct_documentation] 71 | #visibility struct BorrowedFields #new_generic_params #generic_where { #(#fields),* } 72 | }; 73 | let borrowed_fields_type = quote! { BorrowedFields<#(#new_generic_args),*> }; 74 | let documentation = concat!( 75 | "This method provides immutable references to all ", 76 | "[tail and immutably borrowed fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions).", 77 | ); 78 | let documentation = if !options.do_no_doc { 79 | quote! { 80 | #[doc=#documentation] 81 | } 82 | } else { 83 | quote! { #[doc(hidden)] } 84 | }; 85 | let fn_defs = quote! { 86 | #documentation 87 | #[inline(always)] 88 | #visibility fn with <'outer_borrow, ReturnType>( 89 | &'outer_borrow self, 90 | user: impl for<'this> ::core::ops::FnOnce(#borrowed_fields_type) -> ReturnType 91 | ) -> ReturnType { 92 | let this = unsafe { self.actual_data.assume_init_ref() }; 93 | user(BorrowedFields { 94 | #(#field_assignments),* 95 | }) 96 | } 97 | }; 98 | Ok((struct_defs, fn_defs)) 99 | } 100 | -------------------------------------------------------------------------------- /ouroboros_macro/src/covariance_detection.rs: -------------------------------------------------------------------------------- 1 | use quote::ToTokens; 2 | use syn::{GenericArgument, PathArguments, Type}; 3 | 4 | use crate::utils::uses_this_lifetime; 5 | 6 | const STD_CONTAINER_TYPES: &[&str] = &["Box", "Arc", "Rc"]; 7 | 8 | /// Returns Some((type_name, element_type)) if the provided type appears to be Box, Arc, or Rc from 9 | /// the standard library. Returns None if not. 10 | pub fn apparent_std_container_type(raw_type: &Type) -> Option<(&'static str, &Type)> { 11 | let tpath = if let Type::Path(x) = raw_type { 12 | x 13 | } else { 14 | return None; 15 | }; 16 | let segment = tpath.path.segments.last()?; 17 | let args = if let PathArguments::AngleBracketed(args) = &segment.arguments { 18 | args 19 | } else { 20 | return None; 21 | }; 22 | if args.args.len() != 1 { 23 | return None; 24 | } 25 | let arg = args.args.first().unwrap(); 26 | let eltype = if let GenericArgument::Type(x) = arg { 27 | x 28 | } else { 29 | return None; 30 | }; 31 | for type_name in STD_CONTAINER_TYPES { 32 | if segment.ident == type_name { 33 | return Some((type_name, eltype)); 34 | } 35 | } 36 | None 37 | } 38 | 39 | /// Returns Some(true or false) if the type is known to be covariant / not covariant. 40 | pub fn type_is_covariant_over_this_lifetime(ty: &syn::Type) -> Option { 41 | use syn::Type::*; 42 | // If the type never uses the 'this lifetime, we don't have to 43 | // worry about it not being covariant. 44 | if !uses_this_lifetime(ty.to_token_stream()) { 45 | return Some(true); 46 | } 47 | match ty { 48 | Array(arr) => type_is_covariant_over_this_lifetime(&arr.elem), 49 | BareFn(f) => { 50 | debug_assert!(uses_this_lifetime(f.to_token_stream())); 51 | None 52 | } 53 | Group(ty) => type_is_covariant_over_this_lifetime(&ty.elem), 54 | ImplTrait(..) => None, // Unusable in struct definition. 55 | Infer(..) => None, // Unusable in struct definition. 56 | Macro(..) => None, // We don't know what the macro will resolve to. 57 | Never(..) => None, 58 | Paren(ty) => type_is_covariant_over_this_lifetime(&ty.elem), 59 | Path(path) => { 60 | if let Some(qself) = &path.qself { 61 | if !type_is_covariant_over_this_lifetime(&qself.ty)? { 62 | return Some(false); 63 | } 64 | } 65 | let mut all_parameters_are_covariant = false; 66 | // If the type is Box, Arc, or Rc, we can assume it to be covariant. 67 | if apparent_std_container_type(ty).is_some() { 68 | all_parameters_are_covariant = true; 69 | } 70 | for segment in path.path.segments.iter() { 71 | let args = &segment.arguments; 72 | if let syn::PathArguments::AngleBracketed(args) = &args { 73 | for arg in args.args.iter() { 74 | if let syn::GenericArgument::Type(ty) = arg { 75 | if all_parameters_are_covariant { 76 | if !type_is_covariant_over_this_lifetime(ty)? { 77 | return Some(false); 78 | } 79 | } else if uses_this_lifetime(ty.to_token_stream()) { 80 | return None; 81 | } 82 | } else if let syn::GenericArgument::Lifetime(lt) = arg { 83 | if lt.ident == "this" && !all_parameters_are_covariant { 84 | return None; 85 | } 86 | } 87 | } 88 | } else if let syn::PathArguments::Parenthesized(args) = &args { 89 | for arg in args.inputs.iter() { 90 | if uses_this_lifetime(arg.to_token_stream()) { 91 | return None; 92 | } 93 | } 94 | if let syn::ReturnType::Type(_, ty) = &args.output { 95 | if uses_this_lifetime(ty.to_token_stream()) { 96 | return None; 97 | } 98 | } 99 | } 100 | } 101 | Some(true) 102 | } 103 | Ptr(ptr) => { 104 | if ptr.mutability.is_some() { 105 | Some(false) 106 | } else { 107 | type_is_covariant_over_this_lifetime(&ptr.elem) 108 | } 109 | } 110 | // Ignore the actual lifetime of the reference because Rust can automatically convert those. 111 | Reference(rf) => { 112 | if rf.mutability.is_some() { 113 | Some(!uses_this_lifetime(rf.elem.to_token_stream())) 114 | } else { 115 | type_is_covariant_over_this_lifetime(&rf.elem) 116 | } 117 | } 118 | Slice(sl) => type_is_covariant_over_this_lifetime(&sl.elem), 119 | TraitObject(..) => None, 120 | Tuple(tup) => { 121 | let mut result = Some(true); 122 | for ty in tup.elems.iter() { 123 | match type_is_covariant_over_this_lifetime(ty) { 124 | Some(true) => (), 125 | Some(false) => return Some(false), 126 | None => result = None, 127 | } 128 | } 129 | result 130 | } 131 | // As of writing this, syn parses all the types we could need. However, 132 | // just to be safe, return that we don't know if it's covariant. 133 | Verbatim(..) => None, 134 | _ => None, 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /ouroboros_macro/src/utils.rs: -------------------------------------------------------------------------------- 1 | use heck::ToSnakeCase; 2 | use proc_macro2::{Group, Ident, TokenStream, TokenTree}; 3 | use quote::{format_ident, quote}; 4 | use syn::{GenericParam, Generics, Visibility}; 5 | 6 | /// Makes phantom data definitions so that we don't get unused template parameter errors. 7 | pub fn make_generic_consumers(generics: &Generics) -> impl Iterator { 8 | generics 9 | .params 10 | .clone() 11 | .into_iter() 12 | .map(|param| match param { 13 | GenericParam::Type(ty) => { 14 | let ident = &ty.ident; 15 | ( 16 | quote! { #ident }, 17 | format_ident!( 18 | "_consume_template_type_{}", 19 | ident.to_string().to_snake_case() 20 | ), 21 | ) 22 | } 23 | GenericParam::Lifetime(lt) => { 24 | let lifetime = <.lifetime; 25 | let ident = &lifetime.ident; 26 | ( 27 | quote! { &#lifetime () }, 28 | format_ident!("_consume_template_lifetime_{}", ident), 29 | ) 30 | } 31 | // rustc don't require constants to consume, so we just skip it. 32 | GenericParam::Const(ct) => { 33 | let ident = ct.ident; 34 | ( 35 | quote! { () }, 36 | format_ident!( 37 | "_comsume_template_const_parameter_{}", 38 | ident.to_string().to_snake_case() 39 | ), 40 | ) 41 | }, 42 | }) 43 | } 44 | 45 | // Takes the generics parameters from the original struct and turns them into arguments. 46 | pub fn make_generic_arguments(generics: Vec<&GenericParam>) -> Vec { 47 | let mut arguments = Vec::new(); 48 | for generic in generics { 49 | match generic { 50 | GenericParam::Type(typ) => { 51 | let ident = &typ.ident; 52 | arguments.push(quote! { #ident }); 53 | } 54 | GenericParam::Lifetime(lt) => { 55 | let lifetime = <.lifetime; 56 | arguments.push(quote! { #lifetime }); 57 | } 58 | GenericParam::Const(ct) => { 59 | let ident = &ct.ident; 60 | arguments.push(quote! { #ident }); 61 | }, 62 | } 63 | } 64 | arguments 65 | } 66 | 67 | pub fn uses_this_lifetime(input: TokenStream) -> bool { 68 | for token in input.into_iter() { 69 | match token { 70 | TokenTree::Ident(ident) => { 71 | if ident == "this" { 72 | return true; 73 | } 74 | } 75 | TokenTree::Group(group) => { 76 | if uses_this_lifetime(group.stream()) { 77 | return true; 78 | } 79 | } 80 | _ => (), 81 | } 82 | } 83 | false 84 | } 85 | 86 | pub fn replace_this_with_lifetime(input: TokenStream, lifetime: Ident) -> TokenStream { 87 | input 88 | .into_iter() 89 | .map(|token| match &token { 90 | TokenTree::Ident(ident) => { 91 | if ident == "this" { 92 | TokenTree::Ident(lifetime.clone()) 93 | } else { 94 | token 95 | } 96 | } 97 | TokenTree::Group(group) => TokenTree::Group(Group::new( 98 | group.delimiter(), 99 | replace_this_with_lifetime(group.stream(), lifetime.clone()), 100 | )), 101 | _ => token, 102 | }) 103 | .collect() 104 | } 105 | 106 | pub fn submodule_contents_visibility(original_visibility: &Visibility) -> Visibility { 107 | match original_visibility { 108 | // inherited: allow parent of inner submodule to see 109 | Visibility::Inherited => syn::parse_quote! { pub(super) }, 110 | // restricted: add an extra super if needed 111 | Visibility::Restricted(ref restricted) => { 112 | let is_first_component_super = restricted 113 | .path 114 | .segments 115 | .first() 116 | .map(|segm| segm.ident == "super") 117 | .unwrap_or(false); 118 | if restricted.path.leading_colon.is_none() && is_first_component_super { 119 | let mut new_visibility = restricted.clone(); 120 | new_visibility.in_token = Some( 121 | restricted 122 | .in_token 123 | .unwrap_or_else(|| syn::parse_quote! { in }), 124 | ); 125 | new_visibility.path.segments = std::iter::once(syn::parse_quote! { super }) 126 | .chain(restricted.path.segments.iter().cloned()) 127 | .collect(); 128 | Visibility::Restricted(new_visibility) 129 | } else { 130 | original_visibility.clone() 131 | } 132 | } 133 | // others are absolute, can use them as-is 134 | _ => original_visibility.clone(), 135 | } 136 | } 137 | 138 | /// Functionality inspired by `Inflector`, reimplemented here to avoid the 139 | /// `regex` dependency. 140 | pub fn to_class_case(s: &str) -> String { 141 | s.split('_') 142 | .flat_map(|word| { 143 | let mut chars = word.chars(); 144 | let first = chars.next(); 145 | // Unicode allows for a single character to become multiple characters when converting between cases. 146 | first 147 | .into_iter() 148 | .flat_map(|c| c.to_uppercase()) 149 | .chain(chars.flat_map(|c| c.to_lowercase())) 150 | }) 151 | .collect() 152 | } 153 | -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/with_mut.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | info_structures::{FieldType, Options, StructInfo}, 3 | utils::{replace_this_with_lifetime, uses_this_lifetime}, 4 | }; 5 | use proc_macro2::{Span, TokenStream}; 6 | use quote::{format_ident, quote}; 7 | use syn::{Error, Lifetime, WhereClause}; 8 | 9 | pub fn make_with_all_mut_function( 10 | info: &StructInfo, 11 | options: Options, 12 | ) -> Result<(TokenStream, TokenStream), Error> { 13 | let visibility = if options.do_pub_extras { 14 | info.vis.clone() 15 | } else { 16 | syn::parse_quote! { pub(super) } 17 | }; 18 | let mut mut_fields = Vec::new(); 19 | let mut mut_field_assignments = Vec::new(); 20 | let mut lifetime_idents = Vec::new(); 21 | // I don't think the reverse is necessary but it does make the expanded code more uniform. 22 | for (index, field) in info.fields.iter().rev().enumerate() { 23 | let field_name = &field.name; 24 | let original_field_type = &field.typ; 25 | let lifetime = format_ident!("this{}", index); 26 | let field_type = replace_this_with_lifetime(quote! { #original_field_type }, lifetime.clone()); 27 | if field.field_type == FieldType::Tail { 28 | mut_fields.push(quote! { #visibility #field_name: &'outer_borrow mut #field_type }); 29 | mut_field_assignments.push(quote! { #field_name: &mut this.#field_name }); 30 | if uses_this_lifetime(quote! { #original_field_type }) { 31 | lifetime_idents.push(lifetime.clone()); 32 | } 33 | } else if field.field_type == FieldType::Borrowed { 34 | let ass = quote! { #field_name: unsafe { 35 | ::ouroboros::macro_help::change_lifetime( 36 | &*this.#field_name 37 | ) 38 | } }; 39 | let lt = Lifetime::new(&format!("'{}", lifetime), Span::call_site()); 40 | mut_fields.push(quote! { #visibility #field_name: &#lt #field_type }); 41 | mut_field_assignments.push(ass); 42 | lifetime_idents.push(lifetime.clone()); 43 | } else if field.field_type == FieldType::BorrowedMut { 44 | // Add nothing because we cannot borrow something that has already been mutably 45 | // borrowed. 46 | } 47 | } 48 | 49 | for (ty, ident) in info.generic_consumers() { 50 | mut_fields.push(quote! { #ident: ::core::marker::PhantomData<#ty> }); 51 | mut_field_assignments.push(quote! { #ident: ::core::marker::PhantomData }); 52 | } 53 | 54 | let mut new_generic_params = info.generic_params().clone(); 55 | for lt in &lifetime_idents { 56 | let lt = Lifetime::new(&format!("'{}", lt), Span::call_site()); 57 | new_generic_params.insert(0, syn::parse_quote! { #lt }); 58 | } 59 | new_generic_params.insert(0, syn::parse_quote! { 'outer_borrow }); 60 | let mut new_generic_args = info.generic_arguments(); 61 | let mut lifetimes = Vec::new(); 62 | for lt in &lifetime_idents { 63 | let lt = Lifetime::new(&format!("'{}", lt), Span::call_site()); 64 | lifetimes.push(lt.clone()); 65 | new_generic_args.insert(0, quote! { #lt }); 66 | } 67 | new_generic_args.insert(0, quote! { 'outer_borrow }); 68 | 69 | let mut_struct_documentation = format!( 70 | concat!( 71 | "A struct for holding mutable references to all ", 72 | "[tail fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) in an instance of ", 73 | "[`{0}`]({0})." 74 | ), 75 | info.ident.to_string() 76 | ); 77 | let fake_lifetime = Lifetime::new(&format!("'{}", info.fake_lifetime()), Span::call_site()); 78 | let mut generic_where = if let Some(clause) = &info.generics.where_clause { 79 | clause.clone() 80 | } else { 81 | syn::parse_quote! { where } 82 | }; 83 | for lt in &lifetime_idents { 84 | let lt = Lifetime::new(&format!("'{}", lt), Span::call_site()); 85 | let extra: WhereClause = syn::parse_quote! { where #fake_lifetime: #lt }; 86 | generic_where 87 | .predicates 88 | .extend(extra.predicates.into_iter()); 89 | } 90 | for idents in lifetime_idents.windows(2) { 91 | let lt = Lifetime::new(&format!("'{}", idents[1]), Span::call_site()); 92 | let outlives = Lifetime::new(&format!("'{}", idents[0]), Span::call_site()); 93 | let extra: WhereClause = syn::parse_quote! { where #lt: #outlives }; 94 | generic_where 95 | .predicates 96 | .extend(extra.predicates.into_iter()); 97 | } 98 | let struct_defs = quote! { 99 | #[doc=#mut_struct_documentation] 100 | #visibility struct BorrowedMutFields <#new_generic_params> #generic_where { #(#mut_fields),* } 101 | }; 102 | let borrowed_mut_fields_type = quote! { BorrowedMutFields<#(#new_generic_args),*> }; 103 | let mut_documentation = concat!( 104 | "This method provides mutable references to all ", 105 | "[tail fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions).", 106 | ); 107 | let mut_documentation = if !options.do_no_doc { 108 | quote! { 109 | #[doc=#mut_documentation] 110 | } 111 | } else { 112 | quote! { #[doc(hidden)] } 113 | }; 114 | let fn_defs = quote! { 115 | #mut_documentation 116 | #[inline(always)] 117 | #visibility fn with_mut <'outer_borrow, ReturnType>( 118 | &'outer_borrow mut self, 119 | user: impl for<#(#lifetimes),*> ::core::ops::FnOnce(#borrowed_mut_fields_type) -> ReturnType 120 | ) -> ReturnType { 121 | let this = unsafe { self.actual_data.assume_init_mut() }; 122 | user(BorrowedMutFields { 123 | #(#mut_field_assignments),* 124 | }) 125 | } 126 | }; 127 | Ok((struct_defs, fn_defs)) 128 | } 129 | -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/with_each.rs: -------------------------------------------------------------------------------- 1 | use crate::info_structures::{FieldType, Options, StructInfo}; 2 | use proc_macro2::TokenStream; 3 | use proc_macro2_diagnostics::Diagnostic; 4 | use quote::{format_ident, quote}; 5 | use syn::Error; 6 | 7 | pub enum ProcessingError { 8 | Syntax(Error), 9 | Covariance(Vec), 10 | } 11 | 12 | pub fn make_with_functions(info: &StructInfo, options: Options) -> (Vec, Vec) { 13 | let mut users = Vec::new(); 14 | let mut errors = Vec::new(); 15 | for field in &info.fields { 16 | let visibility = &field.vis; 17 | let field_name = &field.name; 18 | let field_type = &field.typ; 19 | // If the field is not a tail, we need to serve up the same kind of reference that other 20 | // fields in the struct may have borrowed to ensure safety. 21 | if field.field_type == FieldType::Tail { 22 | let user_name = format_ident!("with_{}", &field.name); 23 | let documentation = format!( 24 | concat!( 25 | "Provides an immutable reference to `{0}`. This method was generated because ", 26 | "`{0}` is a [tail field](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions)." 27 | ), 28 | field.name.to_string() 29 | ); 30 | let documentation = if !options.do_no_doc { 31 | quote! { 32 | #[doc=#documentation] 33 | } 34 | } else { 35 | quote! { #[doc(hidden)] } 36 | }; 37 | users.push(quote! { 38 | #documentation 39 | #[inline(always)] 40 | #visibility fn #user_name <'outer_borrow, ReturnType>( 41 | &'outer_borrow self, 42 | user: impl for<'this> ::core::ops::FnOnce(&'outer_borrow #field_type) -> ReturnType, 43 | ) -> ReturnType { 44 | let field = &unsafe { self.actual_data.assume_init_ref() }.#field_name; 45 | user(field) 46 | } 47 | }); 48 | if field.covariant == Some(true) { 49 | let borrower_name = format_ident!("borrow_{}", &field.name); 50 | users.push(quote! { 51 | #documentation 52 | #[inline(always)] 53 | #visibility fn #borrower_name<'this>( 54 | &'this self, 55 | ) -> &'this #field_type { 56 | &unsafe { self.actual_data.assume_init_ref() }.#field_name 57 | } 58 | }); 59 | } else if field.covariant.is_none() { 60 | errors.push(field.covariance_error()); 61 | } 62 | // If it is not borrowed at all it's safe to allow mutably borrowing it. 63 | let user_name = format_ident!("with_{}_mut", &field.name); 64 | let documentation = format!( 65 | concat!( 66 | "Provides a mutable reference to `{0}`. This method was generated because ", 67 | "`{0}` is a [tail field](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions). ", 68 | "No `borrow_{0}_mut` function was generated because Rust's borrow checker is ", 69 | "currently unable to guarantee that such a method would be used safely." 70 | ), 71 | field.name.to_string() 72 | ); 73 | let documentation = if !options.do_no_doc { 74 | quote! { 75 | #[doc=#documentation] 76 | } 77 | } else { 78 | quote! { #[doc(hidden)] } 79 | }; 80 | users.push(quote! { 81 | #documentation 82 | #[inline(always)] 83 | #visibility fn #user_name <'outer_borrow, ReturnType>( 84 | &'outer_borrow mut self, 85 | user: impl for<'this> ::core::ops::FnOnce(&'outer_borrow mut #field_type) -> ReturnType, 86 | ) -> ReturnType { 87 | let field = &mut unsafe { self.actual_data.assume_init_mut() }.#field_name; 88 | user(field) 89 | } 90 | }); 91 | } else if field.field_type == FieldType::Borrowed { 92 | let user_name = format_ident!("with_{}", &field.name); 93 | let documentation = format!( 94 | concat!( 95 | "Provides limited immutable access to `{0}`. This method was generated ", 96 | "because the contents of `{0}` are immutably borrowed by other fields." 97 | ), 98 | field.name.to_string() 99 | ); 100 | let documentation = if !options.do_no_doc { 101 | quote! { 102 | #[doc=#documentation] 103 | } 104 | } else { 105 | quote! { #[doc(hidden)] } 106 | }; 107 | users.push(quote! { 108 | #documentation 109 | #[inline(always)] 110 | #visibility fn #user_name <'outer_borrow, ReturnType>( 111 | &'outer_borrow self, 112 | user: impl for<'this> ::core::ops::FnOnce(&'outer_borrow #field_type) -> ReturnType, 113 | ) -> ReturnType { 114 | let field = &unsafe { self.actual_data.assume_init_ref() }.#field_name; 115 | user(field) 116 | } 117 | }); 118 | if field.self_referencing { 119 | if field.covariant == Some(false) { 120 | // Skip the other functions, they will cause compiler errors. 121 | continue; 122 | } else if field.covariant.is_none() { 123 | errors.push(field.covariance_error()); 124 | } 125 | } 126 | let borrower_name = format_ident!("borrow_{}", &field.name); 127 | users.push(quote! { 128 | #documentation 129 | #[inline(always)] 130 | #visibility fn #borrower_name<'this>( 131 | &'this self, 132 | ) -> &'this #field_type { 133 | &unsafe { self.actual_data.assume_init_ref() }.#field_name 134 | } 135 | }); 136 | } else if field.field_type == FieldType::BorrowedMut { 137 | // Do not generate anything because if it is borrowed mutably once, we should not be able 138 | // to get any other kinds of references to it. 139 | } 140 | } 141 | (users, errors) 142 | } 143 | -------------------------------------------------------------------------------- /ouroboros_macro/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro; 2 | 3 | mod covariance_detection; 4 | mod generate; 5 | mod info_structures; 6 | mod parse; 7 | mod utils; 8 | 9 | use crate::{ 10 | generate::{ 11 | constructor::create_builder_and_constructor, derives::create_derives, 12 | into_heads::make_into_heads, struc::create_internal_struct_def, 13 | summon_checker::generate_checker_summoner, 14 | try_constructor::create_try_builder_and_constructor, type_asserts::make_type_asserts, 15 | with::make_with_all_function, with_each::make_with_functions, 16 | }, 17 | info_structures::Options, 18 | parse::parse_struct, 19 | }; 20 | use generate::{ 21 | drop::create_drop_impl, struc::create_actual_struct_def, with_mut::make_with_all_mut_function, 22 | }; 23 | use heck::ToSnakeCase; 24 | use info_structures::BuilderType; 25 | use proc_macro::TokenStream; 26 | use proc_macro2::TokenStream as TokenStream2; 27 | use proc_macro2::TokenTree; 28 | use quote::{format_ident, quote}; 29 | use syn::{Error, ItemStruct}; 30 | 31 | fn self_referencing_impl( 32 | original_struct_def: &ItemStruct, 33 | options: Options, 34 | ) -> Result { 35 | let struct_name = &original_struct_def.ident; 36 | let mod_name = format_ident!("ouroboros_impl_{}", struct_name.to_string().to_snake_case()); 37 | let visibility = &original_struct_def.vis; 38 | 39 | let info = parse_struct(original_struct_def)?; 40 | 41 | let actual_struct_def = create_actual_struct_def(&info)?; 42 | let internal_struct_def = create_internal_struct_def(&info)?; 43 | let drop_impl = create_drop_impl(&info)?; 44 | 45 | let borrowchk_summoner = generate_checker_summoner(&info)?; 46 | 47 | let (builder_struct_name, builder_def, constructor_def) = 48 | create_builder_and_constructor(&info, options, BuilderType::Sync)?; 49 | let (async_builder_struct_name, async_builder_def, async_constructor_def) = 50 | create_builder_and_constructor(&info, options, BuilderType::Async)?; 51 | let (async_send_builder_struct_name, async_send_builder_def, async_send_constructor_def) = 52 | create_builder_and_constructor(&info, options, BuilderType::AsyncSend)?; 53 | let (try_builder_struct_name, try_builder_def, try_constructor_def) = 54 | create_try_builder_and_constructor(&info, options, BuilderType::Sync)?; 55 | let (async_try_builder_struct_name, async_try_builder_def, async_try_constructor_def) = 56 | create_try_builder_and_constructor(&info, options, BuilderType::Async)?; 57 | let ( 58 | async_send_try_builder_struct_name, 59 | async_send_try_builder_def, 60 | async_send_try_constructor_def, 61 | ) = create_try_builder_and_constructor(&info, options, BuilderType::AsyncSend)?; 62 | 63 | let (with_defs, with_errors) = make_with_functions(&info, options); 64 | let with_errors = with_errors 65 | .into_iter() 66 | .map(|err| err.emit_as_item_tokens()) 67 | .collect::>(); 68 | let (with_all_struct_def, with_all_fn_def) = make_with_all_function(&info, options)?; 69 | let (with_all_mut_struct_def, with_all_mut_fn_def) = 70 | make_with_all_mut_function(&info, options)?; 71 | let (heads_struct_def, into_heads_fn) = make_into_heads(&info, options); 72 | 73 | let impls = create_derives(&info)?; 74 | 75 | // These check that types like Box, Arc, and Rc refer to those types in the std lib and have not 76 | // been overridden. 77 | let type_asserts_def = make_type_asserts(&info); 78 | 79 | let extra_visibility = if options.do_pub_extras { 80 | visibility.clone() 81 | } else { 82 | syn::Visibility::Inherited 83 | }; 84 | 85 | let generic_params = info.generic_params(); 86 | let generic_args = info.generic_arguments(); 87 | let generic_where = &info.generics.where_clause; 88 | Ok(TokenStream::from(quote! { 89 | #[doc="Encapsulates implementation details for a self-referencing struct. This module is only visible when using --document-private-items."] 90 | mod #mod_name { 91 | use super::*; 92 | #[doc="The self-referencing struct."] 93 | #actual_struct_def 94 | #internal_struct_def 95 | #drop_impl 96 | #[allow(clippy::too_many_arguments)] //This one makes a difference, verified 97 | #borrowchk_summoner 98 | #builder_def 99 | #async_builder_def 100 | #async_send_builder_def 101 | #try_builder_def 102 | #async_try_builder_def 103 | #async_send_try_builder_def 104 | #with_all_struct_def 105 | #with_all_mut_struct_def 106 | #(#with_errors)* 107 | #heads_struct_def 108 | #impls 109 | #[allow(clippy::too_many_arguments)] //This one makes a difference, verified 110 | impl <#generic_params> #struct_name <#(#generic_args),*> #generic_where { 111 | #constructor_def 112 | #async_constructor_def 113 | #async_send_constructor_def 114 | #try_constructor_def 115 | #async_try_constructor_def 116 | #async_send_try_constructor_def 117 | #(#with_defs)* 118 | #with_all_fn_def 119 | #with_all_mut_fn_def 120 | #into_heads_fn 121 | } 122 | #type_asserts_def 123 | } 124 | #visibility use #mod_name :: #struct_name; 125 | #extra_visibility use #mod_name :: #builder_struct_name; 126 | #extra_visibility use #mod_name :: #async_builder_struct_name; 127 | #extra_visibility use #mod_name :: #async_send_builder_struct_name; 128 | #extra_visibility use #mod_name :: #try_builder_struct_name; 129 | #extra_visibility use #mod_name :: #async_try_builder_struct_name; 130 | #extra_visibility use #mod_name :: #async_send_try_builder_struct_name; 131 | })) 132 | } 133 | 134 | #[proc_macro_attribute] 135 | pub fn self_referencing(attr: TokenStream, item: TokenStream) -> TokenStream { 136 | let mut options = Options { 137 | do_no_doc: false, 138 | do_pub_extras: false, 139 | }; 140 | let mut expecting_comma = false; 141 | for token in >::into(attr).into_iter() { 142 | if let TokenTree::Ident(ident) = &token { 143 | if expecting_comma { 144 | return Error::new(token.span(), "Unexpected identifier, expected comma.") 145 | .to_compile_error() 146 | .into(); 147 | } 148 | match &ident.to_string()[..] { 149 | "no_doc" => options.do_no_doc = true, 150 | "pub_extras" => options.do_pub_extras = true, 151 | _ => { 152 | return Error::new_spanned( 153 | ident, 154 | "Unknown identifier, expected 'no_doc' or 'pub_extras'.", 155 | ) 156 | .to_compile_error() 157 | .into() 158 | } 159 | } 160 | expecting_comma = true; 161 | } else if let TokenTree::Punct(punct) = &token { 162 | if !expecting_comma { 163 | return Error::new(token.span(), "Unexpected punctuation, expected identifier.") 164 | .to_compile_error() 165 | .into(); 166 | } 167 | if punct.as_char() != ',' { 168 | return Error::new(token.span(), "Unknown punctuation, expected comma.") 169 | .to_compile_error() 170 | .into(); 171 | } 172 | expecting_comma = false; 173 | } else { 174 | return Error::new(token.span(), "Unknown syntax, expected identifier.") 175 | .to_compile_error() 176 | .into(); 177 | } 178 | } 179 | let original_struct_def: ItemStruct = syn::parse_macro_input!(item); 180 | match self_referencing_impl(&original_struct_def, options) { 181 | Ok(content) => content, 182 | Err(err) => err.to_compile_error().into(), 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/constructor.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | info_structures::{ArgType, BuilderType, FieldType, Options, StructInfo}, 3 | utils::to_class_case, 4 | }; 5 | use proc_macro2::{Ident, TokenStream}; 6 | use quote::{format_ident, quote}; 7 | use syn::Error; 8 | 9 | pub fn create_builder_and_constructor( 10 | info: &StructInfo, 11 | options: Options, 12 | builder_type: BuilderType, 13 | ) -> Result<(Ident, TokenStream, TokenStream), Error> { 14 | let struct_name = info.ident.clone(); 15 | let generic_args = info.generic_arguments(); 16 | 17 | let vis = if options.do_pub_extras { 18 | info.vis.clone() 19 | } else { 20 | syn::parse_quote! { pub(super) } 21 | }; 22 | let builder_struct_name = match builder_type { 23 | BuilderType::AsyncSend => format_ident!("{}AsyncSendBuilder", info.ident), 24 | BuilderType::Async => format_ident!("{}AsyncBuilder", info.ident), 25 | BuilderType::Sync => format_ident!("{}Builder", info.ident), 26 | }; 27 | let documentation = format!( 28 | concat!( 29 | "Constructs a new instance of this self-referential struct. (See also ", 30 | "[`{0}::build()`]({0}::build)). Each argument is a field of ", 31 | "the new struct. Fields that refer to other fields inside the struct are initialized ", 32 | "using functions instead of directly passing their value. The arguments are as ", 33 | "follows:\n\n| Argument | Suggested Use |\n| --- | --- |\n", 34 | ), 35 | builder_struct_name.to_string() 36 | ); 37 | let builder_documentation = concat!( 38 | "A more verbose but stable way to construct self-referencing structs. It is ", 39 | "comparable to using `StructName { field1: value1, field2: value2 }` rather than ", 40 | "`StructName::new(value1, value2)`. This has the dual benefit of making your code ", 41 | "both easier to refactor and more readable. Call [`build()`](Self::build) to ", 42 | "construct the actual struct. The fields of this struct should be used as follows:\n\n", 43 | "| Field | Suggested Use |\n| --- | --- |\n", 44 | ) 45 | .to_owned(); 46 | let build_fn_documentation = format!( 47 | concat!( 48 | "Calls [`{0}::new()`]({0}::new) using the provided values. This is preferable over ", 49 | "calling `new()` directly for the reasons listed above. " 50 | ), 51 | info.ident.to_string() 52 | ); 53 | let mut doc_table = "".to_owned(); 54 | let mut code: Vec = Vec::new(); 55 | let mut params: Vec = Vec::new(); 56 | let mut builder_struct_generic_producers: Vec<_> = info 57 | .generic_params() 58 | .iter() 59 | .map(|param| quote! { #param }) 60 | .collect(); 61 | let mut builder_struct_generic_consumers = info.generic_arguments(); 62 | let mut builder_struct_fields = Vec::new(); 63 | let mut builder_struct_field_names = Vec::new(); 64 | 65 | // code.push(quote! { let mut result = ::core::mem::MaybeUninit::::uninit(); }); 66 | 67 | for field in &info.fields { 68 | let field_name = &field.name; 69 | 70 | let arg_type = field.make_constructor_arg_type(info, builder_type)?; 71 | if let ArgType::Plain(plain_type) = arg_type { 72 | // No fancy builder function, we can just move the value directly into the struct. 73 | params.push(quote! { #field_name: #plain_type }); 74 | builder_struct_fields.push(quote! { #field_name: #plain_type }); 75 | builder_struct_field_names.push(quote! { #field_name }); 76 | doc_table += &format!( 77 | "| `{}` | Directly pass in the value this field should contain |\n", 78 | field_name 79 | ); 80 | } else if let ArgType::TraitBound(bound_type) = arg_type { 81 | // Trait bounds are much trickier. We need a special syntax to accept them in the 82 | // constructor, and generic parameters need to be added to the builder struct to make 83 | // it work. 84 | let builder_name = field.builder_name(); 85 | params.push(quote! { #builder_name : impl #bound_type }); 86 | doc_table += &format!( 87 | "| `{}` | Use a function or closure: `(", 88 | builder_name 89 | ); 90 | let mut builder_args = Vec::new(); 91 | for (index, borrow) in field.borrows.iter().enumerate() { 92 | let borrowed_name = &info.fields[borrow.index].name; 93 | builder_args.push(format_ident!("{}_illegal_static_reference", borrowed_name)); 94 | doc_table += &format!( 95 | "{}: &{}_", 96 | borrowed_name, 97 | if borrow.mutable { "mut " } else { "" }, 98 | ); 99 | if index < field.borrows.len() - 1 { 100 | doc_table += ", "; 101 | } 102 | } 103 | doc_table += &format!(") -> {}: _` | \n", field_name); 104 | if builder_type.is_async() { 105 | code.push(quote! { let #field_name = #builder_name (#(#builder_args),*).await; }); 106 | } else { 107 | code.push(quote! { let #field_name = #builder_name (#(#builder_args),*); }); 108 | } 109 | let generic_type_name = 110 | format_ident!("{}Builder_", to_class_case(field_name.to_string().as_str())); 111 | 112 | builder_struct_generic_producers.push(quote! { #generic_type_name: #bound_type }); 113 | builder_struct_generic_consumers.push(quote! { #generic_type_name }); 114 | builder_struct_fields.push(quote! { #builder_name: #generic_type_name }); 115 | builder_struct_field_names.push(quote! { #builder_name }); 116 | } 117 | if field.is_borrowed() { 118 | let boxed = field.boxed(); 119 | if field.field_type == FieldType::BorrowedMut { 120 | code.push(quote! { let mut #field_name = #boxed; }); 121 | } else { 122 | code.push(quote! { let #field_name = #boxed; }); 123 | } 124 | }; 125 | 126 | if field.field_type == FieldType::Borrowed { 127 | code.push(field.make_illegal_static_reference()); 128 | } else if field.field_type == FieldType::BorrowedMut { 129 | code.push(field.make_illegal_static_mut_reference()); 130 | } 131 | } 132 | 133 | let documentation = if !options.do_no_doc { 134 | let documentation = documentation + &doc_table; 135 | quote! { 136 | #[doc=#documentation] 137 | } 138 | } else { 139 | quote! { #[doc(hidden)] } 140 | }; 141 | 142 | let builder_documentation = if !options.do_no_doc { 143 | let builder_documentation = builder_documentation + &doc_table; 144 | quote! { 145 | #[doc=#builder_documentation] 146 | } 147 | } else { 148 | quote! { #[doc(hidden)] } 149 | }; 150 | 151 | let constructor_fn = match builder_type { 152 | BuilderType::AsyncSend => quote! { async fn new_async_send }, 153 | BuilderType::Async => quote! { async fn new_async }, 154 | BuilderType::Sync => quote! { fn new }, 155 | }; 156 | let field_names: Vec<_> = info.fields.iter().map(|field| field.name.clone()).collect(); 157 | let internal_ident = &info.internal_ident; 158 | let constructor_def = quote! { 159 | #documentation 160 | #vis #constructor_fn(#(#params),*) -> #struct_name <#(#generic_args),*> { 161 | #(#code)* 162 | unsafe { 163 | Self { 164 | actual_data: ::core::mem::MaybeUninit::new(#internal_ident { 165 | #(#field_names),* 166 | }) 167 | } 168 | } 169 | } 170 | }; 171 | let generic_where = &info.generics.where_clause; 172 | let builder_fn = if builder_type.is_async() { 173 | quote! { async fn build } 174 | } else { 175 | quote! { fn build } 176 | }; 177 | let builder_code = match builder_type { 178 | BuilderType::AsyncSend => quote! { 179 | #struct_name::new_async_send( 180 | #(self.#builder_struct_field_names),* 181 | ).await 182 | }, 183 | BuilderType::Async => quote! { 184 | #struct_name::new_async( 185 | #(self.#builder_struct_field_names),* 186 | ).await 187 | }, 188 | BuilderType::Sync => quote! { 189 | #struct_name::new( 190 | #(self.#builder_struct_field_names),* 191 | ) 192 | }, 193 | }; 194 | let builder_def = quote! { 195 | #builder_documentation 196 | #vis struct #builder_struct_name <#(#builder_struct_generic_producers),*> #generic_where { 197 | #(#vis #builder_struct_fields),* 198 | } 199 | impl<#(#builder_struct_generic_producers),*> #builder_struct_name <#(#builder_struct_generic_consumers),*> #generic_where { 200 | #[doc=#build_fn_documentation] 201 | #vis #builder_fn(self) -> #struct_name <#(#generic_args),*> { 202 | #builder_code 203 | } 204 | } 205 | }; 206 | Ok((builder_struct_name, builder_def, constructor_def)) 207 | } 208 | -------------------------------------------------------------------------------- /examples/src/ok_tests.rs: -------------------------------------------------------------------------------- 1 | use alloc::{borrow::ToOwned, boxed::Box}; 2 | use core::fmt::Debug; 3 | 4 | use ouroboros::self_referencing; 5 | 6 | // All tests here should compile and run correctly and pass Miri's safety checks. 7 | 8 | #[self_referencing] 9 | struct TraitObject { 10 | data: Box, 11 | #[borrows(data)] 12 | dref: &'this dyn Debug, 13 | } 14 | 15 | #[self_referencing] 16 | struct BoxAndRef { 17 | data: i32, 18 | #[borrows(data)] 19 | dref: &'this i32, 20 | } 21 | 22 | #[self_referencing] 23 | struct BoxAndMutRef { 24 | data: i32, 25 | #[borrows(mut data)] 26 | dref: &'this mut i32, 27 | } 28 | 29 | #[self_referencing(no_doc)] 30 | struct ChainedAndUndocumented { 31 | data: i32, 32 | #[borrows(data)] 33 | ref1: &'this i32, 34 | #[borrows(ref1)] 35 | ref2: &'this &'this i32, 36 | } 37 | 38 | #[self_referencing] 39 | struct BoxCheckWithLifetimeParameter<'t> { 40 | external_data: &'t (), 41 | #[borrows(external_data)] 42 | self_reference: &'this &'t (), 43 | } 44 | 45 | #[self_referencing] 46 | struct AutoDetectCovarianceOnFieldsWithoutThis { 47 | data: (), 48 | unrelated_data: Box, 49 | #[borrows(data)] 50 | self_reference: &'this (), 51 | } 52 | 53 | /// This test just makes sure that the macro copes with a ton of template parameters being thrown at 54 | /// it, specifically checking that the templates work fine even when a generated struct doesn't need 55 | /// all of them. (E.G. heads will only contain 'd, A, and B.) 56 | #[self_referencing] 57 | struct TemplateMess<'d, A, B: 'static, C: 'static> 58 | where 59 | A: ?Sized, 60 | B: 'static, 61 | C: 'static, 62 | { 63 | external: &'d A, 64 | data1: B, 65 | #[borrows(data1)] 66 | data2: &'this C, 67 | data3: B, 68 | #[borrows(mut data3)] 69 | data4: &'this mut C, 70 | } 71 | 72 | // Regression test for broken derive macros. 73 | #[self_referencing] 74 | #[derive(Debug, PartialEq, Eq)] 75 | struct DeriveCompilesOk { 76 | data: T, 77 | #[borrows(data)] 78 | dref: &'this T, 79 | } 80 | 81 | // /// Regression test for #46 82 | // #[self_referencing] 83 | // struct PreviouslyBrokeAutoGeneratedChecker { 84 | // x: T, 85 | // #[borrows(mut x)] 86 | // y: &'this (), 87 | // } 88 | 89 | struct PhraseRef<'a> { 90 | data: &'a mut String, 91 | } 92 | 93 | impl<'a> PhraseRef<'a> { 94 | fn change_phrase(&mut self) { 95 | *self.data = self.data.replace("Hello", "Goodbye"); 96 | } 97 | } 98 | 99 | #[self_referencing] 100 | struct DataAndCustomRef { 101 | data: String, 102 | #[borrows(mut data)] 103 | #[not_covariant] 104 | phrase: PhraseRef<'this>, 105 | } 106 | 107 | #[test] 108 | fn box_and_ref() { 109 | let bar = BoxAndRefBuilder { 110 | data: 12, 111 | dref_builder: |data| data, 112 | } 113 | .build(); 114 | assert!(bar.with_dref(|dref| **dref) == 12); 115 | drop(bar); 116 | } 117 | 118 | // Miri crashes with Pin> types due to 119 | // https://github.com/rust-lang/miri/issues/1038 120 | #[cfg(all(not(feature = "miri"), feature = "std"))] 121 | #[tokio::test] 122 | async fn async_new() { 123 | let bar = BoxAndRefAsyncBuilder { 124 | data: 12, 125 | dref_builder: |data| Box::pin(async move { data }), 126 | } 127 | .build() 128 | .await; 129 | assert!(bar.with_dref(|dref| **dref) == 12); 130 | drop(bar); 131 | } 132 | 133 | // Miri crashes with Pin> types due to 134 | // https://github.com/rust-lang/miri/issues/1038 135 | #[cfg(all(not(feature = "miri"), feature = "std"))] 136 | #[tokio::test] 137 | async fn async_try_new() { 138 | let bar = BoxAndRefAsyncTryBuilder { 139 | data: 12, 140 | dref_builder: |data| Box::pin(async move { Result::<_, ()>::Ok(data) }), 141 | } 142 | .try_build() 143 | .await 144 | .unwrap(); 145 | assert!(bar.with_dref(|dref| **dref) == 12); 146 | drop(bar); 147 | } 148 | 149 | // Miri crashes with Pin> types due to 150 | // https://github.com/rust-lang/miri/issues/1038 151 | #[cfg(all(not(feature = "miri"), feature = "std"))] 152 | #[tokio::test] 153 | async fn async_try_new_err() { 154 | let result = BoxAndRefAsyncTryBuilder { 155 | data: 12, 156 | dref_builder: |_data| Box::pin(async move { Err(56u64) }), 157 | } 158 | .try_build() 159 | .await; 160 | if let Err(56) = result { 161 | // okay 162 | } else { 163 | panic!("Test failed."); 164 | } 165 | } 166 | 167 | #[test] 168 | fn try_new() { 169 | let bar = BoxAndRefTryBuilder { 170 | data: 12, 171 | dref_builder: |data| Result::<_, ()>::Ok(data), 172 | } 173 | .try_build() 174 | .unwrap(); 175 | assert!(bar.with_dref(|dref| **dref) == 12); 176 | drop(bar); 177 | } 178 | 179 | #[test] 180 | fn try_new_err() { 181 | let result = BoxAndRefTryBuilder { 182 | data: 12, 183 | dref_builder: |_data| Err(56), 184 | } 185 | .try_build(); 186 | if let Err(56) = result { 187 | // okay 188 | } else { 189 | panic!("Test failed."); 190 | } 191 | } 192 | 193 | #[test] 194 | fn try_new_recover_heads() { 195 | let result = BoxAndRefTryBuilder { 196 | data: 12, 197 | dref_builder: |_data| Err(56), 198 | } 199 | .try_build_or_recover(); 200 | if let Err((56, heads)) = result { 201 | assert!(heads.data == 12); 202 | } else { 203 | panic!("Test failed."); 204 | } 205 | } 206 | 207 | #[test] 208 | fn into_heads() { 209 | let bar = BoxAndRefBuilder { 210 | data: 12, 211 | dref_builder: |data| data, 212 | } 213 | .build(); 214 | assert!(bar.into_heads().data == 12); 215 | } 216 | 217 | #[test] 218 | fn box_and_mut_ref() { 219 | let mut bar = BoxAndMutRefBuilder { 220 | data: 12, 221 | dref_builder: |data| data, 222 | } 223 | .build(); 224 | assert!(bar.with_dref(|dref| **dref) == 12); 225 | bar.with_dref_mut(|dref| **dref = 34); 226 | assert!(bar.with_dref(|dref| **dref) == 34); 227 | } 228 | 229 | // #[test] 230 | // fn template_mess() { 231 | // let ext_str = "Hello World!".to_owned(); 232 | // let mut instance = TemplateMessBuilder { 233 | // external: &ext_str[..], 234 | // data1: "asdf".to_owned(), 235 | // data2_builder: |data1_contents| data1_contents, 236 | // data3: "asdf".to_owned(), 237 | // data4_builder: |data3_contents| data3_contents, 238 | // } 239 | // .build(); 240 | // instance.with_external(|ext| assert_eq!(*ext, "Hello World!")); 241 | // instance.with_data1(|data| assert_eq!(data, "asdf")); 242 | // instance.with_data4_mut(|con| **con = "Modified".to_owned()); 243 | // instance.with(|fields| { 244 | // assert!(**fields.data1 == **fields.data2); 245 | // assert!(*fields.data4 == "Modified"); 246 | // }); 247 | // } 248 | 249 | const STATIC_INT: i32 = 456; 250 | #[test] 251 | fn self_reference_with() { 252 | let mut bar = BoxAndRef::new(123, |b| b); 253 | bar.with_dref(|dref| { 254 | assert_eq!(**dref, 123); 255 | }); 256 | bar.with_dref_mut(|dref| { 257 | *dref = &STATIC_INT; 258 | }); 259 | assert_eq!(**bar.borrow_dref(), STATIC_INT); 260 | bar.with_mut(|fields| { 261 | *fields.dref = fields.data; 262 | }); 263 | assert_eq!(**bar.borrow_dref(), 123); 264 | } 265 | 266 | #[test] 267 | fn single_lifetime() { 268 | #[self_referencing] 269 | struct Struct<'a> { 270 | external: &'a str, 271 | #[borrows(external)] 272 | internal: &'this &'a str, 273 | } 274 | 275 | let external = "Hello world!".to_owned(); 276 | let instance = Struct::new(&external, |field_ref| field_ref); 277 | drop(instance.borrow_external()); 278 | drop(instance.borrow_internal()); 279 | drop(instance); 280 | } 281 | 282 | #[test] 283 | fn double_lifetime() { 284 | #[self_referencing] 285 | struct Struct<'a, 'b: 'a> { 286 | external: &'a str, 287 | external2: &'b str, 288 | #[borrows(external, external2)] 289 | internal: &'this &'b str, 290 | } 291 | } 292 | 293 | #[test] 294 | fn custom_ref() { 295 | let mut instance = DataAndCustomRefBuilder { 296 | data: "Hello world!".to_owned(), 297 | phrase_builder: |data| PhraseRef { data }, 298 | } 299 | .build(); 300 | instance.with_phrase_mut(|phrase| phrase.change_phrase()); 301 | let modified_data = instance.into_heads().data; 302 | assert_eq!(modified_data, "Goodbye world!"); 303 | } 304 | 305 | #[cfg(not(feature = "miri"))] 306 | #[rustversion::stable(1.62)] 307 | mod compile_tests { 308 | /// Tests that all files in fail_tests fail to compile. 309 | #[test] 310 | fn fails_ok() { 311 | let t = trybuild::TestCases::new(); 312 | t.compile_fail("src/fail_tests/*.rs"); 313 | } 314 | } 315 | 316 | #[allow(dead_code)] 317 | mod test_hygiene { 318 | mod std {} 319 | mod core {} 320 | 321 | struct Copy; 322 | struct Send; 323 | struct Sync; 324 | struct Sized; 325 | 326 | struct Drop; 327 | struct Fn; 328 | struct FnMut; 329 | struct FnOnce; 330 | 331 | struct Result; 332 | struct Ok; 333 | struct Err; 334 | struct Option; 335 | struct Some; 336 | struct None; 337 | 338 | fn drop() {} 339 | 340 | #[ouroboros::self_referencing] 341 | struct BoxAndRef { 342 | data: i32, 343 | #[borrows(data)] 344 | dref: &'this i32, 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /ouroboros_macro/src/parse.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::{Span, TokenTree}; 2 | use quote::format_ident; 3 | use syn::{ 4 | spanned::Spanned, Attribute, Error, Fields, GenericParam, ItemStruct, MacroDelimiter, Meta, 5 | }; 6 | 7 | use crate::{ 8 | covariance_detection::type_is_covariant_over_this_lifetime, 9 | info_structures::{BorrowRequest, Derive, FieldType, StructFieldInfo, StructInfo}, 10 | utils::submodule_contents_visibility, 11 | }; 12 | 13 | fn handle_borrows_attr( 14 | field_info: &mut [StructFieldInfo], 15 | attr: &Attribute, 16 | borrows: &mut Vec, 17 | ) -> Result<(), Error> { 18 | let mut borrow_mut = false; 19 | let mut waiting_for_comma = false; 20 | let tokens = match &attr.meta { 21 | Meta::List(ml) => ml.tokens.clone(), 22 | _ => { 23 | return Err(Error::new_spanned( 24 | &attr.meta, 25 | "Invalid syntax for borrows() macro.", 26 | )) 27 | } 28 | }; 29 | for token in tokens { 30 | if let TokenTree::Ident(ident) = token { 31 | if waiting_for_comma { 32 | return Err(Error::new_spanned(&ident, "Expected comma.")); 33 | } 34 | let istr = ident.to_string(); 35 | if istr == "mut" { 36 | if borrow_mut { 37 | return Err(Error::new_spanned(&ident, "Unexpected double 'mut'")); 38 | } 39 | borrow_mut = true; 40 | } else { 41 | let index = field_info.iter().position(|item| item.name == istr); 42 | let index = if let Some(v) = index { 43 | v 44 | } else { 45 | return Err(Error::new_spanned( 46 | &ident, 47 | concat!( 48 | "Unknown identifier, make sure that it is spelled ", 49 | "correctly and defined above the location it is borrowed." 50 | ), 51 | )); 52 | }; 53 | if borrow_mut { 54 | if field_info[index].field_type == FieldType::Borrowed { 55 | return Err(Error::new_spanned( 56 | &ident, 57 | "Cannot borrow mutably, this field was previously borrowed immutably.", 58 | )); 59 | } 60 | if field_info[index].field_type == FieldType::BorrowedMut { 61 | return Err(Error::new_spanned(&ident, "Cannot borrow mutably twice.")); 62 | } 63 | field_info[index].field_type = FieldType::BorrowedMut; 64 | } else { 65 | if field_info[index].field_type == FieldType::BorrowedMut { 66 | return Err(Error::new_spanned( 67 | &ident, 68 | "Cannot borrow as immutable as it was previously borrowed mutably.", 69 | )); 70 | } 71 | field_info[index].field_type = FieldType::Borrowed; 72 | } 73 | borrows.push(BorrowRequest { 74 | index, 75 | mutable: borrow_mut, 76 | }); 77 | waiting_for_comma = true; 78 | borrow_mut = false; 79 | } 80 | } else if let TokenTree::Punct(punct) = token { 81 | if punct.as_char() == ',' { 82 | if waiting_for_comma { 83 | waiting_for_comma = false; 84 | } else { 85 | return Err(Error::new_spanned(&punct, "Unexpected extra comma.")); 86 | } 87 | } else { 88 | return Err(Error::new_spanned( 89 | &punct, 90 | "Unexpected punctuation, expected comma or identifier.", 91 | )); 92 | } 93 | } else { 94 | return Err(Error::new_spanned( 95 | &token, 96 | "Unexpected token, expected comma or identifier.", 97 | )); 98 | } 99 | } 100 | Ok(()) 101 | } 102 | 103 | fn parse_derive_token(token: &TokenTree) -> Result, Error> { 104 | match token { 105 | TokenTree::Ident(ident) => match &ident.to_string()[..] { 106 | "Debug" => Ok(Some(Derive::Debug)), 107 | "PartialEq" => Ok(Some(Derive::PartialEq)), 108 | "Eq" => Ok(Some(Derive::Eq)), 109 | _ => Err(Error::new( 110 | ident.span(), 111 | format!("{} cannot be derived for self-referencing structs", ident), 112 | )), 113 | }, 114 | TokenTree::Punct(..) => Ok(None), 115 | _ => Err(Error::new(token.span(), "bad syntax")), 116 | } 117 | } 118 | 119 | fn parse_derive_attribute(attr: &Attribute) -> Result, Error> { 120 | let body = match &attr.meta { 121 | Meta::List(ml) => ml, 122 | _ => unreachable!(), 123 | }; 124 | if !matches!(body.delimiter, MacroDelimiter::Paren(_)) { 125 | return Err(Error::new( 126 | attr.span(), 127 | format!( 128 | "malformed derive input, derive attributes are of the form `#[derive({})]`", 129 | body.tokens 130 | ), 131 | )); 132 | } 133 | let mut derives = Vec::new(); 134 | for token in body.tokens.clone().into_iter() { 135 | if let Some(derive) = parse_derive_token(&token)? { 136 | derives.push(derive); 137 | } 138 | } 139 | Ok(derives) 140 | } 141 | 142 | pub fn parse_struct(def: &ItemStruct) -> Result { 143 | let vis = def.vis.clone(); 144 | let generics = def.generics.clone(); 145 | let mut actual_struct_def = def.clone(); 146 | actual_struct_def.vis = vis.clone(); 147 | let mut fields = Vec::new(); 148 | match &mut actual_struct_def.fields { 149 | Fields::Named(def_fields) => { 150 | for field in &mut def_fields.named { 151 | let mut borrows = Vec::new(); 152 | let mut self_referencing = false; 153 | let mut covariant = type_is_covariant_over_this_lifetime(&field.ty); 154 | let mut remove_attrs = Vec::new(); 155 | for (index, attr) in field.attrs.iter().enumerate() { 156 | let path = &attr.path(); 157 | if path.leading_colon.is_some() { 158 | continue; 159 | } 160 | if path.segments.len() != 1 { 161 | continue; 162 | } 163 | if path.segments.first().unwrap().ident == "borrows" { 164 | if self_referencing { 165 | panic!("TODO: Nice error, used #[borrows()] twice."); 166 | } 167 | self_referencing = true; 168 | handle_borrows_attr(&mut fields[..], attr, &mut borrows)?; 169 | remove_attrs.push(index); 170 | } 171 | if path.segments.first().unwrap().ident == "covariant" { 172 | if covariant.is_some() { 173 | panic!("TODO: Nice error, covariance specified twice."); 174 | } 175 | covariant = Some(true); 176 | remove_attrs.push(index); 177 | } 178 | if path.segments.first().unwrap().ident == "not_covariant" { 179 | if covariant.is_some() { 180 | panic!("TODO: Nice error, covariance specified twice."); 181 | } 182 | covariant = Some(false); 183 | remove_attrs.push(index); 184 | } 185 | } 186 | // We should not be able to access the field outside of the hidden module where 187 | // everything is generated. 188 | let with_vis = submodule_contents_visibility(&field.vis.clone()); 189 | fields.push(StructFieldInfo { 190 | name: field.ident.clone().expect("Named field has no name."), 191 | typ: field.ty.clone(), 192 | field_type: FieldType::Tail, 193 | vis: with_vis, 194 | borrows, 195 | self_referencing, 196 | covariant, 197 | }); 198 | } 199 | } 200 | Fields::Unnamed(_fields) => { 201 | return Err(Error::new( 202 | Span::call_site(), 203 | "Tuple structs are not supported yet.", 204 | )) 205 | } 206 | Fields::Unit => { 207 | return Err(Error::new( 208 | Span::call_site(), 209 | "Unit structs cannot be self-referential.", 210 | )) 211 | } 212 | } 213 | if fields.len() < 2 { 214 | return Err(Error::new( 215 | Span::call_site(), 216 | "Self-referencing structs must have at least 2 fields.", 217 | )); 218 | } 219 | let mut has_non_tail = false; 220 | for field in &fields { 221 | if !field.field_type.is_tail() { 222 | has_non_tail = true; 223 | break; 224 | } 225 | } 226 | if !has_non_tail { 227 | return Err(Error::new( 228 | Span::call_site(), 229 | format!( 230 | concat!( 231 | "Self-referencing struct cannot be made entirely of tail fields, try adding ", 232 | "#[borrows({0})] to a field defined after {0}." 233 | ), 234 | fields[0].name 235 | ), 236 | )); 237 | } 238 | let first_lifetime = if let Some(GenericParam::Lifetime(param)) = generics.params.first() { 239 | param.lifetime.ident.clone() 240 | } else { 241 | format_ident!("static") 242 | }; 243 | let mut attributes = Vec::new(); 244 | let mut derives = Vec::new(); 245 | for attr in &def.attrs { 246 | let p = &attr.path().segments; 247 | if p.is_empty() { 248 | return Err(Error::new(p.span(), "Unsupported attribute".to_string())); 249 | } 250 | let name = p[0].ident.to_string(); 251 | let good = matches!(&name[..], "clippy" | "allow" | "deny" | "doc" | "cfg"); 252 | if good { 253 | attributes.push(attr.clone()) 254 | } else if name == "derive" { 255 | if !derives.is_empty() { 256 | return Err(Error::new( 257 | attr.span(), 258 | "Multiple derive attributes not allowed", 259 | )); 260 | } else { 261 | derives = parse_derive_attribute(attr)?; 262 | } 263 | } else { 264 | return Err(Error::new(p.span(), "Unsupported attribute".to_string())); 265 | } 266 | } 267 | 268 | Ok(StructInfo { 269 | derives, 270 | ident: def.ident.clone(), 271 | internal_ident: format_ident!("{}Internal", def.ident), 272 | generics: def.generics.clone(), 273 | fields, 274 | vis, 275 | first_lifetime, 276 | attributes, 277 | }) 278 | } 279 | -------------------------------------------------------------------------------- /LICENSE_APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 Josh 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /examples/LICENSE_APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 Josh 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /ouroboros/LICENSE_APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 Josh 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /ouroboros_macro/LICENSE_APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2021 Josh 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /ouroboros_macro/src/info_structures.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::{make_generic_arguments, make_generic_consumers, replace_this_with_lifetime}; 2 | use proc_macro2::{Ident, TokenStream}; 3 | use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt}; 4 | use quote::{format_ident, quote, ToTokens}; 5 | use syn::{ 6 | punctuated::Punctuated, token::Comma, Attribute, ConstParam, Error, GenericParam, Generics, 7 | LifetimeParam, Type, TypeParam, Visibility, spanned::Spanned, 8 | }; 9 | 10 | #[derive(Clone, Copy)] 11 | pub struct Options { 12 | pub do_no_doc: bool, 13 | pub do_pub_extras: bool, 14 | } 15 | 16 | impl Options { 17 | // pub fn documentation_to_tokens(&self, documentation: &str) -> TokenStream { 18 | // if self.do_no_doc { 19 | // quote! { #[doc(hidden)] } 20 | // } else { 21 | // quote! { #[doc=#documentation] } 22 | // } 23 | // } 24 | } 25 | 26 | #[derive(Clone, Copy, PartialEq)] 27 | pub enum FieldType { 28 | /// Not borrowed by other parts of the struct. 29 | Tail, 30 | /// Immutably borrowed by at least one other field. 31 | Borrowed, 32 | /// Mutably borrowed by one other field. 33 | BorrowedMut, 34 | } 35 | 36 | impl FieldType { 37 | pub fn is_tail(self) -> bool { 38 | self == Self::Tail 39 | } 40 | } 41 | 42 | #[derive(Clone)] 43 | pub struct BorrowRequest { 44 | pub index: usize, 45 | pub mutable: bool, 46 | } 47 | 48 | #[derive(Clone)] 49 | pub enum Derive { 50 | Debug, 51 | PartialEq, 52 | Eq, 53 | } 54 | 55 | #[derive(Copy, Clone)] 56 | pub enum BuilderType { 57 | Sync, 58 | Async, 59 | AsyncSend, 60 | } 61 | 62 | impl BuilderType { 63 | pub fn is_async(&self) -> bool { 64 | !matches!(self, BuilderType::Sync) 65 | } 66 | } 67 | 68 | #[derive(Clone)] 69 | pub struct StructInfo { 70 | pub derives: Vec, 71 | pub ident: Ident, 72 | pub internal_ident: Ident, 73 | pub generics: Generics, 74 | pub vis: Visibility, 75 | pub fields: Vec, 76 | pub first_lifetime: Ident, 77 | pub attributes: Vec, 78 | } 79 | 80 | impl StructInfo { 81 | // The lifetime to use in place of 'this for internal implementations, 82 | // should never be exposed to the user. 83 | pub fn fake_lifetime(&self) -> Ident { 84 | self.first_lifetime.clone() 85 | } 86 | 87 | pub fn generic_params(&self) -> &Punctuated { 88 | &self.generics.params 89 | } 90 | 91 | /// Same as generic_params but with 'this and 'outer_borrow prepended. 92 | pub fn borrowed_generic_params(&self) -> TokenStream { 93 | if self.generic_params().is_empty() { 94 | quote! { <'outer_borrow, 'this> } 95 | } else { 96 | let mut new_generic_params = self.generic_params().clone(); 97 | new_generic_params.insert(0, syn::parse_quote! { 'this }); 98 | new_generic_params.insert(0, syn::parse_quote! { 'outer_borrow }); 99 | quote! { <#new_generic_params> } 100 | } 101 | } 102 | 103 | /// Same as generic_params but without bounds and with '_ prepended twice. 104 | pub fn borrowed_generic_params_inferred(&self) -> TokenStream { 105 | use GenericParam::*; 106 | let params = self.generic_params().iter().map(|p| match p { 107 | Type(TypeParam { ident, .. }) | Const(ConstParam { ident, .. }) => { 108 | ident.to_token_stream() 109 | } 110 | Lifetime(LifetimeParam { lifetime, .. }) => lifetime.to_token_stream(), 111 | }); 112 | quote! { <'_, '_, #(#params,)*> } 113 | } 114 | 115 | pub fn generic_arguments(&self) -> Vec { 116 | make_generic_arguments(self.generics.params.iter().collect()) 117 | } 118 | 119 | /// Same as generic_arguments but with 'outer_borrow and 'this prepended. 120 | pub fn borrowed_generic_arguments(&self) -> Vec { 121 | let mut args = self.generic_arguments(); 122 | args.insert(0, quote! { 'this }); 123 | args.insert(0, quote! { 'outer_borrow }); 124 | args 125 | } 126 | 127 | pub fn generic_consumers(&self) -> impl Iterator { 128 | make_generic_consumers(&self.generics) 129 | } 130 | } 131 | 132 | #[derive(Clone)] 133 | pub struct StructFieldInfo { 134 | pub name: Ident, 135 | pub typ: Type, 136 | pub field_type: FieldType, 137 | pub vis: Visibility, 138 | pub borrows: Vec, 139 | /// If this is true and borrows is empty, the struct will borrow from self in the future but 140 | /// does not require a builder to be initialized. It should not be able to be removed from the 141 | /// struct with into_heads. 142 | pub self_referencing: bool, 143 | /// If it is None, the user has not specified whether or not the field is covariant. If this is 144 | /// Some(false), we should avoid making borrow_* or borrow_*_mut functions as they will not 145 | /// be able to compile. 146 | pub covariant: Option, 147 | } 148 | 149 | #[derive(Clone)] 150 | pub enum ArgType { 151 | /// Used when the initial value of a field can be passed directly into the constructor. 152 | Plain(TokenStream), 153 | /// Used when a field requires self references and thus requires something that implements 154 | /// a builder function trait instead of a simple plain type. 155 | TraitBound(TokenStream), 156 | } 157 | 158 | impl StructFieldInfo { 159 | pub fn builder_name(&self) -> Ident { 160 | format_ident!("{}_builder", self.name) 161 | } 162 | 163 | pub fn illegal_ref_name(&self) -> Ident { 164 | format_ident!("{}_illegal_static_reference", self.name) 165 | } 166 | 167 | pub fn is_borrowed(&self) -> bool { 168 | self.field_type != FieldType::Tail 169 | } 170 | 171 | pub fn is_mutably_borrowed(&self) -> bool { 172 | self.field_type == FieldType::BorrowedMut 173 | } 174 | 175 | pub fn boxed(&self) -> TokenStream { 176 | let name = &self.name; 177 | quote! { ::ouroboros::macro_help::aliasable_boxed(#name) } 178 | } 179 | 180 | pub fn stored_type(&self) -> TokenStream { 181 | let t = &self.typ; 182 | if self.is_borrowed() { 183 | quote! { ::ouroboros::macro_help::AliasableBox<#t> } 184 | } else { 185 | quote! { #t } 186 | } 187 | } 188 | 189 | /// Returns code which takes a variable with the same name and type as this field and turns it 190 | /// into a static reference to its dereffed contents. 191 | pub fn make_illegal_static_reference(&self) -> TokenStream { 192 | let field_name = &self.name; 193 | let ref_name = self.illegal_ref_name(); 194 | quote! { 195 | let #ref_name = unsafe { 196 | ::ouroboros::macro_help::change_lifetime(&*#field_name) 197 | }; 198 | } 199 | } 200 | 201 | /// Like make_illegal_static_reference, but provides a mutable reference instead. 202 | pub fn make_illegal_static_mut_reference(&self) -> TokenStream { 203 | let field_name = &self.name; 204 | let ref_name = self.illegal_ref_name(); 205 | quote! { 206 | let #ref_name = unsafe { 207 | ::ouroboros::macro_help::change_lifetime_mut(&mut *#field_name) 208 | }; 209 | } 210 | } 211 | 212 | /// Generates an error requesting that the user explicitly specify whether or not the 213 | /// field's type is covariant. 214 | #[must_use] 215 | pub fn covariance_error(&self) -> Diagnostic { 216 | let error = concat!( 217 | "Ouroboros cannot automatically determine if this type is covariant.\n\n", 218 | "As an example, a Box<&'this ()> is covariant because it can be used as a\n", 219 | "Box<&'smaller ()> for any lifetime smaller than 'this. In contrast,\n", 220 | "a Fn(&'this ()) is not covariant because it cannot be used as a\n", 221 | "Fn(&'smaller ()). In general, values that are safe to use with smaller\n", 222 | "lifetimes than they were defined with are covariant, breaking this \n", 223 | "guarantee means the value is not covariant.\n\n", 224 | "To resolve this error, add #[covariant] or #[not_covariant] to the field.\n", 225 | ); 226 | self.typ.span().error(error) 227 | } 228 | 229 | pub fn make_constructor_arg_type_impl( 230 | &self, 231 | info: &StructInfo, 232 | make_builder_return_type: impl FnOnce() -> TokenStream, 233 | ) -> Result { 234 | let field_type = &self.typ; 235 | let fake_lifetime = info.fake_lifetime(); 236 | if self.borrows.is_empty() { 237 | // Even if self_referencing is true, as long as borrows is empty, we don't need to use a 238 | // builder to construct it. 239 | let field_type = 240 | replace_this_with_lifetime(field_type.into_token_stream(), fake_lifetime.clone()); 241 | Ok(ArgType::Plain(quote! { #field_type })) 242 | } else { 243 | let mut field_builder_params = Vec::new(); 244 | for borrow in &self.borrows { 245 | if borrow.mutable { 246 | let field = &info.fields[borrow.index]; 247 | let field_type = &field.typ; 248 | field_builder_params.push(quote! { 249 | &'this mut #field_type 250 | }); 251 | } else { 252 | let field = &info.fields[borrow.index]; 253 | let field_type = &field.typ; 254 | field_builder_params.push(quote! { 255 | &'this #field_type 256 | }); 257 | } 258 | } 259 | let return_type = make_builder_return_type(); 260 | let bound = quote! { for<'this> ::core::ops::FnOnce(#(#field_builder_params),*) -> #return_type }; 261 | Ok(ArgType::TraitBound(bound)) 262 | } 263 | } 264 | 265 | /// Returns a trait bound if `for_field` refers to any other fields, and a plain type if not. This 266 | /// is the type used in the constructor to initialize the value of `for_field`. 267 | pub fn make_constructor_arg_type( 268 | &self, 269 | info: &StructInfo, 270 | builder_type: BuilderType, 271 | ) -> Result { 272 | let field_type = &self.typ; 273 | let return_ty_constructor = || match builder_type { 274 | BuilderType::AsyncSend => { 275 | quote! { 276 | ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box< 277 | dyn ::core::future::Future + ::core::marker::Send + 'this>> 278 | } 279 | } 280 | BuilderType::Async => { 281 | quote! { ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box< 282 | dyn ::core::future::Future + 'this>> } 283 | } 284 | BuilderType::Sync => quote! { #field_type }, 285 | }; 286 | self.make_constructor_arg_type_impl(info, return_ty_constructor) 287 | } 288 | 289 | /// Like make_constructor_arg_type, but used for the try_new constructor. 290 | pub fn make_try_constructor_arg_type( 291 | &self, 292 | info: &StructInfo, 293 | builder_type: BuilderType, 294 | ) -> Result { 295 | let field_type = &self.typ; 296 | let return_ty_constructor = || match builder_type { 297 | BuilderType::AsyncSend => { 298 | quote! { 299 | ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box< 300 | dyn ::core::future::Future> 301 | + ::core::marker::Send + 'this>> 302 | } 303 | } 304 | BuilderType::Async => { 305 | quote! { 306 | ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box< 307 | dyn ::core::future::Future> 308 | + 'this>> 309 | } 310 | } 311 | BuilderType::Sync => quote! { ::core::result::Result<#field_type, Error_> }, 312 | }; 313 | self.make_constructor_arg_type_impl(info, return_ty_constructor) 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /ouroboros_macro/src/generate/try_constructor.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | info_structures::{ArgType, BuilderType, FieldType, Options, StructInfo}, 3 | utils::to_class_case, 4 | }; 5 | use proc_macro2::{Ident, TokenStream}; 6 | use quote::{format_ident, quote}; 7 | use syn::Error; 8 | 9 | pub fn create_try_builder_and_constructor( 10 | info: &StructInfo, 11 | options: Options, 12 | builder_type: BuilderType, 13 | ) -> Result<(Ident, TokenStream, TokenStream), Error> { 14 | let struct_name = info.ident.clone(); 15 | let generic_args = info.generic_arguments(); 16 | 17 | let visibility = if options.do_pub_extras { 18 | info.vis.clone() 19 | } else { 20 | syn::parse_quote! { pub(super) } 21 | }; 22 | let mut head_recover_code = Vec::new(); 23 | for field in &info.fields { 24 | if !field.self_referencing { 25 | let field_name = &field.name; 26 | head_recover_code.push(quote! { #field_name }); 27 | } 28 | } 29 | for (_ty, ident) in info.generic_consumers() { 30 | head_recover_code.push(quote! { #ident: ::core::marker::PhantomData }); 31 | } 32 | let mut current_head_index = 0; 33 | 34 | let builder_struct_name = match builder_type { 35 | BuilderType::AsyncSend => format_ident!("{}AsyncSendTryBuilder", info.ident), 36 | BuilderType::Async => format_ident!("{}AsyncTryBuilder", info.ident), 37 | BuilderType::Sync => format_ident!("{}TryBuilder", info.ident), 38 | }; 39 | let documentation = format!( 40 | concat!( 41 | "(See also [`{0}::try_build()`]({0}::try_build).) Like [`new`](Self::new), but ", 42 | "builders for [self-referencing fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) ", 43 | "can return results. If any of them fail, `Err` is returned. If all of them ", 44 | "succeed, `Ok` is returned. The arguments are as follows:\n\n", 45 | "| Argument | Suggested Use |\n| --- | --- |\n", 46 | ), 47 | builder_struct_name.to_string() 48 | ); 49 | let or_recover_documentation = format!( 50 | concat!( 51 | "(See also [`{0}::try_build_or_recover()`]({0}::try_build_or_recover).) Like ", 52 | "[`try_new`](Self::try_new), but all ", 53 | "[head fields](https://docs.rs/ouroboros/latest/ouroboros/attr.self_referencing.html#definitions) ", 54 | "are returned in the case of an error. The arguments are as follows:\n\n", 55 | "| Argument | Suggested Use |\n| --- | --- |\n", 56 | ), 57 | builder_struct_name.to_string() 58 | ); 59 | let builder_documentation = concat!( 60 | "A more verbose but stable way to construct self-referencing structs. It is ", 61 | "comparable to using `StructName { field1: value1, field2: value2 }` rather than ", 62 | "`StructName::new(value1, value2)`. This has the dual benefit of making your code ", 63 | "both easier to refactor and more readable. Call [`try_build()`](Self::try_build) or ", 64 | "[`try_build_or_recover()`](Self::try_build_or_recover) to ", 65 | "construct the actual struct. The fields of this struct should be used as follows:\n\n", 66 | "| Field | Suggested Use |\n| --- | --- |\n", 67 | ) 68 | .to_owned(); 69 | let build_fn_documentation = format!( 70 | concat!( 71 | "Calls [`{0}::try_new()`]({0}::try_new) using the provided values. This is ", 72 | "preferable over calling `try_new()` directly for the reasons listed above. " 73 | ), 74 | info.ident.to_string() 75 | ); 76 | let build_or_recover_fn_documentation = format!( 77 | concat!( 78 | "Calls [`{0}::try_new_or_recover()`]({0}::try_new_or_recover) using the provided ", 79 | "values. This is preferable over calling `try_new_or_recover()` directly for the ", 80 | "reasons listed above. " 81 | ), 82 | info.ident.to_string() 83 | ); 84 | let mut doc_table = "".to_owned(); 85 | let mut or_recover_code: Vec = Vec::new(); 86 | let mut params: Vec = Vec::new(); 87 | let mut builder_struct_generic_producers: Vec<_> = info 88 | .generic_params() 89 | .iter() 90 | .map(|param| quote! { #param }) 91 | .collect(); 92 | let mut builder_struct_generic_consumers = info.generic_arguments(); 93 | let mut builder_struct_fields = Vec::new(); 94 | let mut builder_struct_field_names = Vec::new(); 95 | 96 | for field in &info.fields { 97 | let field_name = &field.name; 98 | 99 | let arg_type = field.make_try_constructor_arg_type(info, builder_type)?; 100 | if let ArgType::Plain(plain_type) = arg_type { 101 | // No fancy builder function, we can just move the value directly into the struct. 102 | params.push(quote! { #field_name: #plain_type }); 103 | builder_struct_fields.push(quote! { #field_name: #plain_type }); 104 | builder_struct_field_names.push(quote! { #field_name }); 105 | doc_table += &format!( 106 | "| `{}` | Directly pass in the value this field should contain |\n", 107 | field_name 108 | ); 109 | if !field.self_referencing { 110 | if field.is_borrowed() { 111 | head_recover_code[current_head_index] = quote! { 112 | #field_name: ::ouroboros::macro_help::unbox(#field_name) 113 | }; 114 | } else { 115 | head_recover_code[current_head_index] = quote! { #field_name }; 116 | } 117 | current_head_index += 1; 118 | } 119 | } else if let ArgType::TraitBound(bound_type) = arg_type { 120 | // Trait bounds are much trickier. We need a special syntax to accept them in the 121 | // constructor, and generic parameters need to be added to the builder struct to make 122 | // it work. 123 | let builder_name = field.builder_name(); 124 | params.push(quote! { #builder_name : impl #bound_type }); 125 | // Ok so hear me out basically without this thing here my IDE thinks the rest of the 126 | // code is a string and it all turns green. 127 | {} 128 | doc_table += &format!( 129 | "| `{}` | Use a function or closure: `(", 130 | builder_name 131 | ); 132 | let mut builder_args = Vec::new(); 133 | for (index, borrow) in field.borrows.iter().enumerate() { 134 | let borrowed_name = &info.fields[borrow.index].name; 135 | builder_args.push(format_ident!("{}_illegal_static_reference", borrowed_name)); 136 | doc_table += &format!( 137 | "{}: &{}_", 138 | borrowed_name, 139 | if borrow.mutable { "mut " } else { "" }, 140 | ); 141 | if index < field.borrows.len() - 1 { 142 | doc_table += ", "; 143 | } 144 | } 145 | doc_table += &format!(") -> Result<{}: _, Error_>` | \n", field_name); 146 | let builder_value = if builder_type.is_async() { 147 | quote! { #builder_name (#(#builder_args),*).await } 148 | } else { 149 | quote! { #builder_name (#(#builder_args),*) } 150 | }; 151 | or_recover_code.push(quote! { 152 | let #field_name = match #builder_value { 153 | ::core::result::Result::Ok(value) => value, 154 | ::core::result::Result::Err(err) 155 | => return ::core::result::Result::Err((err, Heads { #(#head_recover_code),* })), 156 | }; 157 | }); 158 | let generic_type_name = 159 | format_ident!("{}Builder_", to_class_case(field_name.to_string().as_str())); 160 | 161 | builder_struct_generic_producers.push(quote! { #generic_type_name: #bound_type }); 162 | builder_struct_generic_consumers.push(quote! { #generic_type_name }); 163 | builder_struct_fields.push(quote! { #builder_name: #generic_type_name }); 164 | builder_struct_field_names.push(quote! { #builder_name }); 165 | } 166 | if field.is_borrowed() { 167 | let boxed = field.boxed(); 168 | if field.field_type == FieldType::BorrowedMut { 169 | or_recover_code.push(quote! { let mut #field_name = #boxed; }); 170 | } else { 171 | or_recover_code.push(quote! { let #field_name = #boxed; }); 172 | } 173 | } 174 | 175 | if field.field_type == FieldType::Borrowed { 176 | or_recover_code.push(field.make_illegal_static_reference()); 177 | } else if field.field_type == FieldType::BorrowedMut { 178 | or_recover_code.push(field.make_illegal_static_mut_reference()); 179 | } 180 | } 181 | let documentation = if !options.do_no_doc { 182 | let documentation = documentation + &doc_table; 183 | quote! { 184 | #[doc=#documentation] 185 | } 186 | } else { 187 | quote! { #[doc(hidden)] } 188 | }; 189 | let or_recover_documentation = if !options.do_no_doc { 190 | let or_recover_documentation = or_recover_documentation + &doc_table; 191 | quote! { 192 | #[doc=#or_recover_documentation] 193 | } 194 | } else { 195 | quote! { #[doc(hidden)] } 196 | }; 197 | let builder_documentation = if !options.do_no_doc { 198 | let builder_documentation = builder_documentation + &doc_table; 199 | quote! { 200 | #[doc=#builder_documentation] 201 | } 202 | } else { 203 | quote! { #[doc(hidden)] } 204 | }; 205 | let or_recover_ident = match builder_type { 206 | BuilderType::AsyncSend => quote! { try_new_or_recover_async_send }, 207 | BuilderType::Async => quote! { try_new_or_recover_async }, 208 | BuilderType::Sync => quote! { try_new_or_recover }, 209 | }; 210 | let or_recover_constructor_fn = if builder_type.is_async() { 211 | quote! { async fn #or_recover_ident } 212 | } else { 213 | quote! { fn #or_recover_ident } 214 | }; 215 | let constructor_fn = match builder_type { 216 | BuilderType::AsyncSend => quote! { async fn try_new_async_send }, 217 | BuilderType::Async => quote! { async fn try_new_async }, 218 | BuilderType::Sync => quote! { fn try_new }, 219 | }; 220 | let constructor_code = if builder_type.is_async() { 221 | quote! { #struct_name::#or_recover_ident(#(#builder_struct_field_names),*).await.map_err(|(error, _heads)| error) } 222 | } else { 223 | quote! { #struct_name::#or_recover_ident(#(#builder_struct_field_names),*).map_err(|(error, _heads)| error) } 224 | }; 225 | let field_names: Vec<_> = info.fields.iter().map(|field| field.name.clone()).collect(); 226 | let internal_ident = &info.internal_ident; 227 | let constructor_def = quote! { 228 | #documentation 229 | #visibility #constructor_fn(#(#params),*) -> ::core::result::Result<#struct_name <#(#generic_args),*>, Error_> { 230 | #constructor_code 231 | } 232 | #or_recover_documentation 233 | #visibility #or_recover_constructor_fn(#(#params),*) -> ::core::result::Result<#struct_name <#(#generic_args),*>, (Error_, Heads<#(#generic_args),*>)> { 234 | #(#or_recover_code)* 235 | ::core::result::Result::Ok(unsafe { 236 | Self { 237 | actual_data: ::core::mem::MaybeUninit::new(#internal_ident { 238 | #(#field_names),* 239 | }) 240 | } 241 | }) 242 | } 243 | }; 244 | builder_struct_generic_producers.push(quote! { Error_ }); 245 | builder_struct_generic_consumers.push(quote! { Error_ }); 246 | let generic_where = &info.generics.where_clause; 247 | let builder_fn = if builder_type.is_async() { 248 | quote! { async fn try_build } 249 | } else { 250 | quote! { fn try_build } 251 | }; 252 | let or_recover_builder_fn = if builder_type.is_async() { 253 | quote! { async fn try_build_or_recover } 254 | } else { 255 | quote! { fn try_build_or_recover } 256 | }; 257 | let builder_code = match builder_type { 258 | BuilderType::AsyncSend => quote! { 259 | #struct_name::try_new_async_send( 260 | #(self.#builder_struct_field_names),* 261 | ).await 262 | }, 263 | BuilderType::Async => quote! { 264 | #struct_name::try_new_async( 265 | #(self.#builder_struct_field_names),* 266 | ).await 267 | }, 268 | BuilderType::Sync => quote! { 269 | #struct_name::try_new( 270 | #(self.#builder_struct_field_names),* 271 | ) 272 | }, 273 | }; 274 | let or_recover_builder_code = match builder_type { 275 | BuilderType::AsyncSend => quote! { 276 | #struct_name::try_new_or_recover_async_send( 277 | #(self.#builder_struct_field_names),* 278 | ).await 279 | }, 280 | BuilderType::Async => quote! { 281 | #struct_name::try_new_or_recover_async( 282 | #(self.#builder_struct_field_names),* 283 | ).await 284 | }, 285 | BuilderType::Sync => quote! { 286 | #struct_name::try_new_or_recover( 287 | #(self.#builder_struct_field_names),* 288 | ) 289 | }, 290 | }; 291 | let builder_def = quote! { 292 | #builder_documentation 293 | #visibility struct #builder_struct_name <#(#builder_struct_generic_producers),*> #generic_where { 294 | #(#visibility #builder_struct_fields),* 295 | } 296 | impl<#(#builder_struct_generic_producers),*> #builder_struct_name <#(#builder_struct_generic_consumers),*> #generic_where { 297 | #[doc=#build_fn_documentation] 298 | #visibility #builder_fn(self) -> ::core::result::Result<#struct_name <#(#generic_args),*>, Error_> { 299 | #builder_code 300 | } 301 | #[doc=#build_or_recover_fn_documentation] 302 | #visibility #or_recover_builder_fn(self) -> ::core::result::Result<#struct_name <#(#generic_args),*>, (Error_, Heads<#(#generic_args),*>)> { 303 | #or_recover_builder_code 304 | } 305 | } 306 | }; 307 | Ok((builder_struct_name, builder_def, constructor_def)) 308 | } 309 | -------------------------------------------------------------------------------- /ouroboros/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A crate for creating safe self-referencing structs. 2 | //! 3 | //! See the documentation of [`ouroboros_examples`](https://docs.rs/ouroboros_examples) for 4 | //! sample documentation of structs which have had the macro applied to them. 5 | 6 | #![no_std] 7 | #![allow(clippy::needless_doctest_main)] 8 | 9 | /// This macro is used to turn a regular struct into a self-referencing one. An example: 10 | /// ```rust 11 | /// use ouroboros::self_referencing; 12 | /// 13 | /// #[self_referencing] 14 | /// struct MyStruct { 15 | /// int_data: i32, 16 | /// float_data: f32, 17 | /// #[borrows(int_data)] 18 | /// // the 'this lifetime is created by the #[self_referencing] macro 19 | /// // and should be used on all references marked by the #[borrows] macro 20 | /// int_reference: &'this i32, 21 | /// #[borrows(mut float_data)] 22 | /// float_reference: &'this mut f32, 23 | /// } 24 | /// 25 | /// fn main() { 26 | /// // The builder is created by the #[self_referencing] macro 27 | /// // and is used to create the struct 28 | /// let mut my_value = MyStructBuilder { 29 | /// int_data: 42, 30 | /// float_data: 3.14, 31 | /// 32 | /// // Note that the name of the field in the builder 33 | /// // is the name of the field in the struct + `_builder` 34 | /// // ie: {field_name}_builder 35 | /// // the closure that assigns the value for the field will be passed 36 | /// // a reference to the field(s) defined in the #[borrows] macro 37 | /// 38 | /// int_reference_builder: |int_data: &i32| int_data, 39 | /// float_reference_builder: |float_data: &mut f32| float_data, 40 | /// }.build(); 41 | /// 42 | /// // The fields in the original struct can not be accessed directly 43 | /// // The builder creates accessor methods which are called borrow_{field_name}() 44 | /// 45 | /// // Prints 42 46 | /// println!("{:?}", my_value.borrow_int_data()); 47 | /// // Prints 3.14 48 | /// println!("{:?}", my_value.borrow_float_reference()); 49 | /// // Sets the value of float_data to 84.0 50 | /// my_value.with_mut(|fields| { 51 | /// **fields.float_reference = (**fields.int_reference as f32) * 2.0; 52 | /// }); 53 | /// 54 | /// // We can hold on to this reference... 55 | /// let int_ref = *my_value.borrow_int_reference(); 56 | /// println!("{:?}", *int_ref); 57 | /// // As long as the struct is still alive. 58 | /// drop(my_value); 59 | /// // This will cause an error! 60 | /// // println!("{:?}", *int_ref); 61 | /// } 62 | /// ``` 63 | /// To explain the features and limitations of this crate, some definitions are necessary: 64 | /// # Definitions 65 | /// - **immutably borrowed field**: a field which is immutably borrowed by at least one other field. 66 | /// - **mutably borrowed field**: a field which is mutably borrowed by exactly one other field. 67 | /// - **self-referencing field**: a field which borrows at least one other field. 68 | /// - **head field**: a field which does not borrow any other fields, I.E. not self-referencing. 69 | /// This does not include fields with empty borrows annotations (`#[borrows()]`.) 70 | /// - **tail field**: a field which is not borrowed by any other fields. 71 | /// 72 | /// # Usage 73 | /// To make a self-referencing struct, you must write a struct definition and place 74 | /// `#[self_referencing]` on top. For every field that borrows other fields, you must place 75 | /// `#[borrows()]` on top and place inside the parenthesis a list of fields that it borrows. Mut can 76 | /// be prefixed to indicate that a mutable borrow is required. For example, 77 | /// `#[borrows(a, b, mut c)]` indicates that the first two fields need to be borrowed immutably and 78 | /// the third needs to be borrowed mutably. You can also use `#[borrows()]` without any arguments to 79 | /// indicate a field that will eventually borrow from the struct, but does not borrow anything when 80 | /// first created. For example, you could use this on a field like `error: Option<&'this str>`. 81 | /// 82 | /// # You must comply with these limitations 83 | /// - Fields must be declared before the first time they are borrowed. 84 | /// - Normal borrowing rules apply, E.G. a field cannot be borrowed mutably twice. 85 | /// - Fields that use the `'this` lifetime must have a corresponding `#[borrows()]` annotation. 86 | /// The error for this needs some work, currently you will get an error saying that `'this` is 87 | /// undefined at the location it was illegally used in. 88 | /// 89 | /// Violating them will result in an error message directly pointing out the violated rule. 90 | /// 91 | /// # Flexibility of this crate 92 | /// The example above uses plain references as the self-referencing part of the struct, but you can 93 | /// use anything that is dependent on lifetimes of objects inside the struct. For example, you could 94 | /// do something like this: 95 | /// ```rust 96 | /// use ouroboros::self_referencing; 97 | /// 98 | /// pub struct ComplexData<'a, 'b> { 99 | /// aref: &'a i32, 100 | /// bref: &'b mut i32, 101 | /// number: i32, 102 | /// } 103 | /// 104 | /// impl<'a, 'b> ComplexData<'a, 'b> { 105 | /// fn new(aref: &'a i32, bref: &'b mut i32, number: i32) -> Self { 106 | /// Self { aref, bref, number } 107 | /// } 108 | /// 109 | /// /// Copies the value aref points to into what bref points to. 110 | /// fn transfer(&mut self) { 111 | /// *self.bref = *self.aref; 112 | /// } 113 | /// 114 | /// /// Prints the value bref points to. 115 | /// fn print_bref(&self) { 116 | /// println!("{}", *self.bref); 117 | /// } 118 | /// } 119 | /// 120 | /// fn main() { 121 | /// #[self_referencing] 122 | /// struct DataStorage { 123 | /// immutable: i32, 124 | /// mutable: i32, 125 | /// #[borrows(immutable, mut mutable)] 126 | /// #[not_covariant] 127 | /// complex_data: ComplexData<'this, 'this>, 128 | /// } 129 | /// 130 | /// let mut data_storage = DataStorageBuilder { 131 | /// immutable: 10, 132 | /// mutable: 20, 133 | /// complex_data_builder: |i: &i32, m: &mut i32| ComplexData::new(i, m, 12345), 134 | /// }.build(); 135 | /// data_storage.with_complex_data_mut(|data| { 136 | /// // Copies the value in immutable into mutable. 137 | /// data.transfer(); 138 | /// // Prints 10 139 | /// data.print_bref(); 140 | /// }); 141 | /// } 142 | /// ``` 143 | /// 144 | /// # Covariance 145 | /// Many types in Rust have a property called "covariance". In practical tearms, this means that a 146 | /// covariant type like `Box<&'this i32>` can be used as a `Box<&'a i32>` as long as `'a` is 147 | /// smaller than `'this`. Since the lifetime is smaller, it does not violate the lifetime specified 148 | /// by the original type. Contrast this to `Fn(&'this i32)`, which is not covariant. You cannot give 149 | /// this function a reference with a lifetime shorter than `'this` as the function needs something 150 | /// that lives at *least* as long as `'this`. Unfortunately, there is no easy way to determine 151 | /// whether or not a type is covariant from inside the macro. As such, you may 152 | /// receive a compiler error letting you know that the macro is uncertain if a particular field 153 | /// uses a covariant type. Adding `#[covariant]` or `#[not_covariant]` will resolve this issue. 154 | /// 155 | /// These annotations control whether or not a `borrow_*` method is generated for that field. 156 | /// Incorrectly using one of these tags will result in a compilation error. It is impossible to 157 | /// use them unsoundly. 158 | /// 159 | /// # Async usage 160 | /// All self-referencing structs can be initialized asynchronously by using either the 161 | /// `MyStruct::new_async()` function or the `MyStructAsyncBuilder` builder. Due to limitations of 162 | /// the rust compiler you closures must return a Future trait object wrapped in a `Pin>`. 163 | /// 164 | /// Here is the same example as above in its async version: 165 | /// 166 | /// ```ignore 167 | /// use ouroboros::self_referencing; 168 | /// 169 | /// #[self_referencing] 170 | /// struct MyStruct { 171 | /// int_data: i32, 172 | /// float_data: f32, 173 | /// #[borrows(int_data)] 174 | /// int_reference: &'this i32, 175 | /// #[borrows(mut float_data)] 176 | /// float_reference: &'this mut f32, 177 | /// } 178 | /// 179 | /// #[tokio::main] 180 | /// async fn main() { 181 | /// let mut my_value = MyStructAsyncBuilder { 182 | /// int_data: 42, 183 | /// float_data: 3.14, 184 | /// int_reference_builder: |int_data: &i32| Box::pin(async move { int_data }), 185 | /// float_reference_builder: |float_data: &mut f32| Box::pin(async move { float_data }), 186 | /// }.build().await; 187 | /// 188 | /// // Prints 42 189 | /// println!("{:?}", my_value.borrow_int_data()); 190 | /// // Prints 3.14 191 | /// println!("{:?}", my_value.borrow_float_reference()); 192 | /// // Sets the value of float_data to 84.0 193 | /// my_value.with_mut(|fields| { 194 | /// **fields.float_reference = (**fields.int_reference as f32) * 2.0; 195 | /// }); 196 | /// 197 | /// // We can hold on to this reference... 198 | /// let int_ref = *my_value.borrow_int_reference(); 199 | /// println!("{:?}", *int_ref); 200 | /// // As long as the struct is still alive. 201 | /// drop(my_value); 202 | /// // This will cause an error! 203 | /// // println!("{:?}", *int_ref); 204 | /// } 205 | /// ``` 206 | /// 207 | /// # Async Send 208 | /// When Send trait is needed, the Send variant of async methods and builders is available. 209 | /// 210 | /// Here is the same example as above in its async send version: 211 | /// 212 | /// ```ignore 213 | /// use ouroboros::self_referencing; 214 | /// 215 | /// #[self_referencing] 216 | /// struct MyStruct { 217 | /// int_data: i32, 218 | /// float_data: f32, 219 | /// #[borrows(int_data)] 220 | /// int_reference: &'this i32, 221 | /// #[borrows(mut float_data)] 222 | /// float_reference: &'this mut f32, 223 | /// } 224 | /// 225 | /// #[tokio::main] 226 | /// async fn main() { 227 | /// let mut my_value = MyStructAsyncSendBuilder { 228 | /// int_data: 42, 229 | /// float_data: 3.14, 230 | /// int_reference_builder: |int_data: &i32| Box::pin(async move { int_data }), 231 | /// float_reference_builder: |float_data: &mut f32| Box::pin(async move { float_data }), 232 | /// }.build().await; 233 | /// 234 | /// // Prints 42 235 | /// println!("{:?}", my_value.borrow_int_data()); 236 | /// // Prints 3.14 237 | /// println!("{:?}", my_value.borrow_float_reference()); 238 | /// // Sets the value of float_data to 84.0 239 | /// my_value.with_mut(|fields| { 240 | /// **fields.float_reference = (**fields.int_reference as f32) * 2.0; 241 | /// }); 242 | /// 243 | /// // We can hold on to this reference... 244 | /// let int_ref = *my_value.borrow_int_reference(); 245 | /// println!("{:?}", *int_ref); 246 | /// // As long as the struct is still alive. 247 | /// drop(my_value); 248 | /// // This will cause an error! 249 | /// // println!("{:?}", *int_ref); 250 | /// } 251 | /// ``` 252 | /// 253 | /// # What does the macro generate? 254 | /// The `#[self_referencing]` struct will replace your definition with an unsafe self-referencing 255 | /// struct with a safe public interface. Many functions will be generated depending on your original 256 | /// struct definition. Documentation is generated for all items, so building documentation for 257 | /// your project allows accessing detailed information about available functions. Using 258 | /// `#[self_referencing(no_doc)]` will hide the generated items from documentation if it is becoming 259 | /// too cluttered. 260 | /// 261 | /// ### A quick note on visibility 262 | /// The visibility of generated items is dependent on one of two things. If the 263 | /// generated item is related to a specific field of the struct, it uses the visibility of the 264 | /// original field. (The actual field in the struct will be made private since accessing it could cause 265 | /// undefined behavior.) If the generated item is not related to any particular field, it will by 266 | /// default only be visible to the module the struct is declared in. (This includes things like 267 | /// `new()` and `with()`.) You can use `#[self_referencing(pub_extras)]` to make these items have the 268 | /// same visibility as the struct itself. 269 | /// 270 | /// # List of generated items 271 | /// ### `MyStruct::new(fields...) -> MyStruct` 272 | /// A basic constructor. It accepts values for each field in the order you declared them in. For 273 | /// **head fields**, you only need to pass in what value it should have and it will be moved in 274 | /// to the output. For **self-referencing fields**, you must provide a function or closure which creates 275 | /// the value based on the values it borrows. A field using the earlier example of 276 | /// `#[borrow(a, b, mut c)]` would require a function typed as 277 | /// `FnOnce(a: &_, b: &_, c: &mut _) -> _`. Fields which have an empty borrows annotation 278 | /// (`#[borrows()]`) should have their value directly passed in. A field using the earlier example 279 | /// of `Option<&'this str>` would require an input of `None`. Do not pass a function. Do not collect 280 | /// 200 dollars. 281 | /// ### `MyStruct::new_async(fields...) -> MyStruct` 282 | /// A basic async constructor. It works identically to the sync constructor differing only in the 283 | /// type of closures it expects. Whenever a closure is required it is expected to return a Pinned 284 | /// and Boxed Future that Outputs the same type as the synchronous version. 285 | /// ### `MyStruct::new_async_send(fields...) -> MyStruct` 286 | /// An async send constructor. It works identically to the sync constructor differing only in the 287 | /// Send trait being specified in the return type. 288 | /// ### `MyStructBuilder` 289 | /// This is the preferred way to create a new instance of your struct. It is similar to using the 290 | /// `MyStruct { a, b, c, d }` syntax instead of `MyStruct::new(a, b, c, d)`. It contains one field 291 | /// for every argument in the actual constructor. **Head fields** have the same name that you 292 | /// originally defined them with. **self-referencing fields** are suffixed with `_builder` since you need 293 | /// to provide a function instead of a value. Fields with an empty borrows annotation are not 294 | /// initialized using builders. Calling `.build()` on an instance of `MyStructBuilder` 295 | /// will convert it to an instance of `MyStruct` by calling all `_builder` functions in the order that 296 | /// they were declared and storing their results. 297 | /// ### `MyStructAsyncBuilder` 298 | /// This is the preferred way to asynchronously create a new instance of your struct. It works 299 | /// identically to the synchronous builder differing only in the type of closures it expects. In 300 | /// particular, all builder functions are called serially in the order that they were declared. 301 | /// Whenever a closure is required it is expected to return a Pinned and Boxed Future that Outputs 302 | /// the same type as the synchronous version. 303 | /// ### `MyStructAsyncSendBuilder` 304 | /// Same as MyStructAsyncBuilder, but with Send trait specified in the return type. 305 | /// ### `MyStruct::try_new(fields...) -> Result` 306 | /// Similar to the regular `new()` function, except the functions which create values for all 307 | /// **self-referencing fields** can return `Result<>`s. If any of those are `Err`s, that error will be 308 | /// returned instead of an instance of `MyStruct`. The preferred way to use this function is through 309 | /// `MyStructTryBuilder` and its `try_build()` function. 310 | /// ### `MyStruct::try_new_async(fields...) -> Result` 311 | /// Similar to the regular `new_async()` function, except the functions which create values for all 312 | /// **self-referencing fields** can return `Result<>`s. If any of those are `Err`s, that error will be 313 | /// returned instead of an instance of `MyStruct`. The preferred way to use this function is through 314 | /// `MyStructAsyncTryBuilder` and its `try_build()` function. 315 | /// ### `MyStruct::try_new_async_send(fields...) -> Result` 316 | /// Same as `new_async()` function, but with Send trait specified in the return type. 317 | /// ### `MyStruct::try_new_or_recover_async(fields...) -> Result` 318 | /// Similar to the `try_new_async()` function, except that all the **head fields** are returned along side 319 | /// the original error in case of an error. The preferred way to use this function is through 320 | /// `MyStructAsyncTryBuilder` and its `try_build_or_recover()` function. 321 | /// ### `MyStruct::try_new_or_recover_async_send(fields...) -> Result` 322 | /// Same as `try_new_or_recover_async()` function, but with Send trait specified in the return type. 323 | /// ### `MyStruct::with_FIELD(&self, user: FnOnce(field: &FieldType) -> R) -> R` 324 | /// This function is generated for every **tail and immutably-borrowed field** in your struct. It 325 | /// allows safely accessing 326 | /// a reference to that value. The function generates the reference and passes it to `user`. You 327 | /// can do anything you want with the reference, it is constructed to not outlive the struct. 328 | /// ### `MyStruct::borrow_FIELD(&self) -> &FieldType` 329 | /// This function is generated for every **tail and immutably-borrowed field** in your struct. It 330 | /// is equivalent to calling `my_struct.with_FIELD(|field| field)`. It is only generated for types 331 | /// which are known to be covariant, either through the macro being able to detect it or through the 332 | /// programmer adding the `#[covariant]` annotation to the field. 333 | /// There is no `borrow_FIELD_mut`, unfortunately, as Rust's 334 | /// borrow checker is currently not capable of ensuring that such a method would be used safely. 335 | /// ### `MyStruct::with_FIELD_mut(&mut self, user: FnOnce(field: &mut FieldType) -> R) -> R` 336 | /// This function is generated for every **tail field** in your struct. It is the mutable version 337 | /// of `with_FIELD`. 338 | /// ### `MyStruct::with(&self, user: FnOnce(fields: AllFields) -> R) -> R` 339 | /// Allows borrowing all **tail and immutably-borrowed fields** at once. Functions similarly to 340 | /// `with_FIELD`. 341 | /// ### `MyStruct::with_mut(&self, user: FnOnce(fields: AllFields) -> R) -> R` 342 | /// Allows mutably borrowing all **tail fields** and immutably borrowing all **immutably-borrowed** 343 | /// fields at once. Functions similarly to `with_FIELD_mut`, except that you can borrow multiple 344 | /// fields as mutable at the same time and also have immutable access to any remaining fields. 345 | /// ### `MyStruct::into_heads(self) -> Heads` 346 | /// Drops all self-referencing fields and returns a struct containing all **head fields**. 347 | pub use ouroboros_macro::self_referencing; 348 | 349 | #[doc(hidden)] 350 | pub mod macro_help { 351 | pub extern crate alloc; 352 | 353 | pub use aliasable::boxed::AliasableBox; 354 | pub use static_assertions::assert_impl_all; 355 | use aliasable::boxed::UniqueBox; 356 | 357 | pub struct CheckIfTypeIsStd(core::marker::PhantomData); 358 | 359 | macro_rules! std_type_check { 360 | ($fn_name:ident $T:ident $check_for:ty) => { 361 | impl<$T: ?Sized> CheckIfTypeIsStd<$check_for> { 362 | pub fn $fn_name() {} 363 | } 364 | }; 365 | } 366 | 367 | std_type_check!(is_std_box_type T alloc::boxed::Box); 368 | #[cfg(target_has_atomic = "ptr")] 369 | std_type_check!(is_std_arc_type T alloc::sync::Arc); 370 | std_type_check!(is_std_rc_type T alloc::rc::Rc); 371 | 372 | pub fn aliasable_boxed(data: T) -> AliasableBox { 373 | AliasableBox::from_unique(UniqueBox::new(data)) 374 | } 375 | 376 | pub fn unbox(boxed: AliasableBox) -> T { 377 | *AliasableBox::into_unique(boxed) 378 | } 379 | 380 | /// Converts a reference to an object to a static reference This is 381 | /// obviously unsafe because the compiler can no longer guarantee that the 382 | /// data outlives the reference. It is up to the consumer to get rid of the 383 | /// reference before the container is dropped. The + 'static ensures that 384 | /// whatever we are referring to will remain valid indefinitely, that there 385 | /// are no limitations on how long the pointer itself can live. 386 | /// 387 | /// # Safety 388 | /// 389 | /// The caller must ensure that the returned reference is not used after the originally passed 390 | /// reference would become invalid. 391 | pub unsafe fn change_lifetime<'old, 'new: 'old, T: 'new>(data: &'old T) -> &'new T { 392 | &*(data as *const _) 393 | } 394 | 395 | /// Like change_lifetime, but for mutable references. 396 | /// 397 | /// # Safety 398 | /// 399 | /// The caller must ensure that the returned reference is not used after the originally passed 400 | /// reference would become invalid. 401 | pub unsafe fn change_lifetime_mut<'old, 'new: 'old, T: 'new>(data: &'old mut T) -> &'new mut T { 402 | &mut *(data as *mut _) 403 | } 404 | } 405 | --------------------------------------------------------------------------------