diff --git a/.gitignore b/.gitignore index 5a51787e86..62e8d7dec7 100755 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /target /node_modules /.module +/.data /package-lock.json /Cargo.lock /.vscode diff --git a/Cargo.toml b/Cargo.toml index 787b070893..1b52be3898 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,7 +104,7 @@ default-features = false features = [ "enabled" ] [workspace.dependencies.collection_tools] -version = "~0.8.0" +version = "~0.9.0" path = "module/core/collection_tools" default-features = false @@ -159,16 +159,22 @@ default-features = false features = [ "enabled" ] [workspace.dependencies.clone_dyn] -version = "~0.18.0" +version = "~0.19.0" path = "module/core/clone_dyn" default-features = false features = [ "enabled" ] [workspace.dependencies.clone_dyn_meta] -version = "~0.18.0" +version = "~0.19.0" path = "module/core/clone_dyn_meta" features = [ "enabled" ] +[workspace.dependencies.clone_dyn_types] +version = "~0.20.0" +path = "module/core/clone_dyn_types" +default-features = false +features = [ "enabled" ] + ## mem @@ -189,7 +195,7 @@ default-features = false ## iter [workspace.dependencies.iter_tools] -version = "~0.17.0" +version = "~0.18.0" path = "module/core/iter_tools" default-features = false @@ -207,7 +213,7 @@ path = "module/core/for_each" default-features = false [workspace.dependencies.former] -version = "~2.3.0" +version = "~2.4.0" path = "module/core/former" default-features = false @@ -217,12 +223,12 @@ default-features = false # default-features = false [workspace.dependencies.former_meta] -version = "~2.3.0" +version = "~2.4.0" path = "module/core/former_meta" default-features = false [workspace.dependencies.former_types] -version = "~2.4.0" +version = "~2.5.0" path = "module/core/former_types" default-features = false @@ -267,7 +273,7 @@ default-features = false ## macro tools [workspace.dependencies.macro_tools] -version = "~0.30.0" +version = "~0.32.0" path = "module/core/macro_tools" default-features = false diff --git a/module/core/clone_dyn/Cargo.toml b/module/core/clone_dyn/Cargo.toml index 0c2804d339..a4110df3bd 100644 --- a/module/core/clone_dyn/Cargo.toml +++ b/module/core/clone_dyn/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clone_dyn" -version = "0.18.0" +version = "0.19.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", @@ -23,18 +23,20 @@ workspace = true [package.metadata.docs.rs] features = [ "full" ] all-features = false -# exclude = [ "/tests", "/examples", "-*" ] [features] -default = [ "enabled" ] -full = [ "enabled" ] -no_std = [] -use_alloc = [ "no_std" ] -enabled = [ "clone_dyn_meta/enabled" ] +default = [ "enabled", "clone_dyn_types", "clone_dyn_meta" ] +full = [ "enabled", "clone_dyn_types", "clone_dyn_meta" ] +enabled = [] + +clone_dyn_types = [ "dep:clone_dyn_types", "clone_dyn_types/enabled" ] +clone_dyn_meta = [ "dep:clone_dyn_meta", "clone_dyn_meta/enabled", "clone_dyn_types" ] [dependencies] -clone_dyn_meta = { workspace = true } +clone_dyn_meta = { workspace = true, optional = true } +clone_dyn_types = { workspace = true, optional = true } [dev-dependencies] test_tools = { workspace = true } +inspect_type = { workspace = true, features = [ "full" ] } diff --git a/module/core/clone_dyn/Readme.md b/module/core/clone_dyn/Readme.md index 4a8efa5ae2..eda69277ee 100644 --- a/module/core/clone_dyn/Readme.md +++ b/module/core/clone_dyn/Readme.md @@ -10,28 +10,207 @@ By default, Rust does not support cloning for trait objects due to the `Clone` t ### Alternative -There are few alternatives [dyn-clone](https://github.com/dtolnay/dyn-clone), [dyn-clonable](https://github.com/kardeiz/objekt-clonable). Unlike other options, this solution is more concise and demands less effort to use, all without compromising the quality of the outcome. Also, you can ask an inquiry and get answers, which is problematic in the case of alternatives. +There are few alternatives [dyn-clone](https://github.com/dtolnay/dyn-clone), [dyn-clonable](https://github.com/kardeiz/objekt-clonable). Unlike other options, this solution is more concise and demands less effort to use, all without compromising the quality of the outcome. -### Basic use-case +## Basic use-case + +Demonstrates the usage of `clone_dyn` to enable cloning for trait objects. + +By default, Rust does not support cloning for trait objects due to the `Clone` trait +requiring compile-time knowledge of the type's size. The `clone_dyn` crate addresses +this limitation through procedural macros, allowing for cloning collections of trait objects. + +##### Overview + +This example shows how to use the `clone_dyn` crate to enable cloning for trait objects, +specifically for iterators. It defines a custom trait, `IterTrait`, that encapsulates +an iterator with specific characteristics and demonstrates how to use `CloneDyn` to +overcome the object safety constraints of the `Clone` trait. + +##### The `IterTrait` Trait + +The `IterTrait` trait is designed to represent iterators that yield references to items (`&'a T`). +These iterators must also implement the `ExactSizeIterator` and `DoubleEndedIterator` traits. +Additionally, the iterator must implement the `CloneDyn` trait, which allows cloning of trait objects. + +The trait is implemented for any type that meets the specified requirements. + +##### Cloning Trait Objects + +Rust's type system does not allow trait objects to implement the `Clone` trait directly due to object safety constraints. +Specifically, the `Clone` trait requires knowledge of the concrete type at compile time, which is not available for trait objects. + +The `CloneDyn` trait from the `clone_dyn` crate provides a workaround for this limitation by allowing trait objects to be cloned. +Procedural macros generates the necessary code for cloning trait objects, making it possible to clone collections of trait objects. + +The example demonstrates how to implement `Clone` for boxed `IterTrait` trait objects. + +##### `get_iter` Function + +The `get_iter` function returns a boxed iterator that implements the `IterTrait` trait. +If the input is `Some`, it returns an iterator over the vector. +If the input is `None`, it returns an empty iterator. + +It's not possible to use `impl Iterator` here because the code returns iterators of two different types: +- `std::slice::Iter` when the input is `Some`. +- `std::iter::Empty` when the input is `None`. + +To handle this, the function returns a trait object ( `Box< dyn IterTrait >` ). +However, Rust's `Clone` trait cannot be implemented for trait objects due to object safety constraints. +The `CloneDyn` trait addresses this problem by enabling cloning of trait objects. + +##### `use_iter` Function + +The `use_iter` function demonstrates the use of the `CloneDyn` trait by cloning the iterator. +It then iterates over the cloned iterator and prints each element. + +##### Main Function + +The main function demonstrates the overall usage by creating a vector, obtaining an iterator, and using the iterator to print elements. - ```rust -# #[ cfg( all( feature = "enabled", any( not( feature = "no_std" ), feature = "use_alloc" ) ) ) ] +# #[ cfg( not( feature = "enabled" ) ) ] +# fn main() {} +# #[ cfg( feature = "enabled" ) ] +# fn main() # { - use clone_dyn::clone_dyn; + use clone_dyn::{ clone_dyn, CloneDyn }; + + /// Trait that encapsulates an iterator with specific characteristics, tailored for your needs. #[ clone_dyn ] - trait Trait1 + pub trait IterTrait< 'a, T > + where + T : 'a, + Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, + // Self : CloneDyn, + // no need to explicitly to define this bound, because macro will do it for you anyway + { + } + + impl< 'a, T, I > IterTrait< 'a, T > for I + where + T : 'a, + Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, + Self : CloneDyn, + { + } + + /// + /// Function to get an iterator over a vector of integers. + /// + /// This function returns a boxed iterator that implements the `IterTrait` trait. + /// If the input is `Some`, it returns an iterator over the vector. + /// If the input is `None`, it returns an empty iterator. + /// + /// Rust's type system does not allow trait objects to implement the `Clone` trait directly due to object safety constraints. + /// Specifically, the `Clone` trait requires knowledge of the concrete type at compile time, which is not available for trait objects. + /// + /// In this example, we need to return an iterator that can be cloned. Since we are returning a trait object ( `Box< dyn IterTrait >` ), + /// we cannot directly implement `Clone` for this trait object. This is where the `CloneDyn` trait from the `clone_dyn` crate comes in handy. + /// + /// The `CloneDyn` trait provides a workaround for this limitation by allowing trait objects to be cloned. + /// It uses procedural macros to generate the necessary code for cloning trait objects, making it possible to clone collections of trait objects. + /// + /// It's not possible to use `impl Iterator` here because the code returns iterators of two different types: + /// - `std::slice::Iter` when the input is `Some`. + /// - `std::iter::Empty` when the input is `None`. + /// + /// To handle this, the function returns a trait object (`Box`). + /// However, Rust's `Clone` trait cannot be implemented for trait objects due to object safety constraints. + /// The `CloneDyn` trait addresses this problem by enabling cloning of trait objects. + + pub fn get_iter< 'a >( src : Option< &'a Vec< i32 > > ) -> Box< dyn IterTrait< 'a, &'a i32 > + 'a > { + match &src + { + Some( src ) => Box::new( src.iter() ), + _ => Box::new( core::iter::empty() ), + } } - let vec = Vec::< Box< dyn Trait1 > >::new(); - let vec2 = vec.clone(); /* <- it does not work without `clone_dyn` */ + /// Function to use an iterator and print its elements. + /// + /// This function demonstrates the use of the `CloneDyn` trait by cloning the iterator. + /// It then iterates over the cloned iterator and prints each element. + pub fn use_iter< 'a >( iter : Box< dyn IterTrait< 'a, &'a i32 > + 'a > ) + { + // Clone would not be available if CloneDyn is not implemented for the iterator. + // And being an object-safe trait, it can't implement Clone. + // Nevertheless, thanks to CloneDyn, the object is clonable. + // + // This line demonstrates cloning the iterator and iterating over the cloned iterator. + iter.clone().for_each( | e | println!( "{e}" ) ); + + // Iterate over the original iterator and print each element. + iter.for_each( | e | println!( "{e}" ) ); + } + + // Create a vector of integers. + let data = vec![ 1, 2, 3 ]; + // Get an iterator over the vector. + let iter = get_iter( Some( &data ) ); + // Use the iterator to print its elements. + use_iter( iter ); + # } ``` - +
+If you use multithreading or asynchronous paradigms implement trait `Clone` also for `Send` and `Sync` + +```rust, ignore + +#[ allow( non_local_definitions ) ] +impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self + { + clone_dyn::clone_into_box( &**self ) + } +} + +#[ allow( non_local_definitions ) ] +impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + Send + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self + { + clone_dyn::clone_into_box( &**self ) + } +} + +#[ allow( non_local_definitions ) ] +impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + Sync + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self + { + clone_dyn::clone_into_box( &**self ) + } +} + +#[ allow( non_local_definitions ) ] +impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + Send + Sync + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self + { + clone_dyn::clone_into_box( &**self ) + } +} + +``` + +
+ +
+ +Try out `cargo run --example clone_dyn_trivial`. +
+[See code](./examples/clone_dyn_trivial.rs). ### To add to your project diff --git a/module/core/clone_dyn/examples/clone_dyn_trivial.rs b/module/core/clone_dyn/examples/clone_dyn_trivial.rs index 980bb02488..e14bbc9a8a 100644 --- a/module/core/clone_dyn/examples/clone_dyn_trivial.rs +++ b/module/core/clone_dyn/examples/clone_dyn_trivial.rs @@ -1,24 +1,142 @@ +//! +//! ## Basic use-case +//! //! Demonstrates the usage of `clone_dyn` to enable cloning for trait objects. //! //! By default, Rust does not support cloning for trait objects due to the `Clone` trait //! requiring compile-time knowledge of the type's size. The `clone_dyn` crate addresses //! this limitation through procedural macros, allowing for cloning collections of trait objects. +//! +//! ##### Overview +//! +//! This example shows how to use the `clone_dyn` crate to enable cloning for trait objects, +//! specifically for iterators. It defines a custom trait, `IterTrait`, that encapsulates +//! an iterator with specific characteristics and demonstrates how to use `CloneDyn` to +//! overcome the object safety constraints of the `Clone` trait. +//! +//! ##### The `IterTrait` Trait +//! +//! The `IterTrait` trait is designed to represent iterators that yield references to items (`&'a T`). +//! These iterators must also implement the `ExactSizeIterator` and `DoubleEndedIterator` traits. +//! Additionally, the iterator must implement the `CloneDyn` trait, which allows cloning of trait objects. +//! +//! The trait is implemented for any type that meets the specified requirements. +//! +//! ##### Cloning Trait Objects +//! +//! Rust's type system does not allow trait objects to implement the `Clone` trait directly due to object safety constraints. +//! Specifically, the `Clone` trait requires knowledge of the concrete type at compile time, which is not available for trait objects. +//! +//! The `CloneDyn` trait from the `clone_dyn` crate provides a workaround for this limitation by allowing trait objects to be cloned. +//! Procedural macros generates the necessary code for cloning trait objects, making it possible to clone collections of trait objects. +//! +//! The example demonstrates how to implement `Clone` for boxed `IterTrait` trait objects. +//! +//! ##### `get_iter` Function +//! +//! The `get_iter` function returns a boxed iterator that implements the `IterTrait` trait. +//! If the input is `Some`, it returns an iterator over the vector. +//! If the input is `None`, it returns an empty iterator. +//! +//! It's not possible to use `impl Iterator` here because the code returns iterators of two different types: +//! - `std::slice::Iter` when the input is `Some`. +//! - `std::iter::Empty` when the input is `None`. +//! +//! To handle this, the function returns a trait object ( `Box< dyn IterTrait >` ). +//! However, Rust's `Clone` trait cannot be implemented for trait objects due to object safety constraints. +//! The `CloneDyn` trait addresses this problem by enabling cloning of trait objects. +//! +//! ##### `use_iter` Function +//! +//! The `use_iter` function demonstrates the use of the `CloneDyn` trait by cloning the iterator. +//! It then iterates over the cloned iterator and prints each element. +//! +//! ##### Main Function +//! +//! The main function demonstrates the overall usage by creating a vector, obtaining an iterator, and using the iterator to print elements. +//! -#[ cfg( any( not( feature = "enabled" ), all( feature = "no_std", not( feature = "use_alloc" ) ) ) ) ] +#[ cfg( not( feature = "enabled" ) ) ] fn main() {} - -#[ cfg( all( feature = "enabled", any( not( feature = "no_std" ), feature = "use_alloc" ) ) ) ] +#[ cfg( feature = "enabled" ) ] fn main() { + use clone_dyn::{ clone_dyn, CloneDyn }; - use clone_dyn::clone_dyn; - + /// Trait that encapsulates an iterator with specific characteristics, tailored for your needs. #[ clone_dyn ] - trait Trait1 + pub trait IterTrait< 'a, T > + where + T : 'a, + Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, + // Self : CloneDyn, + // no need to explicitly to define this bound, because macro will do it for you anyway + { + } + + impl< 'a, T, I > IterTrait< 'a, T > for I + where + T : 'a, + Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, + Self : CloneDyn, { } - let vec = Vec::< Box< dyn Trait1 > >::new(); - let _vec2 = vec.clone(); /* <- it does not work without `clone_dyn` */ + /// + /// Function to get an iterator over a vector of integers. + /// + /// This function returns a boxed iterator that implements the `IterTrait` trait. + /// If the input is `Some`, it returns an iterator over the vector. + /// If the input is `None`, it returns an empty iterator. + /// + /// Rust's type system does not allow trait objects to implement the `Clone` trait directly due to object safety constraints. + /// Specifically, the `Clone` trait requires knowledge of the concrete type at compile time, which is not available for trait objects. + /// + /// In this example, we need to return an iterator that can be cloned. Since we are returning a trait object ( `Box< dyn IterTrait >` ), + /// we cannot directly implement `Clone` for this trait object. This is where the `CloneDyn` trait from the `clone_dyn` crate comes in handy. + /// + /// The `CloneDyn` trait provides a workaround for this limitation by allowing trait objects to be cloned. + /// It uses procedural macros to generate the necessary code for cloning trait objects, making it possible to clone collections of trait objects. + /// + /// It's not possible to use `impl Iterator` here because the code returns iterators of two different types: + /// - `std::slice::Iter` when the input is `Some`. + /// - `std::iter::Empty` when the input is `None`. + /// + /// To handle this, the function returns a trait object (`Box`). + /// However, Rust's `Clone` trait cannot be implemented for trait objects due to object safety constraints. + /// The `CloneDyn` trait addresses this problem by enabling cloning of trait objects. + + pub fn get_iter< 'a >( src : Option< &'a Vec< i32 > > ) -> Box< dyn IterTrait< 'a, &'a i32 > + 'a > + { + match &src + { + Some( src ) => Box::new( src.iter() ), + _ => Box::new( core::iter::empty() ), + } + } + + /// Function to use an iterator and print its elements. + /// + /// This function demonstrates the use of the `CloneDyn` trait by cloning the iterator. + /// It then iterates over the cloned iterator and prints each element. + pub fn use_iter< 'a >( iter : Box< dyn IterTrait< 'a, &'a i32 > + 'a > ) + { + // Clone would not be available if CloneDyn is not implemented for the iterator. + // And being an object-safe trait, it can't implement Clone. + // Nevertheless, thanks to CloneDyn, the object is clonable. + // + // This line demonstrates cloning the iterator and iterating over the cloned iterator. + iter.clone().for_each( | e | println!( "{e}" ) ); + + // Iterate over the original iterator and print each element. + iter.for_each( | e | println!( "{e}" ) ); + } + + // Create a vector of integers. + let data = vec![ 1, 2, 3 ]; + // Get an iterator over the vector. + let iter = get_iter( Some( &data ) ); + // Use the iterator to print its elements. + use_iter( iter ); } diff --git a/module/core/clone_dyn/src/lib.rs b/module/core/clone_dyn/src/lib.rs index 54e6f3ef40..251186abd6 100644 --- a/module/core/clone_dyn/src/lib.rs +++ b/module/core/clone_dyn/src/lib.rs @@ -1,61 +1,24 @@ -#![ cfg_attr( feature = "no_std", no_std ) ] +#![ no_std ] #![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ] #![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ] #![ doc( html_root_url = "https://docs.rs/clone_dyn/latest/clone_dyn/" ) ] #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] -#[ allow( unused_extern_crates ) ] -#[ cfg( all( feature = "no_std", feature = "use_alloc" ) ) ] -extern crate alloc; - /// Namespace with dependencies. #[ cfg( feature = "enabled" ) ] pub mod dependency { + #[ cfg( feature = "clone_dyn_meta" ) ] pub use ::clone_dyn_meta; + #[ cfg( feature = "clone_dyn_types" ) ] + pub use ::clone_dyn_types; } /// Internal namespace. -#[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] #[ cfg( feature = "enabled" ) ] pub( crate ) mod private { - - #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] - extern crate alloc; - #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] - #[ allow( unused_imports ) ] - use alloc::boxed::Box; - #[ cfg( all( feature = "use_std", not( feature = "use_alloc" ) ) ) ] - use std::boxed::Box; - - /// Clone boxed dyn. - /// - /// Not intended to be used directly. - #[ inline ] - pub fn _clone_boxed< T >( t : &T ) -> Box< T > - where - T : ?Sized, - { - // Explanation for the use of `unsafe`: - // The `unsafe` block is necessary here because we're performing low-level memory manipulations - // that cannot be checked by the Rust compiler for safety. Specifically, we're manually handling - // raw pointers and converting them to and from `Box< T >`, which is considered unsafe as it - // bypasses Rust's ownership and borrowing rules. This is done to dynamically clone a boxed - // trait object, which doesn't support cloning through the standard `Clone` trait. The operations - // within this block are carefully crafted to ensure memory safety manually, including proper - // allocation and deallocation of heap memory for the clone. - #[ allow( unsafe_code ) ] - unsafe - { - let mut ptr = t as *const T; - let data_ptr = &mut ptr as *mut *const T as *mut *mut (); - *data_ptr = Box::into_raw( Box::new( < &T >::clone( &t ) ) ) as *mut (); - Box::from_raw( ptr as *mut T ) - } - } - } #[ cfg( feature = "enabled" ) ] @@ -76,9 +39,16 @@ pub mod protected #[ cfg( feature = "enabled" ) ] pub mod orphan { + #[ doc( inline ) ] #[ allow( unused_imports ) ] pub use super::exposed::*; + + #[ doc( inline ) ] + #[ allow( unused_imports ) ] + #[ cfg( feature = "clone_dyn_types" ) ] + pub use super::dependency::clone_dyn_types::exposed::*; + } /// Exposed namespace of the module. @@ -94,12 +64,15 @@ pub mod exposed #[ cfg( feature = "enabled" ) ] pub mod prelude { + #[ doc( inline ) ] #[ allow( unused_imports ) ] - #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] + #[ cfg( feature = "clone_dyn_meta" ) ] pub use ::clone_dyn_meta::clone_dyn; + #[ doc( inline ) ] #[ allow( unused_imports ) ] - #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] - pub use super::private::_clone_boxed; + #[ cfg( feature = "clone_dyn_types" ) ] + pub use super::dependency::clone_dyn_types::prelude::*; + } diff --git a/module/core/clone_dyn/tests/inc/basic.rs b/module/core/clone_dyn/tests/inc/basic.rs new file mode 100644 index 0000000000..55e7eee3cd --- /dev/null +++ b/module/core/clone_dyn/tests/inc/basic.rs @@ -0,0 +1,57 @@ + +#[ allow( unused_imports ) ] +use super::*; + +use the_module::clone_dyn; + +#[ clone_dyn ] +trait Trait1 +{ + fn val( &self ) -> i32; +} + +// + +impl Trait1 for i32 +{ + fn val( &self ) -> i32 + { + *self + } +} + +impl Trait1 for i64 +{ + fn val( &self ) -> i32 + { + self.clone().try_into().unwrap() + } +} + +impl Trait1 for String +{ + fn val( &self ) -> i32 + { + self.len().try_into().unwrap() + } +} + +impl< T > Trait1 for &[ T ] +where + T : the_module::CloneDyn, +{ + fn val( &self ) -> i32 + { + self.len().try_into().unwrap() + } +} + +impl Trait1 for &str +{ + fn val( &self ) -> i32 + { + self.len().try_into().unwrap() + } +} + +include!( "./only_test/basic.rs" ); diff --git a/module/core/clone_dyn/tests/inc/basic_manual.rs b/module/core/clone_dyn/tests/inc/basic_manual.rs new file mode 100644 index 0000000000..04ff392acb --- /dev/null +++ b/module/core/clone_dyn/tests/inc/basic_manual.rs @@ -0,0 +1,95 @@ + +#[ allow( unused_imports ) ] +use super::*; + +trait Trait1 +where + Self : the_module::CloneDyn, +{ + fn val( &self ) -> i32; +} + +// + +impl Trait1 for i32 +{ + fn val( &self ) -> i32 + { + *self + } +} + +impl Trait1 for i64 +{ + fn val( &self ) -> i32 + { + self.clone().try_into().unwrap() + } +} + +impl Trait1 for String +{ + fn val( &self ) -> i32 + { + self.len().try_into().unwrap() + } +} + +impl< T > Trait1 for &[ T ] +where + T : the_module::CloneDyn, +{ + fn val( &self ) -> i32 + { + self.len().try_into().unwrap() + } +} + +impl Trait1 for &str +{ + fn val( &self ) -> i32 + { + self.len().try_into().unwrap() + } +} + +// == begin of generated + +#[ allow( non_local_definitions ) ] +impl < 'c > Clone +for Box< dyn Trait1 + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self + { + the_module::clone_into_box( &**self ) + } +} + +#[ allow( non_local_definitions ) ] +impl < 'c > Clone +for Box< dyn Trait1 + Send + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self { the_module::clone_into_box( &**self ) } +} + +#[ allow( non_local_definitions ) ] +impl < 'c > Clone +for Box< dyn Trait1 + Sync + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self { the_module::clone_into_box( &**self ) } +} + +#[ allow( non_local_definitions ) ] +impl < 'c > Clone +for Box< dyn Trait1 + Send + Sync + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self { the_module::clone_into_box( &**self ) } +} + +// == end of generated + +include!( "./only_test/basic.rs" ); diff --git a/module/core/clone_dyn/tests/inc/mod.rs b/module/core/clone_dyn/tests/inc/mod.rs index 99cee0a3c6..8b790f55cf 100644 --- a/module/core/clone_dyn/tests/inc/mod.rs +++ b/module/core/clone_dyn/tests/inc/mod.rs @@ -2,159 +2,7 @@ #[ allow( unused_imports ) ] use super::*; -// +mod basic_manual; +mod basic; +mod parametrized; -tests_impls! -{ - - // - - // qqq : organize tests in the same way tests organized for derive_tools - fn manual() - { - - trait Trait1 - { - } - - // - - #[ inline ] - pub fn _clone_boxed< T >( t : &T ) -> Box< T > - where - T : ?Sized, - { - unsafe - { - let mut ptr = t as *const T; - let data_ptr = &mut ptr as *mut *const T as *mut *mut (); - *data_ptr = Box::into_raw( Box::new( t.clone() ) ) as *mut (); - Box::from_raw( ptr as *mut T ) - } - } - - // - - #[ allow( non_local_definitions ) ] - impl < 'c > Clone - for Box< dyn Trait1 + 'c > - { - #[ inline ] - fn clone( &self ) -> Self { _clone_boxed( &**self ) } - } - - #[ allow( non_local_definitions ) ] - impl < 'c > Clone - for Box< dyn Trait1 + Send + 'c > - { - #[ inline ] - fn clone( &self ) -> Self { _clone_boxed( &**self ) } - } - - #[ allow( non_local_definitions ) ] - impl < 'c > Clone - for Box< dyn Trait1 + Sync + 'c > - { - #[ inline ] - fn clone( &self ) -> Self { _clone_boxed( &**self ) } - } - - #[ allow( non_local_definitions ) ] - impl < 'c > Clone - for Box< dyn Trait1 + Send + Sync + 'c > - { - #[ inline ] - fn clone( &self ) -> Self { _clone_boxed( &**self ) } - } - - // - - let vec = Vec::< Box< dyn Trait1 > >::new(); - let vec2 = vec.clone(); - - } - - // - - fn basic() - { - use the_module::clone_dyn; - - #[ clone_dyn ] - trait Trait1 - { - } - - // - - let vec = Vec::< Box< dyn Trait1 > >::new(); - let vec2 = vec.clone(); - - } - - // - - fn prelude() - { - use the_module::prelude::*; - - #[ clone_dyn ] - trait Trait1 - { - } - - // - - let vec = Vec::< Box< dyn Trait1 > >::new(); - let vec2 = vec.clone(); - - } - - // - - fn parametrized() - { - use the_module::clone_dyn; - - #[ clone_dyn ] - trait Trait2< T1 : Copy, T2 : Copy > - where - T2 : Clone + core::fmt::Debug, - { - } - - // - - let vec = Vec::< Box< dyn Trait2< i32, f32 > > >::new(); - let vec2 = vec.clone(); - - } - - // - - fn sample() - { - use the_module::clone_dyn; - - #[ clone_dyn ] - trait Trait1 - { - } - - let vec = Vec::< Box< dyn Trait1 > >::new(); - let vec2 = vec.clone(); /* <- it does not work without `clone_dyn` */ - - } - -} - -// - -tests_index! -{ - manual, - basic, - prelude, - parametrized, - sample, -} diff --git a/module/core/clone_dyn/tests/inc/only_test/basic.rs b/module/core/clone_dyn/tests/inc/only_test/basic.rs new file mode 100644 index 0000000000..1ae447ea14 --- /dev/null +++ b/module/core/clone_dyn/tests/inc/only_test/basic.rs @@ -0,0 +1,103 @@ + +#[ test ] +fn clone_into_box() +{ + + // copyable + + let a : i32 = 13; + let b : Box< i32 > = the_module::clone_into_box( &a ); + a_id!( a, *b ); + + // clonable + + let a : String = "abc".to_string(); + let b : Box< String > = the_module::clone_into_box( &a ); + a_id!( a, *b ); + + // str slice + + let a : &str = "abc"; + let b : Box< str > = the_module::clone_into_box( a ); + a_id!( *a, *b ); + + // slice + + let a : &[ i32 ] = &[ 1, 2, 3 ]; + let b : Box< [ i32 ] > = the_module::clone_into_box( a ); + a_id!( *a, *b ); + + // + +} + +#[ test ] +fn clone() +{ + + // copyable + + let a : i32 = 13; + let b : i32 = the_module::clone( &a ); + a_id!( a, b ); + + // clonable + + let a : String = "abc".to_string(); + let b : String = the_module::clone( &a ); + a_id!( a, b ); + + // str slice + + let a : &str = "abc"; + let b : &str = the_module::clone( &a ); + a_id!( a, b ); + + // slice + + let a : &[ i32 ] = &[ 1, 2, 3 ]; + let b : &[ i32 ] = the_module::clone( &a ); + a_id!( a, b ); + + // + +} + +#[ test ] +fn basic() +{ + + // + + let e_i32 : Box< dyn Trait1 > = Box::new( 13 ); + let e_i64 : Box< dyn Trait1 > = Box::new( 14 ); + let e_string : Box< dyn Trait1 > = Box::new( "abc".to_string() ); + let e_str_slice : Box< dyn Trait1 > = Box::new( "abcd" ); + let e_slice : Box< dyn Trait1 > = Box::new( &[ 1i32, 2i32 ] as &[ i32 ] ); + + // + + let vec : Vec< Box< dyn Trait1 > > = vec![ e_i32.clone(), e_i64.clone(), e_string.clone(), e_str_slice.clone(), e_slice.clone() ]; + let vec = vec.iter().map( | e | e.val() ).collect::< Vec< _ > >(); + let vec2 = vec![ 13, 14, 3, 4, 2 ]; + a_id!( vec, vec2 ); + + // + + let vec : Vec< Box< dyn Trait1 > > = vec![ e_i32.clone(), e_i64.clone(), e_string.clone(), e_str_slice.clone(), e_slice.clone() ]; + let vec2 = the_module::clone( &vec ); + let vec = vec.iter().map( | e | e.val() ).collect::< Vec< _ > >(); + let vec2 = vec2.iter().map( | e | e.val() ).collect::< Vec< _ > >(); + a_id!( vec, vec2 ); + + // + + let vec : Vec< Box< dyn Trait1 > > = vec![ e_i32.clone(), e_i64.clone(), e_string.clone(), e_str_slice.clone(), e_slice.clone() ]; + let vec2 = vec.clone(); + let vec = vec.iter().map( | e | e.val() ).collect::< Vec< _ > >(); + let vec2 = vec2.iter().map( | e | e.val() ).collect::< Vec< _ > >(); + a_id!( vec, vec2 ); + + // + +} diff --git a/module/core/clone_dyn/tests/inc/parametrized.rs b/module/core/clone_dyn/tests/inc/parametrized.rs new file mode 100644 index 0000000000..851acf30b0 --- /dev/null +++ b/module/core/clone_dyn/tests/inc/parametrized.rs @@ -0,0 +1,130 @@ + +#[ allow( unused_imports ) ] +use super::*; +use the_module::prelude::*; + +// + +#[ clone_dyn ] +trait Trait1< T1 : ::core::fmt::Debug, T2 > +where + T2 : ::core::fmt::Debug, + Self : ::core::fmt::Debug, +{ + fn dbg( &self ) -> String + { + format!( "{:?}", self ) + } +} + +// + +#[ derive( Debug, Clone ) ] +struct Struct1< T1, T2 > +where + T1 : ::core::fmt::Debug, + T2 : ::core::fmt::Debug, +{ + a : T1, + b : T2, +} + +impl Trait1< i32, char > for Struct1< i32, char > +{ + fn dbg( &self ) -> String + { + format!( "{self:?}( {:?} {:?} )", self.a, self.b ) + } +} + +// + +impl Trait1< i32, char > for i32 +{ + fn dbg( &self ) -> String + { + format!( "{:?}", self ) + } +} + +impl Trait1< i32, char > for i64 +{ + fn dbg( &self ) -> String + { + format!( "{:?}", self ) + } +} + +impl Trait1< i32, char > for String +{ + fn dbg( &self ) -> String + { + format!( "{:?}", self ) + } +} + +impl< T > Trait1< i32, char > for &[ T ] +where + T : the_module::CloneDyn, + Self : ::core::fmt::Debug, +{ + fn dbg( &self ) -> String + { + format!( "{:?}", self ) + } +} + +impl Trait1< i32, char > for &str +{ + fn dbg( &self ) -> String + { + format!( "{:?}", self ) + } +} + + +#[ test ] +fn basic() +{ + + // + + let e_i32 : Box< dyn Trait1< i32, char > > = Box::new( 13 ); + let e_i64 : Box< dyn Trait1< i32, char > > = Box::new( 14 ); + let e_string : Box< dyn Trait1< i32, char > > = Box::new( "abc".to_string() ); + let e_str_slice : Box< dyn Trait1< i32, char > > = Box::new( "abcd" ); + let e_slice : Box< dyn Trait1< i32, char > > = Box::new( &[ 1i32, 2i32 ] as &[ i32 ] ); + + // + + let vec : Vec< Box< dyn Trait1< i32, char > > > = vec![ e_i32.clone(), e_i64.clone(), e_string.clone(), e_str_slice.clone(), e_slice.clone() ]; + let vec = vec.iter().map( | e | e.dbg() ).collect::< Vec< _ > >(); + let vec2 = vec! + [ + "13".to_string(), + "14".to_string(), + "\"abc\"".to_string(), + "\"abcd\"".to_string(), + "[1, 2]".to_string(), + ]; + a_id!( vec, vec2 ); + + // + + let vec : Vec< Box< dyn Trait1< i32, char > > > = vec![ e_i32.clone(), e_i64.clone(), e_string.clone(), e_str_slice.clone(), e_slice.clone() ]; + let vec2 = the_module::clone( &vec ); + let vec = vec.iter().map( | e | e.dbg() ).collect::< Vec< _ > >(); + let vec2 = vec2.iter().map( | e | e.dbg() ).collect::< Vec< _ > >(); + a_id!( vec, vec2 ); + + // + + let vec : Vec< Box< dyn Trait1< i32, char > > > = vec![ e_i32.clone(), e_i64.clone(), e_string.clone(), e_str_slice.clone(), e_slice.clone() ]; + let vec2 = vec.clone(); + let vec = vec.iter().map( | e | e.dbg() ).collect::< Vec< _ > >(); + let vec2 = vec2.iter().map( | e | e.dbg() ).collect::< Vec< _ > >(); + a_id!( vec, vec2 ); + + // + +} diff --git a/module/core/clone_dyn_meta/Cargo.toml b/module/core/clone_dyn_meta/Cargo.toml index 3b371d1629..e8b060725b 100644 --- a/module/core/clone_dyn_meta/Cargo.toml +++ b/module/core/clone_dyn_meta/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clone_dyn_meta" -version = "0.18.0" +version = "0.19.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", @@ -31,10 +31,14 @@ proc-macro = true [features] default = [ "enabled" ] full = [ "enabled" ] -enabled = [ "macro_tools/enabled" ] +enabled = [ "macro_tools/enabled", "former_types/enabled" ] [dependencies] -macro_tools = { workspace = true } +macro_tools = { workspace = true } # qqq : xxx : optimize set of features +former_types = { workspace = true, features = [ "types_component_assign" ] } +# xxx : incapsulate into macro_tools +const_format = { version = "0.2.32" } +# xxx : incapsulate into macro_tools [dev-dependencies] test_tools = { workspace = true } diff --git a/module/core/clone_dyn_meta/src/derive.rs b/module/core/clone_dyn_meta/src/derive.rs index cb006d1a9e..40e1cb9de0 100644 --- a/module/core/clone_dyn_meta/src/derive.rs +++ b/module/core/clone_dyn_meta/src/derive.rs @@ -1,69 +1,185 @@ use macro_tools::prelude::*; -use macro_tools::{ Result, generic_params }; +use macro_tools:: +{ + Result, + AttributePropertyOptionalSingletone, + AttributePropertyComponent, + diag, + generic_params, +}; +use former_types::{ Assign }; +// use const_format::concatcp; +// xxx : incapsulate into macro_tools and put all that under features // -pub fn clone_dyn( _attr : proc_macro::TokenStream, item : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStream > +pub fn clone_dyn( attr_input : proc_macro::TokenStream, item_input : proc_macro::TokenStream ) +-> Result< proc_macro2::TokenStream > { - let item_parsed = match syn::parse::< syn::ItemTrait >( item ) + let attrs = syn::parse::< ItemAttributes >( attr_input )?; + let original_input = item_input.clone(); + let mut item_parsed = match syn::parse::< syn::ItemTrait >( item_input ) { Ok( original ) => original, Err( err ) => return Err( err ), }; - let name_ident = &item_parsed.ident; + let has_debug = attrs.debug.value( false ); + let item_name = &item_parsed.ident; + + let ( _generics_with_defaults, generics_impl, generics_ty, generics_where ) + = generic_params::decompose( &item_parsed.generics ); - let generic_params = &item_parsed.generics.params; - let generics_where = &item_parsed.generics.where_clause; - let generics_names : Vec< _ > = generic_params::names( &item_parsed.generics ).collect(); + let extra : macro_tools::GenericsWithWhere = parse_quote! + { + where + Self : clone_dyn::CloneDyn, + }; + item_parsed.generics = generic_params::merge( &item_parsed.generics, &extra.into() ); let result = qt! { #item_parsed #[ allow( non_local_definitions ) ] - impl < 'c, #generic_params > Clone - for Box< dyn #name_ident< #( #generics_names ),* > + 'c > - // where + impl < 'c, #generics_impl > Clone + for Box< dyn #item_name< #generics_ty > + 'c > + where #generics_where { #[ inline ] - fn clone( &self ) -> Self { clone_dyn::_clone_boxed( &**self ) } + fn clone( &self ) -> Self { clone_dyn::clone_into_box( &**self ) } } #[ allow( non_local_definitions ) ] - impl < 'c, #generic_params > Clone - for Box< dyn #name_ident< #( #generics_names ),* > + Send + 'c > - // where + impl < 'c, #generics_impl > Clone + for Box< dyn #item_name< #generics_ty > + Send + 'c > + where #generics_where { #[ inline ] - fn clone( &self ) -> Self { clone_dyn::_clone_boxed( &**self ) } + fn clone( &self ) -> Self { clone_dyn::clone_into_box( &**self ) } } #[ allow( non_local_definitions ) ] - impl < 'c, #generic_params > Clone - for Box< dyn #name_ident< #( #generics_names ),* > + Sync + 'c > - // where + impl < 'c, #generics_impl > Clone + for Box< dyn #item_name< #generics_ty > + Sync + 'c > + where #generics_where { #[ inline ] - fn clone( &self ) -> Self { clone_dyn::_clone_boxed( &**self ) } + fn clone( &self ) -> Self { clone_dyn::clone_into_box( &**self ) } } #[ allow( non_local_definitions ) ] - impl < 'c, #generic_params > Clone - for Box< dyn #name_ident< #( #generics_names ),* > + Send + Sync + 'c > - // where + impl < 'c, #generics_impl > Clone + for Box< dyn #item_name< #generics_ty > + Send + Sync + 'c > + where #generics_where { #[ inline ] - fn clone( &self ) -> Self { clone_dyn::_clone_boxed( &**self ) } + fn clone( &self ) -> Self { clone_dyn::clone_into_box( &**self ) } } }; + if has_debug + { + let about = format!( "macro : CloneDny\ntrait : {item_name}" ); + diag::report_print( about, &original_input, &result ); + } + Ok( result ) } + +// == attributes + +/// Represents the attributes of a struct. Aggregates all its attributes. +#[ derive( Debug, Default ) ] +pub struct ItemAttributes +{ + /// Attribute for customizing generated code. + pub debug : AttributePropertyDebug, +} + +impl syn::parse::Parse for ItemAttributes +{ + fn parse( input : syn::parse::ParseStream< '_ > ) -> syn::Result< Self > + { + let mut result = Self::default(); + + let error = | ident : &syn::Ident | -> syn::Error + { + let known = const_format::concatcp! + ( + "Known properties of attribute `clone_dyn` are : ", + AttributePropertyDebug::KEYWORD, + ".", + ); + syn_err! + ( + ident, + r#"Expects an attribute of format '#[ clone_dyn( {} ) ]' + {known} + But got: '{}' +"#, + AttributePropertyDebug::KEYWORD, + qt!{ #ident } + ) + }; + + while !input.is_empty() + { + let lookahead = input.lookahead1(); + if lookahead.peek( syn::Ident ) + { + let ident : syn::Ident = input.parse()?; + match ident.to_string().as_str() + { + AttributePropertyDebug::KEYWORD => result.assign( AttributePropertyDebug::from( true ) ), + _ => return Err( error( &ident ) ), + } + } + else + { + return Err( lookahead.error() ); + } + + // Optional comma handling + if input.peek( syn::Token![ , ] ) + { + input.parse::< syn::Token![ , ] >()?; + } + } + + Ok( result ) + } +} + +impl< IntoT > Assign< AttributePropertyDebug, IntoT > for ItemAttributes +where + IntoT : Into< AttributePropertyDebug >, +{ + #[ inline( always ) ] + fn assign( &mut self, prop : IntoT ) + { + self.debug = prop.into(); + } +} + +// == attribute properties + +/// Marker type for attribute property to specify whether to provide a generated code as a hint. +#[ derive( Debug, Default, Clone, Copy ) ] +pub struct AttributePropertyDebugMarker; + +impl AttributePropertyComponent for AttributePropertyDebugMarker +{ + const KEYWORD : &'static str = "debug"; +} + +/// Specifies whether to provide a generated code as a hint. +/// Defaults to `false`, which means no debug is provided unless explicitly requested. +pub type AttributePropertyDebug = AttributePropertyOptionalSingletone< AttributePropertyDebugMarker >; diff --git a/module/core/clone_dyn_types/Cargo.toml b/module/core/clone_dyn_types/Cargo.toml new file mode 100644 index 0000000000..55535ac954 --- /dev/null +++ b/module/core/clone_dyn_types/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "clone_dyn_types" +version = "0.20.0" +edition = "2021" +authors = [ + "Kostiantyn Wandalen ", +] +license = "MIT" +readme = "Readme.md" +documentation = "https://docs.rs/clone_dyn_types" +repository = "https://github.com/Wandalen/wTools/tree/master/module/core/clone_dyn_types" +homepage = "https://github.com/Wandalen/wTools/tree/master/module/core/clone_dyn_types" +description = """ +Derive to clone dyn structures. +""" +categories = [ "algorithms", "development-tools" ] +keywords = [ "fundamental", "general-purpose" ] + +[lints] +workspace = true + +[package.metadata.docs.rs] +features = [ "full" ] +all-features = false + +[features] + +default = [ "enabled" ] +full = [ "enabled" ] +enabled = [] + +[dependencies] + +[dev-dependencies] +test_tools = { workspace = true } +# inspect_type = { workspace = true, features = [ "full" ] } diff --git a/module/core/clone_dyn_types/License b/module/core/clone_dyn_types/License new file mode 100644 index 0000000000..6d5ef8559f --- /dev/null +++ b/module/core/clone_dyn_types/License @@ -0,0 +1,22 @@ +Copyright Kostiantyn W and Out of the Box Systems (c) 2013-2024 + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/module/core/clone_dyn_types/Readme.md b/module/core/clone_dyn_types/Readme.md new file mode 100644 index 0000000000..8485e1c9db --- /dev/null +++ b/module/core/clone_dyn_types/Readme.md @@ -0,0 +1,238 @@ + +# Module :: clone_dyn_types + + [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) [![rust-status](https://github.com/Wandalen/wTools/actions/workflows/module_clone_dyn_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_clone_dyn_push.yml) [![docs.rs](https://img.shields.io/docsrs/clone_dyn_types?color=e3e8f0&logo=docs.rs)](https://docs.rs/clone_dyn_types) [![Open in Gitpod](https://raster.shields.io/static/v1?label=try&message=online&color=eee&logo=gitpod&logoColor=eee)](https://gitpod.io/#RUN_PATH=.,SAMPLE_FILE=module%2Fcore%2Fclone_dyn%2Fexamples%2Fclone_dyn_trivial.rs,RUN_POSTFIX=--example%20clone_dyn_trivial/https://github.com/Wandalen/wTools) [![discord](https://img.shields.io/discord/872391416519737405?color=eee&logo=discord&logoColor=eee&label=ask)](https://discord.gg/m3YfbXpUUY) + + +Derive to clone dyn structures. + +It's types, use `clone_dyn` to avoid bolerplate. + +By default, Rust does not support cloning for trait objects due to the `Clone` trait requiring compile-time knowledge of the type's size. The `clone_dyn` crate addresses this limitation through procedural macros, allowing for cloning collections of trait objects. Prefer to use `clone_dyn` instead of this crate, because `clone_dyn` includes this crate and also provides an attribute macro to generate boilerplate with one line of code. + +## Alternative + +There are few alternatives [dyn-clone](https://github.com/dtolnay/dyn-clone), [dyn-clonable](https://github.com/kardeiz/objekt-clonable). Unlike other options, this solution is more concise and demands less effort to use, all without compromising the quality of the outcome. + +## Basic use-case + +Demonstrates the usage of `clone_dyn` to enable cloning for trait objects. + +By default, Rust does not support cloning for trait objects due to the `Clone` trait +requiring compile-time knowledge of the type's size. The `clone_dyn` crate addresses +this limitation through procedural macros, allowing for cloning collections of trait objects +and crate `clone_dyn_types` contains implementation of all types. + +##### Overview + +This example shows how to use the `clone_dyn` crate to enable cloning for trait objects, +specifically for iterators. It defines a custom trait, `IterTrait`, that encapsulates +an iterator with specific characteristics and demonstrates how to use `CloneDyn` to +overcome the object safety constraints of the `Clone` trait. + +##### The `IterTrait` Trait + +The `IterTrait` trait is designed to represent iterators that yield references to items (`&'a T`). +These iterators must also implement the `ExactSizeIterator` and `DoubleEndedIterator` traits. +Additionally, the iterator must implement the `CloneDyn` trait, which allows cloning of trait objects. + +The trait is implemented for any type that meets the specified requirements. + +##### Cloning Trait Objects + +Rust's type system does not allow trait objects to implement the `Clone` trait directly due to object safety constraints. +Specifically, the `Clone` trait requires knowledge of the concrete type at compile time, which is not available for trait objects. + +The `CloneDyn` trait from the `clone_dyn_types` crate provides a workaround for this limitation by allowing trait objects to be cloned. + +The example demonstrates how to implement `Clone` for boxed `IterTrait` trait objects. + +##### `get_iter` Function + +The `get_iter` function returns a boxed iterator that implements the `IterTrait` trait. +If the input is `Some`, it returns an iterator over the vector. +If the input is `None`, it returns an empty iterator. + +It's not possible to use `impl Iterator` here because the code returns iterators of two different types: +- `std::slice::Iter` when the input is `Some`. +- `std::iter::Empty` when the input is `None`. + +To handle this, the function returns a trait object ( `Box< dyn IterTrait >` ). +However, Rust's `Clone` trait cannot be implemented for trait objects due to object safety constraints. +The `CloneDyn` trait addresses this problem by enabling cloning of trait objects. + +##### `use_iter` Function + +The `use_iter` function demonstrates the use of the `CloneDyn` trait by cloning the iterator. +It then iterates over the cloned iterator and prints each element. + +##### Main Function + +The main function demonstrates the overall usage by creating a vector, obtaining an iterator, and using the iterator to print elements. + +```rust + +#[ cfg( not( feature = "enabled" ) ) ] +fn main() {} +#[ cfg( feature = "enabled" ) ] +fn main() +{ + use clone_dyn_types::CloneDyn; + + /// Trait that encapsulates an iterator with specific characteristics, tailored for your needs. + pub trait IterTrait< 'a, T > + where + T : 'a, + Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, + Self : CloneDyn, + { + } + + impl< 'a, T, I > IterTrait< 'a, T > for I + where + T : 'a, + Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, + Self : CloneDyn, + { + } + + // Implement `Clone` for boxed `IterTrait` trait objects. + impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + 'c > + { + #[ inline ] + fn clone( &self ) -> Self + { + clone_dyn_types::clone_into_box( &**self ) + } + } + + /// + /// Function to get an iterator over a vector of integers. + /// + /// This function returns a boxed iterator that implements the `IterTrait` trait. + /// If the input is `Some`, it returns an iterator over the vector. + /// If the input is `None`, it returns an empty iterator. + /// + /// Rust's type system does not allow trait objects to implement the `Clone` trait directly due to object safety constraints. + /// Specifically, the `Clone` trait requires knowledge of the concrete type at compile time, which is not available for trait objects. + /// + /// In this example, we need to return an iterator that can be cloned. Since we are returning a trait object ( `Box< dyn IterTrait >` ), + /// we cannot directly implement `Clone` for this trait object. This is where the `CloneDyn` trait from the `clone_dyn_types` crate comes in handy. + /// + /// The `CloneDyn` trait provides a workaround for this limitation by allowing trait objects to be cloned. + /// It uses procedural macros to generate the necessary code for cloning trait objects, making it possible to clone collections of trait objects. + /// + /// It's not possible to use `impl Iterator` here because the code returns iterators of two different types: + /// - `std::slice::Iter` when the input is `Some`. + /// - `std::iter::Empty` when the input is `None`. + /// + /// To handle this, the function returns a trait object (`Box`). + /// However, Rust's `Clone` trait cannot be implemented for trait objects due to object safety constraints. + /// The `CloneDyn` trait addresses this problem by enabling cloning of trait objects. + /// + + pub fn get_iter< 'a >( src : Option< &'a Vec< i32 > > ) -> Box< dyn IterTrait< 'a, &'a i32 > + 'a > + { + match &src + { + Some( src ) => Box::new( src.iter() ), + _ => Box::new( core::iter::empty() ), + } + } + + /// Function to use an iterator and print its elements. + /// + /// This function demonstrates the use of the `CloneDyn` trait by cloning the iterator. + /// It then iterates over the cloned iterator and prints each element. + pub fn use_iter< 'a >( iter : Box< dyn IterTrait< 'a, &'a i32 > + 'a > ) + { + // Clone would not be available if CloneDyn is not implemented for the iterator. + // And being an object-safe trait, it can't implement Clone. + // Nevertheless, thanks to CloneDyn, the object is clonable. + // + // This line demonstrates cloning the iterator and iterating over the cloned iterator. + iter.clone().for_each( | e | println!( "{e}" ) ); + + // Iterate over the original iterator and print each element. + iter.for_each( | e | println!( "{e}" ) ); + } + + // Create a vector of integers. + let data = vec![ 1, 2, 3 ]; + // Get an iterator over the vector. + let iter = get_iter( Some( &data ) ); + // Use the iterator to print its elements. + use_iter( iter ); + +} +``` + +
+If you use multithreading or asynchronous paradigms implement trait `Clone` also for `Send` and `Sync` + +```rust, ignore + +#[ allow( non_local_definitions ) ] +impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self + { + clone_dyn_types::clone_into_box( &**self ) + } +} + +#[ allow( non_local_definitions ) ] +impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + Send + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self + { + clone_dyn_types::clone_into_box( &**self ) + } +} + +#[ allow( non_local_definitions ) ] +impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + Sync + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self + { + clone_dyn_types::clone_into_box( &**self ) + } +} + +#[ allow( non_local_definitions ) ] +impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + Send + Sync + 'c > +{ + #[ inline ] + fn clone( &self ) -> Self + { + clone_dyn_types::clone_into_box( &**self ) + } +} + +``` + +
+ +
+ +Try out `cargo run --example clone_dyn_types_trivial`. +
+[See code](./examples/clone_dyn_types_trivial.rs). + +## To add to your project + +```sh +cargo add clone_dyn_types +``` + +## Try out from the repository + +```sh +git clone https://github.com/Wandalen/wTools +cd wTools +cd examples/clone_dyn_types_trivial +cargo run +``` diff --git a/module/core/clone_dyn_types/examples/clone_dyn_types_trivial.rs b/module/core/clone_dyn_types/examples/clone_dyn_types_trivial.rs new file mode 100644 index 0000000000..dce84eb919 --- /dev/null +++ b/module/core/clone_dyn_types/examples/clone_dyn_types_trivial.rs @@ -0,0 +1,150 @@ +//! +//! ## Basic use-case +//! +//! Demonstrates the usage of `clone_dyn` to enable cloning for trait objects. +//! +//! By default, Rust does not support cloning for trait objects due to the `Clone` trait +//! requiring compile-time knowledge of the type's size. The `clone_dyn` crate addresses +//! this limitation through procedural macros, allowing for cloning collections of trait objects +//! and crate `clone_dyn_types` contains implementation of all types. +//! +//! ##### Overview +//! +//! This example shows how to use the `clone_dyn` crate to enable cloning for trait objects, +//! specifically for iterators. It defines a custom trait, `IterTrait`, that encapsulates +//! an iterator with specific characteristics and demonstrates how to use `CloneDyn` to +//! overcome the object safety constraints of the `Clone` trait. +//! +//! ##### The `IterTrait` Trait +//! +//! The `IterTrait` trait is designed to represent iterators that yield references to items (`&'a T`). +//! These iterators must also implement the `ExactSizeIterator` and `DoubleEndedIterator` traits. +//! Additionally, the iterator must implement the `CloneDyn` trait, which allows cloning of trait objects. +//! +//! The trait is implemented for any type that meets the specified requirements. +//! +//! ##### Cloning Trait Objects +//! +//! Rust's type system does not allow trait objects to implement the `Clone` trait directly due to object safety constraints. +//! Specifically, the `Clone` trait requires knowledge of the concrete type at compile time, which is not available for trait objects. +//! +//! The `CloneDyn` trait from the `clone_dyn_types` crate provides a workaround for this limitation by allowing trait objects to be cloned. +//! +//! The example demonstrates how to implement `Clone` for boxed `IterTrait` trait objects. +//! +//! ##### `get_iter` Function +//! +//! The `get_iter` function returns a boxed iterator that implements the `IterTrait` trait. +//! If the input is `Some`, it returns an iterator over the vector. +//! If the input is `None`, it returns an empty iterator. +//! +//! It's not possible to use `impl Iterator` here because the code returns iterators of two different types: +//! - `std::slice::Iter` when the input is `Some`. +//! - `std::iter::Empty` when the input is `None`. +//! +//! To handle this, the function returns a trait object ( `Box< dyn IterTrait >` ). +//! However, Rust's `Clone` trait cannot be implemented for trait objects due to object safety constraints. +//! The `CloneDyn` trait addresses this problem by enabling cloning of trait objects. +//! +//! ##### `use_iter` Function +//! +//! The `use_iter` function demonstrates the use of the `CloneDyn` trait by cloning the iterator. +//! It then iterates over the cloned iterator and prints each element. +//! +//! ##### Main Function +//! +//! The main function demonstrates the overall usage by creating a vector, obtaining an iterator, and using the iterator to print elements. +//! + +#[ cfg( not( feature = "enabled" ) ) ] +fn main() {} +#[ cfg( feature = "enabled" ) ] +fn main() +{ + use clone_dyn_types::CloneDyn; + + /// Trait that encapsulates an iterator with specific characteristics, tailored for your needs. + pub trait IterTrait< 'a, T > + where + T : 'a, + Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, + Self : CloneDyn, + { + } + + impl< 'a, T, I > IterTrait< 'a, T > for I + where + T : 'a, + Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, + Self : CloneDyn, + { + } + + // Implement `Clone` for boxed `IterTrait` trait objects. + #[ allow( non_local_definitions ) ] + impl< 'c, T > Clone for Box< dyn IterTrait< 'c, T > + 'c > + { + #[ inline ] + fn clone( &self ) -> Self + { + clone_dyn_types::clone_into_box( &**self ) + } + } + + /// + /// Function to get an iterator over a vector of integers. + /// + /// This function returns a boxed iterator that implements the `IterTrait` trait. + /// If the input is `Some`, it returns an iterator over the vector. + /// If the input is `None`, it returns an empty iterator. + /// + /// Rust's type system does not allow trait objects to implement the `Clone` trait directly due to object safety constraints. + /// Specifically, the `Clone` trait requires knowledge of the concrete type at compile time, which is not available for trait objects. + /// + /// In this example, we need to return an iterator that can be cloned. Since we are returning a trait object ( `Box< dyn IterTrait >` ), + /// we cannot directly implement `Clone` for this trait object. This is where the `CloneDyn` trait from the `clone_dyn_types` crate comes in handy. + /// + /// The `CloneDyn` trait provides a workaround for this limitation by allowing trait objects to be cloned. + /// + /// It's not possible to use `impl Iterator` here because the code returns iterators of two different types: + /// - `std::slice::Iter` when the input is `Some`. + /// - `std::iter::Empty` when the input is `None`. + /// + /// To handle this, the function returns a trait object (`Box`). + /// However, Rust's `Clone` trait cannot be implemented for trait objects due to object safety constraints. + /// The `CloneDyn` trait addresses this problem by enabling cloning of trait objects. + + pub fn get_iter< 'a >( src : Option< &'a Vec< i32 > > ) -> Box< dyn IterTrait< 'a, &'a i32 > + 'a > + { + match &src + { + Some( src ) => Box::new( src.iter() ), + _ => Box::new( core::iter::empty() ), + } + } + + /// Function to use an iterator and print its elements. + /// + /// This function demonstrates the use of the `CloneDyn` trait by cloning the iterator. + /// It then iterates over the cloned iterator and prints each element. + pub fn use_iter< 'a >( iter : Box< dyn IterTrait< 'a, &'a i32 > + 'a > ) + { + // Clone would not be available if CloneDyn is not implemented for the iterator. + // And being an object-safe trait, it can't implement Clone. + // Nevertheless, thanks to CloneDyn, the object is clonable. + // + // This line demonstrates cloning the iterator and iterating over the cloned iterator. + iter.clone().for_each( | e | println!( "{e}" ) ); + + // Iterate over the original iterator and print each element. + iter.for_each( | e | println!( "{e}" ) ); + } + + // Create a vector of integers. + let data = vec![ 1, 2, 3 ]; + // Get an iterator over the vector. + let iter = get_iter( Some( &data ) ); + // Use the iterator to print its elements. + use_iter( iter ); + +} diff --git a/module/core/clone_dyn_types/src/lib.rs b/module/core/clone_dyn_types/src/lib.rs new file mode 100644 index 0000000000..3ace741087 --- /dev/null +++ b/module/core/clone_dyn_types/src/lib.rs @@ -0,0 +1,258 @@ +#![ no_std ] +#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ] +#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ] +#![ doc( html_root_url = "https://docs.rs/clone_dyn_types/latest/clone_dyn_types/" ) ] +#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] + +/// Namespace with dependencies. +#[ cfg( feature = "enabled" ) ] +pub mod dependency +{ +} + +/// Internal namespace. +#[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] +#[ cfg( feature = "enabled" ) ] +pub( crate ) mod private +{ + + // #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] + extern crate alloc; + // #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] + // #[ allow( unused_imports ) ] + use alloc::boxed::Box; + // #[ cfg( all( feature = "use_std", not( feature = "use_alloc" ) ) ) ] + // use std::boxed::Box; + + /// A trait to upcast a clonable entity and clone it. + /// It's implemented for all entities which can be cloned. + pub trait CloneDyn : Sealed + { + #[ doc( hidden ) ] + fn __clone_dyn( &self, _ : DontCallMe ) -> *mut (); + } + + // clonable + impl< T > CloneDyn for T + where + T : Clone, + { + #[ inline ] + fn __clone_dyn( &self, _ : DontCallMe ) -> *mut () + { + Box::< T >::into_raw( Box::new( self.clone() ) ) as *mut () + } + } + + // slice + impl< T > CloneDyn for [ T ] + where + T : Clone, + { + #[ inline ] + fn __clone_dyn( &self, _ : DontCallMe ) -> *mut () + { + Box::< [ T ] >::into_raw( self.iter().cloned().collect() ) as *mut () + } + } + + // str slice + impl CloneDyn for str + { + #[ inline ] + fn __clone_dyn( &self, _ : DontCallMe ) -> *mut () + { + Box::< str >::into_raw( Box::from( self ) ) as *mut () + } + } + + /// + /// True clone which is applicable not only to clonable entities, but to trait objects implementing CloneDyn. + /// + /// # Example + /// + /// ``` + /// use clone_dyn_types::clone; + /// + /// #[ derive( Clone ) ] + /// struct MyStruct + /// { + /// value : i32, + /// } + /// + /// let original = MyStruct { value : 42 }; + /// let cloned = clone( &original ); + /// + /// assert_eq!( original.value, cloned.value ); + /// ``` + + #[ inline ] + pub fn clone< T >( src : &T ) -> T + where + T : CloneDyn, + { + // # Safety + // + // This function uses an `unsafe` block because it performs low-level memory manipulations. Specifically, it handles + // raw pointers and converts them to and from `Box< T >`. This is necessary to dynamically clone a trait object, which + // does not support cloning through the standard `Clone` trait. The safety of this function depends on the guarantee + // that the `CloneDyn` trait is correctly implemented for the given type `T`, ensuring that `__clone_dyn` returns a + // valid pointer to a cloned instance of `T`. + // + #[ allow( unsafe_code ) ] + unsafe + { + *Box::from_raw( < T as CloneDyn >::__clone_dyn( src, DontCallMe ) as *mut T ) + } + } + + /// + /// Clone boxed dyn. + /// + /// Clones a dynamically sized trait object into a `Box< T >`. + /// + /// # Example + /// + /// ``` + /// use clone_dyn_types::{ CloneDyn, clone_into_box }; + /// + /// #[ derive( Clone ) ] + /// struct MyStruct + /// { + /// value : i32, + /// } + /// + /// trait MyTrait : CloneDyn + /// { + /// fn val( &self ) -> i32; + /// } + /// + /// impl MyTrait for MyStruct + /// { + /// fn val( &self ) -> i32 + /// { + /// self.value + /// } + /// } + /// + /// #[ allow( non_local_definitions ) ] + /// impl < 'c > Clone + /// for Box< dyn MyTrait + 'c > + /// { + /// #[ inline ] + /// fn clone( &self ) -> Self { clone_into_box( &**self ) } + /// } + /// + /// #[ allow( non_local_definitions ) ] + /// impl < 'c > Clone + /// for Box< dyn MyTrait + Send + 'c > + /// { + /// #[ inline ] + /// fn clone( &self ) -> Self { clone_into_box( &**self ) } + /// } + /// + /// #[ allow( non_local_definitions ) ] + /// impl < 'c > Clone + /// for Box< dyn MyTrait + Sync + 'c > + /// { + /// #[ inline ] + /// fn clone( &self ) -> Self { clone_into_box( &**self ) } + /// } + /// + /// #[ allow( non_local_definitions ) ] + /// impl < 'c > Clone + /// for Box< dyn MyTrait + Send + Sync + 'c > + /// { + /// #[ inline ] + /// fn clone( &self ) -> Self { clone_into_box( &**self ) } + /// } + /// + /// let cloned : Box< dyn MyTrait > = clone_into_box( &MyStruct { value : 42 } ); + /// + /// ``` + + #[ inline ] + pub fn clone_into_box< T >( ref_dyn : &T ) -> Box< T > + where + T : ?Sized + CloneDyn, + { + // # Safety + // + // This function uses an `unsafe` block because it performs low-level memory manipulations involving raw pointers. + // The `unsafe` block is necessary here because we're manually handling raw pointers and converting them to and from + // `Box`. This bypasses Rust's ownership and borrowing rules to achieve dynamic cloning of a boxed trait object. + // The safety of this function relies on the correct implementation of the `CloneDyn` trait for the given type `T`. + // Specifically, `__clone_dyn` must return a valid pointer to a cloned instance of `T`. + // + #[ allow( unsafe_code ) ] + unsafe + { + let mut ptr = ref_dyn as *const T; + let data_ptr = &mut ptr as *mut *const T as *mut *mut (); + *data_ptr = < T as CloneDyn >::__clone_dyn( ref_dyn, DontCallMe ); + Box::from_raw( ptr as *mut T ) + } + } + + #[ doc( hidden ) ] + mod sealed + { + #[ doc( hidden ) ] + #[ allow( missing_debug_implementations ) ] + pub struct DontCallMe; + #[ doc( hidden ) ] + pub trait Sealed {} + impl< T : Clone > Sealed for T {} + impl< T : Clone > Sealed for [ T ] {} + impl Sealed for str {} + } + use sealed::*; + +} + +#[ cfg( feature = "enabled" ) ] +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +pub use protected::*; + +/// Protected namespace of the module. +#[ cfg( feature = "enabled" ) ] +pub mod protected +{ + #[ doc( inline ) ] + #[ allow( unused_imports ) ] + pub use super::orphan::*; +} + +/// Orphan namespace of the module. +#[ cfg( feature = "enabled" ) ] +pub mod orphan +{ + #[ doc( inline ) ] + #[ allow( unused_imports ) ] + pub use super::exposed::*; +} + +/// Exposed namespace of the module. +#[ cfg( feature = "enabled" ) ] +pub mod exposed +{ + #[ doc( inline ) ] + #[ allow( unused_imports ) ] + pub use super::prelude::*; +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ cfg( feature = "enabled" ) ] +pub mod prelude +{ + #[ doc( inline ) ] + #[ allow( unused_imports ) ] + #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] + pub use super::private:: + { + CloneDyn, + clone_into_box, + clone, + }; +} diff --git a/module/core/clone_dyn_types/tests/inc/mod.rs b/module/core/clone_dyn_types/tests/inc/mod.rs new file mode 100644 index 0000000000..c5bda8ed18 --- /dev/null +++ b/module/core/clone_dyn_types/tests/inc/mod.rs @@ -0,0 +1,15 @@ + +#[ allow( unused_imports ) ] +use super::*; + +#[ path = "../../../clone_dyn/tests/inc" ] +mod tests +{ + #[ allow( unused_imports ) ] + use super::*; + + mod basic_manual; + // mod basic; + // mod parametrized; + +} diff --git a/module/core/clone_dyn_types/tests/smoke_test.rs b/module/core/clone_dyn_types/tests/smoke_test.rs new file mode 100644 index 0000000000..828e9b016b --- /dev/null +++ b/module/core/clone_dyn_types/tests/smoke_test.rs @@ -0,0 +1,14 @@ + + +#[ test ] +fn local_smoke_test() +{ + ::test_tools::smoke_test_for_local_run(); +} + + +#[ test ] +fn published_smoke_test() +{ + ::test_tools::smoke_test_for_published_run(); +} diff --git a/module/core/clone_dyn_types/tests/tests.rs b/module/core/clone_dyn_types/tests/tests.rs new file mode 100644 index 0000000000..e2210e22b4 --- /dev/null +++ b/module/core/clone_dyn_types/tests/tests.rs @@ -0,0 +1,8 @@ + +#[ allow( unused_imports ) ] +use clone_dyn_types as the_module; +#[ allow( unused_imports ) ] +use test_tools::exposed::*; + +#[ cfg( all( feature = "enabled", any( not( feature = "no_std" ), feature = "use_alloc" ) ) ) ] +mod inc; diff --git a/module/core/collection_tools/Cargo.toml b/module/core/collection_tools/Cargo.toml index 65a81d7cde..bb7609b9c9 100644 --- a/module/core/collection_tools/Cargo.toml +++ b/module/core/collection_tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "collection_tools" -version = "0.8.0" +version = "0.9.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/derive_tools/Cargo.toml b/module/core/derive_tools/Cargo.toml index 3f2b08fe4b..2dc4b4afb6 100644 --- a/module/core/derive_tools/Cargo.toml +++ b/module/core/derive_tools/Cargo.toml @@ -17,14 +17,17 @@ A collection of derive macros designed to enhance STD. categories = [ "algorithms", "development-tools" ] keywords = [ "fundamental", "general-purpose" ] + [lints] workspace = true + [package.metadata.docs.rs] features = [ "full" ] all-features = false # exclude = [ "/tests", "/examples", "-*" ] + [features] default = [ @@ -117,7 +120,7 @@ full = [ # "use_std", ] no_std = [] -use_alloc = [ "no_std", "clone_dyn/use_alloc" ] +use_alloc = [ "no_std" ] enabled = [ "derive_tools_meta/enabled" ] # nightly = [ "derive_more/nightly" ] @@ -176,6 +179,7 @@ derive_new = [ "derive_tools_meta/derive_new" ] parse_display = [ "parse-display" ] + [dependencies] ## external @@ -190,6 +194,7 @@ derive_tools_meta = { workspace = true, features = [] } variadic_from = { workspace = true, features = [] } clone_dyn = { workspace = true, features = [] } + [dev-dependencies] test_tools = { workspace = true } diff --git a/module/core/derive_tools/src/lib.rs b/module/core/derive_tools/src/lib.rs index d99c9c9455..5bf65c972a 100644 --- a/module/core/derive_tools/src/lib.rs +++ b/module/core/derive_tools/src/lib.rs @@ -84,9 +84,23 @@ pub use variadic_from as variadic; /// Namespace with dependencies. +#[ allow( unused_imports ) ] #[ cfg( feature = "enabled" ) ] pub mod dependency { + + #[ doc( inline ) ] + #[ cfg( any_derive ) ] + pub use ::derive_tools_meta; + + #[ doc( inline ) ] + #[ cfg( feature = "clone_dyn" ) ] + pub use ::clone_dyn::{ self, dependency::* }; + + #[ doc( inline ) ] + #[ cfg( any( feature = "derive_variadic_from", feature = "type_variadic_from" ) ) ] + pub use ::variadic_from::{ self, dependency::* }; + #[ doc( inline ) ] #[ cfg( feature = "derive_more" ) ] pub use ::derive_more; @@ -96,18 +110,7 @@ pub mod dependency #[ doc( inline ) ] #[ cfg( feature = "parse_display" ) ] pub use ::parse_display; - #[ doc( inline ) ] - #[ cfg( feature = "clone_dyn" ) ] - pub use ::clone_dyn; - #[ doc( inline ) ] - #[ cfg( feature = "clone_dyn" ) ] - pub use ::clone_dyn::dependency::*; - #[ doc( inline ) ] - #[ cfg( any_derive ) ] - pub use ::derive_tools_meta; - #[ doc( inline ) ] - #[ cfg( any( feature = "derive_variadic_from", feature = "type_variadic_from" ) ) ] - pub use ::variadic_from; + } #[ doc( inline ) ] diff --git a/module/core/derive_tools/tests/inc/mod.rs b/module/core/derive_tools/tests/inc/mod.rs index a79deeb407..8dc439c8d8 100644 --- a/module/core/derive_tools/tests/inc/mod.rs +++ b/module/core/derive_tools/tests/inc/mod.rs @@ -178,6 +178,7 @@ mod new_tests mod multiple_named_test; mod multiple_unnamed_manual_test; // mod multiple_unnamed_test; + // xxx : continue // diff --git a/module/core/derive_tools_meta/Cargo.toml b/module/core/derive_tools_meta/Cargo.toml index eade555900..28db43d34a 100644 --- a/module/core/derive_tools_meta/Cargo.toml +++ b/module/core/derive_tools_meta/Cargo.toml @@ -64,7 +64,7 @@ derive_inner_from = [] derive_variadic_from = [] [dependencies] -# xxx : qqq : optimize features set +# zzz : qqq : optimize features set macro_tools = { workspace = true, features = [ "full" ] } iter_tools = { workspace = true, features = [ "full" ] } former_types = { workspace = true, features = [ "types_component_assign" ] } diff --git a/module/core/derive_tools_meta/src/derive/from.rs b/module/core/derive_tools_meta/src/derive/from.rs index 2e375e5d86..d9168768a9 100644 --- a/module/core/derive_tools_meta/src/derive/from.rs +++ b/module/core/derive_tools_meta/src/derive/from.rs @@ -363,7 +363,8 @@ fn generate_multiple_fields_named< 'a > }); // xxx : qqq : rid off collects - let field_types : Vec< _ > = field_types.collect(); + // let field_types : Vec< _ > = field_types.collect(); + let field_types2 = field_types.clone(); qt! { impl< #generics_impl > From< (# ( #field_types ),* ) > for #item_name< #generics_ty > @@ -372,9 +373,9 @@ fn generate_multiple_fields_named< 'a > { #[ inline( always ) ] // fn from( src : (i32, bool) ) -> Self - fn from( src : ( #( #field_types ),* ) ) -> Self + fn from( src : ( #( #field_types2 ),* ) ) -> Self { - #item_name { #(#params),* } + #item_name { #( #params ),* } } } } diff --git a/module/core/derive_tools_meta/src/derive/new.rs b/module/core/derive_tools_meta/src/derive/new.rs index af9a1f8645..2f0341c159 100644 --- a/module/core/derive_tools_meta/src/derive/new.rs +++ b/module/core/derive_tools_meta/src/derive/new.rs @@ -18,7 +18,7 @@ use item_attributes::*; // -// xxx : qqq : implement +// zzz : qqq : implement pub fn new( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStream > { // use macro_tools::quote::ToTokens; @@ -126,7 +126,7 @@ pub fn new( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStrea Ok( result ) } -// xxx : qqq : implement +// zzz : qqq : implement // qqq : document, add example of generated code fn generate_unit ( @@ -153,7 +153,7 @@ fn generate_unit } } -// xxx : qqq : implement +// zzz : qqq : implement // qqq : document, add example of generated code fn generate_single_field_named ( @@ -185,7 +185,7 @@ fn generate_single_field_named } } -// xxx : qqq : implement +// zzz : qqq : implement // qqq : document, add example of generated code fn generate_single_field ( @@ -217,7 +217,7 @@ fn generate_single_field } } -// xxx : qqq : implement +// zzz : qqq : implement // qqq : document, add example of generated code fn generate_multiple_fields_named< 'a > ( @@ -231,14 +231,12 @@ fn generate_multiple_fields_named< 'a > -> proc_macro2::TokenStream { - let field_names : Vec< _ > = field_names.collect(); // xxx : qqq : rid off collects - - let val_type = field_names.iter() + let val_type = field_names + .clone() .zip( field_types ) .enumerate() - .map(| ( index, ( field_name, field_type ) ) | + .map(| ( _index, ( field_name, field_type ) ) | { - // let index = index.to_string().parse::< proc_macro2::TokenStream >().unwrap(); qt! { #field_name : #field_type } }); @@ -261,7 +259,7 @@ fn generate_multiple_fields_named< 'a > } -// xxx : qqq : implement +// zzz : qqq : implement // qqq : document, add example of generated code fn generate_multiple_fields< 'a > ( @@ -299,7 +297,7 @@ fn generate_multiple_fields< 'a > } } -// xxx : qqq : implement +// zzz : qqq : implement // qqq : document, add example of generated code fn variant_generate ( diff --git a/module/core/derive_tools_meta/src/lib.rs b/module/core/derive_tools_meta/src/lib.rs index f9b255f8ff..0868a82f77 100644 --- a/module/core/derive_tools_meta/src/lib.rs +++ b/module/core/derive_tools_meta/src/lib.rs @@ -77,7 +77,7 @@ mod derive; From, attributes ( - debug, // struct + debug, // item from, // field ) )] @@ -132,7 +132,7 @@ pub fn from( input : proc_macro::TokenStream ) -> proc_macro::TokenStream New, attributes ( - debug, // struct + debug, // item new, // field ) )] @@ -497,7 +497,7 @@ pub fn as_mut( input : proc_macro::TokenStream ) -> proc_macro::TokenStream /// #[ derive( Debug, PartialEq, Default, VariadicFrom ) ] /// // Use `#[ debug ]` to expand and debug generate code. /// // #[ debug ] -/// struct MyStruct +/// item MyStruct /// { /// a : i32, /// b : i32, diff --git a/module/core/format_tools/tests/inc/fields_test.rs b/module/core/format_tools/tests/inc/fields_test.rs index 9f6b62261e..f0da3129c3 100644 --- a/module/core/format_tools/tests/inc/fields_test.rs +++ b/module/core/format_tools/tests/inc/fields_test.rs @@ -40,16 +40,16 @@ where { let mut dst : Vec< ( &'static str, MaybeAs< 'a, String, How > ) > = Vec::new(); - // fn into< 'a, V, How >( src : &'a V ) -> MaybeAs< 'a, String, How > - // where - // How : Clone + Copy + 'static, - // V : ToStringWith< How > + 'a, - // { - // MaybeAs::< 'a, String, How >::from - // ( - // < V as ToStringWith< How > >::to_string_with( src ) - // ) - // } + fn from< 'a, V, How >( src : &'a V ) -> MaybeAs< 'a, String, How > + where + How : Clone + Copy + 'static, + V : ToStringWith< How > + 'a, + { + MaybeAs::< 'a, String, How >::from + ( + < V as ToStringWith< How > >::to_string_with( src ) + ) + } fn add< 'a, V, How > ( @@ -61,15 +61,12 @@ where How : Clone + Copy + 'static, V : ToStringWith< How > + 'a, { - let val = MaybeAs::< 'a, String, How >::from - ( - < V as ToStringWith< How > >::to_string_with( src ) - ); + let val = from( src ); dst.push( ( key, val ) ); } - // dst.push( ( "id", MaybeAs::< 'a, String, How >::from( &self.id ) ) ); - add( &mut dst, "id", &self.id ); + dst.push( ( "id", from( &self.id ) ) ); + // add( &mut dst, "id", &self.id ); add( &mut dst, "created_at", &self.created_at ); add( &mut dst, "file_ids", &self.file_ids ); @@ -82,32 +79,6 @@ where dst.push( ( "tools", MaybeAs::none() ) ); } -// dst.push( ( "id", into( &self.id ) ) ); -// dst.push( ( "created_at", into( &self.created_at ) ) ); -// dst.push( ( "file_ids", into( &self.file_ids ) ) ); -// -// if let Some( tools ) = &self.tools -// { -// dst.push( ( "tools", into( &self.tools ) ) ); -// } -// else -// { -// dst.push( ( "tools", MaybeAs::none() ) ); -// } - - // dst.push( ( "id", MaybeAs::< 'a, String, How >::from( < String as ToStringWith< How > >::to_string_with( &self.id ) ) ) ); -// dst.push( ( "created_at", self.created_at.to_string_with().into() ) ); -// dst.push( ( "file_ids", self.file_ids.to_string_with().into() ) ); -// -// if let Some( tools ) = &self.tools -// { -// dst.push( ( "tools", self.tools.to_string_with().into() ) ); -// } -// else -// { -// dst.push( ( "tools", MaybeAs::none() ) ); -// } - dst.into_iter() } } @@ -170,6 +141,7 @@ fn basic() #[ test ] fn test_vec_fields() { + let test_objects = vec! [ TestObject @@ -201,4 +173,5 @@ fn test_vec_fields() assert_eq!( fields.len(), 2 ); assert_eq!( fields[ 0 ].0, 0 ); assert_eq!( fields[ 1 ].0, 1 ); + } diff --git a/module/core/former/Cargo.toml b/module/core/former/Cargo.toml index 812cda2467..ca855af42a 100644 --- a/module/core/former/Cargo.toml +++ b/module/core/former/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "former" -version = "2.3.0" +version = "2.4.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/former/Readme.md b/module/core/former/Readme.md index 40992b6116..d36ce4b061 100644 --- a/module/core/former/Readme.md +++ b/module/core/former/Readme.md @@ -1256,7 +1256,7 @@ Two key definition Traits: - Building upon `FormerDefinitionTypes`, this trait incorporates the `FormingEnd` callback, linking the formation types with a definitive ending. It specifies how the formation process should conclude, which may involve validations, transformations, or integrations into larger structures. - The inclusion of the `End` type parameter specifies the end conditions of the formation process, effectively connecting the temporary state held in storage to its ultimate form. -## Overview of Formation Traits +## Overview of Formation Traits System The formation process utilizes several core traits, each serving a specific purpose in the lifecycle of entity creation. These traits ensure that entities are constructed methodically, adhering to a structured pattern that enhances maintainability and scalability. Below is a summary of these key traits: diff --git a/module/core/former_meta/Cargo.toml b/module/core/former_meta/Cargo.toml index 5363d0dd89..32b6323ecc 100644 --- a/module/core/former_meta/Cargo.toml +++ b/module/core/former_meta/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "former_meta" -version = "2.3.0" +version = "2.4.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/former_types/Cargo.toml b/module/core/former_types/Cargo.toml index 96047371a5..371a31a76a 100644 --- a/module/core/former_types/Cargo.toml +++ b/module/core/former_types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "former_types" -version = "2.4.0" +version = "2.5.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/inspect_type/src/lib.rs b/module/core/inspect_type/src/lib.rs index 046f3332f9..b0e8da7f37 100644 --- a/module/core/inspect_type/src/lib.rs +++ b/module/core/inspect_type/src/lib.rs @@ -2,20 +2,6 @@ #![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ] #![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ] #![ doc( html_root_url = "https://docs.rs/inspect_type/latest/inspect_type/" ) ] -// #![ deny( rust_2018_idioms ) ] -// #![ deny( missing_debug_implementations ) ] -// #![ deny( missing_docs ) ] - -// #![ cfg( rustversion::nightly ) ] -// #![ feature( type_name_of_val ) ] -// #![ cfg_attr( feature = "type_name_of_val", feature( type_name_of_val ) ) ] - -// #![ cfg_attr( RUSTC_IS_NIGHTLY, feature( type_name_of_val ) ) ] - -//! -//! Diagnostic-purpose tools to inspect type of a variable and its size. -//! - #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] diff --git a/module/core/iter_tools/Cargo.toml b/module/core/iter_tools/Cargo.toml index 233ac33f5b..0675b432e9 100644 --- a/module/core/iter_tools/Cargo.toml +++ b/module/core/iter_tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "iter_tools" -version = "0.17.0" +version = "0.18.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/core/macro_tools/Cargo.toml b/module/core/macro_tools/Cargo.toml index 824ce77097..5071cdb8d0 100644 --- a/module/core/macro_tools/Cargo.toml +++ b/module/core/macro_tools/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "macro_tools" -version = "0.30.0" +version = "0.32.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", @@ -28,7 +28,11 @@ all-features = false [features] default = [ "enabled" ] full = [ "enabled" ] -enabled = [ "former_types/enabled", "interval_adapter/enabled" ] +enabled = [ + "former_types/enabled", + "interval_adapter/enabled", + "clone_dyn_types/enabled", +] # qqq : put all files under features: macro_attr, macro_container_kind, ... @@ -44,6 +48,7 @@ syn = { version = "~2.0.52", features = [ "full", "extra-traits" ] } ## internal interval_adapter = { workspace = true, features = [] } former_types = { workspace = true, features = [ "types_component_assign" ] } +clone_dyn_types = { workspace = true, features = [] } # xxx : qqq : optimize features [dev-dependencies] test_tools = { workspace = true } diff --git a/module/core/macro_tools/src/item_struct.rs b/module/core/macro_tools/src/item_struct.rs index 50b1318866..d98dcfcfd8 100644 --- a/module/core/macro_tools/src/item_struct.rs +++ b/module/core/macro_tools/src/item_struct.rs @@ -8,24 +8,25 @@ pub( crate ) mod private use crate::*; /// Extracts the types of each field into a vector. - // pub fn field_types< 'a >( t : &'a syn::ItemStruct ) -> impl IterTrait< 'a, &'a syn::Type > + Clone pub fn field_types< 'a >( t : &'a syn::ItemStruct ) -> impl IterTrait< 'a, &'a syn::Type > + Clone { t.fields.iter().map( | field | &field.ty ) } /// Retrieves the names of each field, if they exist. - // pub fn field_names< 'a >( t : &'a syn::ItemStruct ) -> Option< Box< dyn IterTrait< 'a, &'a syn::Ident > + '_ > > - pub fn field_names< 'a >( t : &'a syn::ItemStruct ) -> Option< DynIter< 'a, syn::Ident > > + // pub fn field_names< 'a >( t : &'a syn::ItemStruct ) -> Option< impl IterTrait< 'a, &'a syn::Ident > > + pub fn field_names< 'a >( t : &'a syn::ItemStruct ) -> Option< BoxedIter< 'a, &'a syn::Ident > > + // xxx { - match &t.fields + let result : Option< BoxedIter< 'a, &'a syn::Ident > > = match &t.fields { - // syn::Fields::Named( fields ) => Some( Box::new( fields.named.iter().map( | field | field.ident.as_ref().unwrap() ) ) ), - // syn::Fields::Unit => Some( Box::new( core::iter::empty() ) ), - syn::Fields::Named( fields ) => Some( DynIter::new( fields.named.iter().map( | field | field.ident.as_ref().unwrap() ) ) ), - syn::Fields::Unit => Some( DynIter::new( core::iter::empty() ) ), + syn::Fields::Named( fields ) => Some( Box::new( fields.named.iter().map( | field | field.ident.as_ref().unwrap() ) ) ), + syn::Fields::Unit => Some( Box::new( core::iter::empty() ) ), + // syn::Fields::Named( fields ) => Some( DynIter::new( fields.named.iter().map( | field | field.ident.as_ref().unwrap() ) ) ), + // syn::Fields::Unit => Some( DynIter::new( core::iter::empty() ) ), _ => None, - } + }; + return result; } /// Retrieves the type of the first field of the struct. diff --git a/module/core/macro_tools/src/iter.rs b/module/core/macro_tools/src/iter.rs index f4b5fcbfc9..13bb883dfb 100644 --- a/module/core/macro_tools/src/iter.rs +++ b/module/core/macro_tools/src/iter.rs @@ -2,219 +2,284 @@ //! Iterators. //! -// use std::fmt::Debug; - /// Internal namespace. pub( crate ) mod private { - use std::fmt; - - // use crate::*; + use clone_dyn_types::CloneDyn; - /// Trait that encapsulates an iterator with specific characteristics, tailored for use with the `syn` crate. + /// Trait that encapsulates an iterator with specific characteristics, tailored for use with the `syn` crate and implemetning `CloneDyn`. /// - /// The `IterTrait` trait is designed to represent iterators that may yield references to items (`&'a T`) within the `syn` crate. + /// The `_IterTrait` trait is designed to represent iterators that may yield references to items ( `&'a T` ) within the `syn` crate. /// These iterators must also implement the `ExactSizeIterator` and `DoubleEndedIterator` traits. /// This combination ensures that the iterator can: - /// - Provide an exact size hint (`ExactSizeIterator`), - /// - Be traversed from both ends (`DoubleEndedIterator`). + /// - Provide an exact size hint ( `ExactSizeIterator` ), + /// - Be traversed from both ends ( `DoubleEndedIterator` ). /// - pub trait IterTrait< 'a, T > - where - T : 'a, - Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, - { - } - - impl< 'a, T, I > IterTrait< 'a, T > for I - where - T : 'a, - I : 'a, - Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, - { - } - - /// Trait that encapsulates a clonable iterator with specific characteristics, tailored for use with the `syn` crate. + /// Additionally, the iterator must implement the `CloneDyn` trait, which allows cloning of trait objects. /// - /// The `IterTraitClonable` trait is designed to represent iterators that may yield references to items (`&'a T`) within the `syn` crate. - /// These iterators must also implement the `ExactSizeIterator`, `DoubleEndedIterator`, and `Clone` traits. - /// This combination ensures that the iterator can: - /// - Provide an exact size hint (`ExactSizeIterator`), - /// - Be traversed from both ends (`DoubleEndedIterator`), - /// - Be clonable (`Clone`). + /// # Example + /// ```rust + /// use assistant::_IterTrait; /// - pub trait IterTraitClonable< 'a, T > - where - T : 'a, - Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator + Clone, - { - } - - impl< 'a, T, I > IterTraitClonable< 'a, T > for I - where - T : 'a, - Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator + Clone, - { - } - - /// Wrapper around a boxed iterator that implements `IterTrait`. + /// // Example struct that implements Iterator, ExactSizeIterator, DoubleEndedIterator, and CloneDyn. + /// #[ derive( Clone ) ] + /// struct MyIterator + /// { + /// // internal fields + /// } /// - /// The `DynIter` struct provides a way to work with trait objects that implement the `IterTrait` trait. It acts as a - /// wrapper around a boxed iterator and provides methods to interact with the iterator in a type-safe manner. + /// impl Iterator for MyIterator + /// { + /// type Item = i32; /// - /// # Examples + /// fn next( &mut self ) -> Option< Self::Item > + /// { + /// // implementation + /// Some( 1 ) + /// } + /// } /// - /// ```rust - /// use crate::DynIter; - /// use std::vec::Vec; + /// impl ExactSizeIterator for MyIterator + /// { + /// fn len( &self ) -> usize + /// { + /// // implementation + /// 1 + /// } + /// } /// - /// let v = vec![1, 2, 3]; - /// let iter = DynIter::new(v.iter()); - /// for val in iter { - /// println!("{}", val); + /// impl DoubleEndedIterator for MyIterator + /// { + /// fn next_back( &mut self ) -> Option< Self::Item > + /// { + /// // implementation + /// Some( 1 ) + /// } /// } + /// + /// impl _IterTrait< '_, i32 > for MyIterator {} /// ``` - pub struct DynIter< 'a, T >( Box< dyn IterTrait< 'a, & 'a T > + 'a > ); - - impl< 'a, T > fmt::Debug for DynIter< 'a, T > + pub trait _IterTrait< 'a, T > + where + T : 'a, + Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, + Self : CloneDyn, { - fn fmt( &self, f : &mut fmt::Formatter<'_> ) -> fmt::Result - { - f.write_fmt( format_args!( "DynIter" ) ) - } } - impl< 'a, T > DynIter< 'a, T > + impl< 'a, T, I > _IterTrait< 'a, T > for I + where + T : 'a, + Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, + Self : CloneDyn, { - /// Creates a new `DynIter` from an iterator that implements `IterTrait`. - /// - /// # Parameters - /// - /// - `src`: The source iterator to be wrapped. - /// - /// # Returns - /// - /// A new instance of `DynIter`. - pub fn new< It >( src : It ) -> Self - where - It : IterTrait< 'a, & 'a T > + 'a, - { - Self( Box::new( src ) ) - } } - impl< 'a, T > From< DynIter< 'a, T > > for Box< dyn IterTrait< 'a, & 'a T > + 'a > + /// Implement `Clone` for boxed `_IterTrait` trait objects. + /// + /// This allows cloning of boxed iterators that implement `_IterTrait`. + #[ allow( non_local_definitions ) ] + impl< 'c, T > Clone for Box< dyn _IterTrait< 'c, T > + 'c > { - fn from( src : DynIter< 'a, T > ) -> Self + #[ inline ] + fn clone( &self ) -> Self { - src.0 + clone_dyn_types::clone_into_box( &**self ) } } - impl< 'a, T > core::ops::Deref for DynIter< 'a, T > + #[ allow( non_local_definitions ) ] + impl< 'c, T > Clone for Box< dyn _IterTrait< 'c, T > + Send + 'c > { - type Target = Box< dyn IterTrait< 'a, & 'a T > + 'a >; - - fn deref( & self ) -> & Self::Target + #[ inline ] + fn clone( &self ) -> Self { - & self.0 + clone_dyn_types::clone_into_box( &**self ) } } - impl< 'a, T > core::convert::AsRef< Box< dyn IterTrait< 'a, & 'a T > + 'a > > for DynIter< 'a, T > + #[ allow( non_local_definitions ) ] + impl< 'c, T > Clone for Box< dyn _IterTrait< 'c, T > + Sync + 'c > { - fn as_ref( & self ) -> & Box< dyn IterTrait< 'a, & 'a T > + 'a > + #[ inline ] + fn clone( &self ) -> Self { - & self.0 + clone_dyn_types::clone_into_box( &**self ) } } - impl< 'a, T > Iterator for DynIter< 'a, T > + #[ allow( non_local_definitions ) ] + impl< 'c, T > Clone for Box< dyn _IterTrait< 'c, T > + Send + Sync + 'c > { - type Item = & 'a T; - - fn next( & mut self ) -> Option< Self::Item > + #[ inline ] + fn clone( &self ) -> Self { - self.0.next() + clone_dyn_types::clone_into_box( &**self ) } } - impl< 'a, T > ExactSizeIterator for DynIter< 'a, T > + /// Type alias for boxed `_IterTrait` trait objects. + /// + /// Prefer `BoxedIter` over `impl _IterTrait` when using trait objects ( `dyn _IterTrait` ) because the concrete type in return is less restrictive than `impl _IterTrait`. + /// + /// # Example + /// ```rust + /// use assistant::{ _IterTrait, BoxedIter }; + /// + /// // Example function that returns a BoxedIter. + /// fn example_iterator() -> BoxedIter< 'static, i32 > + /// { + /// Box::new( MyIterator + /// { + /// // initialize fields + /// }) + /// } + /// ``` + pub type BoxedIter< 'a, T > = Box< dyn _IterTrait< 'a, T > + 'a >; + + /// Trait that encapsulates a clonable iterator with specific characteristics, tailored for use with the `syn` crate. + /// + /// The `IterTrait` trait is designed to represent iterators that may yield references to items ( `&'a T` ) within the `syn` crate. + /// These iterators must also implement the `ExactSizeIterator`, `DoubleEndedIterator`, and `Clone` traits. + /// This combination ensures that the iterator can: + /// - Provide an exact size hint ( `ExactSizeIterator` ), + /// - Be traversed from both ends ( `DoubleEndedIterator` ), + /// - Be clonable ( `Clone` ). + /// + pub trait IterTrait< 'a, T > + where + T : 'a, + Self : _IterTrait< 'a, T > + Clone, { - fn len( & self ) -> usize - { - self.0.len() - } } - impl< 'a, T > DoubleEndedIterator for DynIter< 'a, T > + impl< 'a, T, I > IterTrait< 'a, T > for I + where + T : 'a, + Self : _IterTrait< 'a, T > + Clone, { - fn next_back( & mut self ) -> Option< Self::Item > - { - self.0.next_back() - } } -// pub trait IterTrait< 'a, T > -// where -// T : 'a, -// Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator + Clone, +// xxx : qqq : make command to autogenerate it +// /// Wrapper around a boxed iterator that implements `_IterTrait`. +// /// +// /// The `DynIter` struct provides a way to work with trait objects that implement the `_IterTrait` trait. It acts as a +// /// wrapper around a boxed iterator and provides methods to interact with the iterator in a type-safe manner. +// /// +// /// # Examples +// /// +// /// ```rust +// /// use crate::DynIter; +// /// use std::vec::Vec; +// /// +// /// let v = vec![ 1, 2, 3 ]; +// /// let iter = DynIter::new( v.iter() ); +// /// for val in iter +// /// { +// /// println!( "{}", val ); +// /// } +// /// ``` +// pub struct DynIter< 'a, T >( Box< dyn _IterTrait< 'a, & 'a T > + 'a > ); +// +// impl< 'a, T > fmt::Debug for DynIter< 'a, T > // { -// // fn clone_box( self ) -> Box< dyn IterTrait< 'a, T > + 'a >; +// fn fmt( &self, f : &mut fmt::Formatter<'_> ) -> fmt::Result +// { +// f.write_fmt( format_args!( "DynIter" ) ) +// } // } // -// impl< 'a, T, I > IterTrait< 'a, T > for I -// where -// T : 'a, -// I : 'a, -// Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator + Clone, +// impl< 'a, T > DynIter< 'a, T > // { +// /// Creates a new `DynIter` from an iterator that implements `_IterTrait`. +// /// +// /// # Parameters +// /// +// /// - `src`: The source iterator to be wrapped. +// /// +// /// # Returns +// /// +// /// A new instance of `DynIter`. +// pub fn new< It >( src : It ) -> Self +// where +// It : _IterTrait< 'a, & 'a T > + 'a, +// { +// Self( Box::new( src ) ) +// } +// } // -// // fn clone_box( self ) -> Box< dyn IterTrait< 'a, T > + 'a > -// // { -// // Box::new( self ).clone() -// // } +// impl< 'a, T > From< DynIter< 'a, T > > for Box< dyn _IterTrait< 'a, & 'a T > + 'a > +// { +// fn from( src : DynIter< 'a, T > ) -> Self +// { +// src.0 +// } +// } // +// impl< 'a, T > core::ops::Deref for DynIter< 'a, T > +// { +// type Target = Box< dyn _IterTrait< 'a, & 'a T > + 'a >; +// +// fn deref( & self ) -> & Self::Target +// { +// & self.0 +// } // } - -// /// Trait that encapsulates an iterator with specific characteristics, tailored for use with the `syn` crate. -// /// -// /// The `IterTrait2` trait is designed to represent iterators that yield references to items (`&'a T`) within the `syn` crate. -// /// These iterators must also implement the `ExactSizeIterator` and `DoubleEndedIterator` traits. -// /// This combination ensures that the iterator can: -// /// - Provide an exact size hint (`ExactSizeIterator`), -// /// - Be traversed from both ends (`DoubleEndedIterator`). -// /// -// pub trait IterTrait2< T > -// where -// Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, +// +// impl< 'a, T > core::convert::AsRef< Box< dyn _IterTrait< 'a, & 'a T > + 'a > > for DynIter< 'a, T > // { +// fn as_ref( & self ) -> & Box< dyn _IterTrait< 'a, & 'a T > + 'a > +// { +// & self.0 +// } // } // -// impl< T, I > IterTrait2< T > for I -// where -// Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, +// impl< 'a, T > Iterator for DynIter< 'a, T > // { +// type Item = & 'a T; +// +// fn next( & mut self ) -> Option< Self::Item > +// { +// self.0.next() +// } // } // -// /// Trait that encapsulates an iterator with specific characteristics, tailored for use with the `syn` crate. -// /// -// /// The `IterTrait3` trait is designed to represent iterators that yield references to items (`&'a T`) within the `syn` crate. -// /// These iterators must also implement the `ExactSizeIterator` and `DoubleEndedIterator` traits. -// /// This combination ensures that the iterator can: -// /// - Provide an exact size hint (`ExactSizeIterator`), -// /// - Be traversed from both ends (`DoubleEndedIterator`). -// /// -// pub trait IterTrait3< 'a, T : 'a > -// where -// Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, +// impl< 'a, T > ExactSizeIterator for DynIter< 'a, T > +// { +// fn len( & self ) -> usize +// { +// self.0.len() +// } +// } +// +// impl< 'a, T > DoubleEndedIterator for DynIter< 'a, T > +// { +// fn next_back( & mut self ) -> Option< Self::Item > +// { +// self.0.next_back() +// } +// } + + // = + +// trait Cloneable : Clone // { +// fn clone_box( & self ) -> Box< dyn Cloneable >; // } // -// impl< 'a, T : 'a, I > IterTrait3< 'a, T > for I +// impl< T > Cloneable for T // where -// Self : Iterator< Item = T > + ExactSizeIterator< Item = T > + DoubleEndedIterator, +// T : 'static + Clone, +// { +// fn clone_box( & self ) -> Box< dyn Cloneable > +// { +// Box::new( self.clone() ) +// } +// } +// +// pub fn clone_boxed( t : & dyn Cloneable ) -> Box< dyn Cloneable > // { +// t.clone_box() // } } @@ -255,9 +320,10 @@ pub mod exposed #[ allow( unused_imports ) ] pub use super::private:: { + _IterTrait, IterTrait, - IterTraitClonable, - DynIter, + BoxedIter, + // DynIter, // DynIterFrom, // IterTrait2, // IterTrait3, diff --git a/module/core/macro_tools/src/struct_like.rs b/module/core/macro_tools/src/struct_like.rs index d95ef0f01b..4658265551 100644 --- a/module/core/macro_tools/src/struct_like.rs +++ b/module/core/macro_tools/src/struct_like.rs @@ -9,7 +9,7 @@ pub( crate ) mod private // use interval_adapter::BoundExt; /// Enum to encapsulate either a field from a struct or a variant from an enum. - #[ derive( Debug, PartialEq ) ] + #[ derive( Debug, PartialEq, Clone ) ] pub enum FieldOrVariant< 'a > { /// Represents a field within a struct or union. @@ -18,6 +18,11 @@ pub( crate ) mod private Variant( &'a syn::Variant ), } + // xxx + impl< 'a > Copy for FieldOrVariant< 'a > + { + } + impl< 'a > From< &'a syn::Field > for FieldOrVariant< 'a > { fn from( field : &'a syn::Field ) -> Self @@ -253,17 +258,17 @@ pub( crate ) mod private StructLike::Unit( _ ) => { let empty : Vec< FieldOrVariant< 'a > > = vec![]; - Box::new( empty.into_iter() ) as Box< dyn IterTrait< 'a, FieldOrVariant< 'a > > > + Box::new( empty.into_iter() ) as BoxedIter< 'a, FieldOrVariant< 'a > > }, StructLike::Struct( item ) => { let fields = item.fields.iter().map( FieldOrVariant::from ); - Box::new( fields ) as Box< dyn IterTrait< 'a, FieldOrVariant< 'a > > > + Box::new( fields ) as BoxedIter< 'a, FieldOrVariant< 'a > > }, StructLike::Enum( item ) => { let variants = item.variants.iter().map( FieldOrVariant::from ); - Box::new( variants ) as Box< dyn IterTrait< 'a, FieldOrVariant< 'a > > > + Box::new( variants ) as BoxedIter< 'a, FieldOrVariant< 'a > > }, } } @@ -349,11 +354,11 @@ pub( crate ) mod private } /// Returns an iterator over fields of the item. - // pub fn fields( &self ) -> Box< dyn Iterator< Item = &syn::Field > + '_ > - pub fn fields< 'a >( &'a self ) -> Box< dyn IterTrait< 'a, &'a syn::Field > + '_ > - // pub fn fields< 'a >( &'a self ) -> impl IterTrait< 'a, &'a syn::Field > + // pub fn fields< 'a >( &'a self ) -> BoxedIter< 'a, &'a syn::Field > + pub fn fields< 'a >( &'a self ) -> impl IterTrait< 'a, &'a syn::Field > + // xxx { - match self + let result : BoxedIter< 'a, &'a syn::Field > = match self { StructLike::Unit( _item ) => { @@ -367,12 +372,13 @@ pub( crate ) mod private { Box::new( std::iter::empty() ) }, - } + }; + result } /// Extracts the name of each field. - // pub fn field_names< 'a >( &'a self ) -> Option< impl IterTrait< 'a, &'a syn::Ident > + '_ > - pub fn field_names< 'a >( &'a self ) -> Option< DynIter< 'a, syn::Ident > > + pub fn field_names< 'a >( &'a self ) -> Option< impl IterTrait< 'a, &'a syn::Ident > + '_ > + // pub fn field_names< 'a >( &'a self ) -> Option< DynIter< 'a, syn::Ident > > { match self { @@ -386,7 +392,10 @@ pub( crate ) mod private }, StructLike::Enum( _item ) => { - Some( DynIter::new( self.fields().map( | field | field.ident.as_ref().unwrap() ) ) ) + // xxx + let iter : BoxedIter< 'a, &'a syn::Ident > = Box::new( self.fields().map( | field | field.ident.as_ref().unwrap() ) ); + Some( iter ) + // Some( DynIter::new( self.fields().map( | field | field.ident.as_ref().unwrap() ) ) ) // Some( DynIterFrom::dyn_iter_from( self.fields().map( | field | field.ident.as_ref().unwrap() ) ) ) // Box::new( std::iter::empty() ) }, @@ -395,19 +404,21 @@ pub( crate ) mod private } /// Extracts the type of each field. - // pub fn field_types( &self ) -> Box< dyn Iterator< Item = &syn::Type > + '_ > - // pub fn field_types< 'a >( &'a self ) -> Box< dyn IterTrait< 'a, &'a syn::Type > + '_ > pub fn field_types< 'a >( &'a self ) -> impl IterTrait< 'a, &'a syn::Type > + // pub fn field_types< 'a >( &'a self ) -> BoxedIter< 'a, &'a syn::Type > { - Box::new( self.fields().map( | field | &field.ty ) ) + // Box::new( self.fields().map( | field | &field.ty ) ) + self.fields().map( | field | &field.ty ) } /// Extracts the name of each field. // pub fn field_attrs( &self ) -> Box< dyn Iterator< Item = &Vec< syn::Attribute > > + '_ > - // pub fn field_attrs< 'a >( &'a self ) -> Box< dyn IterTrait< 'a, &'a Vec< syn::Attribute > > + '_ > pub fn field_attrs< 'a >( &'a self ) -> impl IterTrait< 'a, &'a Vec< syn::Attribute > > + // pub fn field_attrs< 'a >( &'a self ) -> BoxedIter< 'a, &'a Vec< syn::Attribute > > { - Box::new( self.fields().map( | field | &field.attrs ) ) + self.fields().map( | field | &field.attrs ) + // Box::new( self.fields().map( | field | &field.attrs ) ) + // xxx } /// Extract the first field. diff --git a/module/core/process_tools/src/process.rs b/module/core/process_tools/src/process.rs index db954da17c..6c34f298f5 100644 --- a/module/core/process_tools/src/process.rs +++ b/module/core/process_tools/src/process.rs @@ -272,7 +272,7 @@ pub( crate ) mod private { fn clone( &self ) -> Self { - Report + Self { command : self.command.clone(), current_path : self.current_path.clone(), diff --git a/module/core/reflect_tools/src/reflect/fields.rs b/module/core/reflect_tools/src/reflect/fields.rs index 888517f730..2956c8180f 100644 --- a/module/core/reflect_tools/src/reflect/fields.rs +++ b/module/core/reflect_tools/src/reflect/fields.rs @@ -35,28 +35,30 @@ pub( crate ) mod private { } + /// /// A trait for iterating over all fields convertible into a specified type within an entity. /// /// # Type Parameters /// /// - `K`: The key type. - /// - `E`: The element type. - pub trait Fields< 'a, K, E > + /// - `V`: The value type. + /// + pub trait Fields< 'a, K, V > where - E : Clone + 'a, + V : Clone + 'a, { /// Returns an iterator over all fields of the specified type within the entity. - fn fields( &'a self ) -> impl IteratorTrait< Item = ( K, E ) >; - // fn fields( &'a self ) -> impl IteratorTrait< Item = ( K, Option< Cow< 'a, E > > ) >; + fn fields( &'a self ) -> impl IteratorTrait< Item = ( K, V ) >; + // fn fields( &'a self ) -> impl IteratorTrait< Item = ( K, Option< Cow< 'a, V > > ) >; } // /// Return number of fields convertible into a specified type withing an entity. // /// // /// # Type Parameters // /// - // /// - `E`: The element type. + // /// - `V`: The value type. // /// - // pub trait FieldsLen< E > + // pub trait FieldsLen< V > // { // /// Return number of fields convertible into a specified type withing an entity. // fn len( &self ) -> usize; diff --git a/module/move/wca/Cargo.toml b/module/move/wca/Cargo.toml index 7489b66fbb..f4d6f7c861 100644 --- a/module/move/wca/Cargo.toml +++ b/module/move/wca/Cargo.toml @@ -45,6 +45,7 @@ strs_tools = { workspace = true, features = [ "default" ] } mod_interface = { workspace = true, features = [ "default" ] } iter_tools = { workspace = true, features = [ "default" ] } former = { workspace = true, features = [ "default" ] } +# xxx : qqq : optimize set of features ## external log = "0.4" diff --git a/module/move/willbe/src/tool/cargo.rs b/module/move/willbe/src/tool/cargo.rs index 0edc77a7e1..32ef54e375 100644 --- a/module/move/willbe/src/tool/cargo.rs +++ b/module/move/willbe/src/tool/cargo.rs @@ -19,7 +19,9 @@ mod private pub( crate ) channel : Channel, #[ former( default = true ) ] pub( crate ) allow_dirty : bool, - #[ former( default = true ) ] + // qqq : rename to checking_changes + #[ former( default = false ) ] + // qqq : don't abuse negative form, rename to checking_consistency pub( crate ) no_verify : bool, pub( crate ) temp_path : Option< PathBuf >, pub( crate ) dry : bool,