diff --git a/Cargo.toml b/Cargo.toml index a940b1b1ec..cfbea9f300 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,9 +29,9 @@ discord_url = "https://discord.gg/m3YfbXpUUY" # Source :: https://github.com/obox-systems/conventions/blob/master/code_style.md#lints-and-warnings # Denies non-idiomatic code for Rust 2018 edition. -rust_2018_idioms = "deny" +rust_2018_idioms = { level = "deny", priority = -1 } # Denies using features that may break in future Rust versions. -future_incompatible = "deny" +future_incompatible = { level = "deny", priority = -1 } # Warns if public items lack documentation. missing_docs = "warn" # Warns for public types not implementing Debug. @@ -41,9 +41,9 @@ unsafe-code = "warn" [workspace.lints.clippy] # Denies restrictive lints, limiting certain language features/patterns. -restriction = "warn" +#restriction = { level = "deny", priority = -1 } # Denies pedantic lints, enforcing strict coding styles and conventions. -pedantic = "warn" +pedantic = { level = "warn", priority = -1 } # Denies undocumented unsafe blocks. undocumented_unsafe_blocks = "deny" # xxx : check @@ -492,7 +492,7 @@ version = "~0.2.0" path = "module/move/sqlx_query" [workspace.dependencies.deterministic_rand] -version = "~0.5.0" +version = "~0.6.0" path = "module/move/deterministic_rand" [workspace.dependencies.crates_tools] @@ -536,4 +536,36 @@ version = "0.1.83" [workspace.dependencies.tokio] version = "1.41.0" features = [] -default-features = false \ No newline at end of file +default-features = false + +[workspace.dependencies.anyhow] +version = "~1.0" +# features = [] +# default-features = false + +[workspace.dependencies.thiserror] +version = "~1.0" +# features = [] +# default-features = false + +[workspace.dependencies.hashbrown] +version = "~0.14.3" +# optional = true +default-features = false +# features = [ "default" ] + +[workspace.dependencies.paste] +version = "~1.0.14" +default-features = false + +[workspace.dependencies.tempdir] +version = "~0.3.7" + +[workspace.dependencies.rustversion] +version = "~1.0" + +[workspace.dependencies.num-traits] +version = "~0.2" + +[workspace.dependencies.rand] +version = "0.8.5" diff --git a/cgtools b/cgtools deleted file mode 160000 index f42bdc878f..0000000000 --- a/cgtools +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f42bdc878f9414f7fd46b212454f615ab6ebcf61 diff --git a/module/alias/instance_of/src/typing/implements_lib.rs b/module/alias/instance_of/src/typing/implements_lib.rs index 1a3f76aa7e..4129608ed8 100644 --- a/module/alias/instance_of/src/typing/implements_lib.rs +++ b/module/alias/instance_of/src/typing/implements_lib.rs @@ -15,7 +15,7 @@ // #[ macro_use ] mod implements_impl; -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/alias/instance_of/src/typing/is_slice_lib.rs b/module/alias/instance_of/src/typing/is_slice_lib.rs index 0f4a45cbc4..f3479787d1 100644 --- a/module/alias/instance_of/src/typing/is_slice_lib.rs +++ b/module/alias/instance_of/src/typing/is_slice_lib.rs @@ -12,7 +12,7 @@ #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/alias/wtest_basic/src/test/basic/helper.rs b/module/alias/wtest_basic/src/test/basic/helper.rs index fd3f8907d2..dc9ed8372b 100644 --- a/module/alias/wtest_basic/src/test/basic/helper.rs +++ b/module/alias/wtest_basic/src/test/basic/helper.rs @@ -3,7 +3,7 @@ //! Helpers. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/alias/wtest_basic/src/test/basic/mod.rs b/module/alias/wtest_basic/src/test/basic/mod.rs index 9e9e011623..034ebb427a 100644 --- a/module/alias/wtest_basic/src/test/basic/mod.rs +++ b/module/alias/wtest_basic/src/test/basic/mod.rs @@ -3,7 +3,7 @@ //! Basic tools for testing. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } diff --git a/module/core/async_from/src/lib.rs b/module/core/async_from/src/lib.rs index b2419ae521..669dcf988e 100644 --- a/module/core/async_from/src/lib.rs +++ b/module/core/async_from/src/lib.rs @@ -11,7 +11,7 @@ pub mod dependency pub use ::async_trait; } -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( feature = "enabled" ) ] mod private { diff --git a/module/core/async_tools/src/lib.rs b/module/core/async_tools/src/lib.rs index ab0bcbf7e8..0390e0dbe2 100644 --- a/module/core/async_tools/src/lib.rs +++ b/module/core/async_tools/src/lib.rs @@ -12,7 +12,7 @@ pub mod dependency pub use ::async_from; } -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( feature = "enabled" ) ] mod private { diff --git a/module/core/clone_dyn/src/lib.rs b/module/core/clone_dyn/src/lib.rs index 18e0150163..57ae64c7f8 100644 --- a/module/core/clone_dyn/src/lib.rs +++ b/module/core/clone_dyn/src/lib.rs @@ -14,7 +14,7 @@ pub mod dependency pub use ::clone_dyn_types; } -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( feature = "enabled" ) ] mod private { diff --git a/module/core/clone_dyn_types/Readme.md b/module/core/clone_dyn_types/Readme.md index 12cc1e5f46..0a3caaae26 100644 --- a/module/core/clone_dyn_types/Readme.md +++ b/module/core/clone_dyn_types/Readme.md @@ -1,5 +1,5 @@ -# Module :: clone_dyn_types +# 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) diff --git a/module/core/clone_dyn_types/src/lib.rs b/module/core/clone_dyn_types/src/lib.rs index 3fc94133df..2642542d03 100644 --- a/module/core/clone_dyn_types/src/lib.rs +++ b/module/core/clone_dyn_types/src/lib.rs @@ -10,7 +10,7 @@ pub mod dependency { } -/// Internal namespace. +/// Define a private namespace for all its items. // #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] #[ cfg( feature = "enabled" ) ] mod private @@ -39,6 +39,7 @@ mod private T : Clone, { #[ inline ] + #[ allow( clippy::implicit_return, clippy::as_conversions, clippy::ptr_as_ptr ) ] fn __clone_dyn( &self, _ : DontCallMe ) -> *mut () { Box::< T >::into_raw( Box::new( self.clone() ) ) as *mut () @@ -51,6 +52,7 @@ mod private T : Clone, { #[ inline ] + #[ allow( clippy::implicit_return, clippy::as_conversions, clippy::ptr_as_ptr ) ] fn __clone_dyn( &self, _ : DontCallMe ) -> *mut () { Box::< [ T ] >::into_raw( self.iter().cloned().collect() ) as *mut () @@ -61,6 +63,7 @@ mod private impl CloneDyn for str { #[ inline ] + #[ allow( clippy::as_conversions, clippy::ptr_as_ptr, clippy::implicit_return ) ] fn __clone_dyn( &self, _ : DontCallMe ) -> *mut () { Box::< str >::into_raw( Box::from( self ) ) as *mut () @@ -68,7 +71,7 @@ mod private } /// - /// True clone which is applicable not only to clonable entities, but to trait objects implementing CloneDyn. + /// True clone which is applicable not only to clonable entities, but to trait objects implementing `CloneDyn`. /// /// # Example /// @@ -100,7 +103,7 @@ mod private // 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 ) ] + #[ allow( unsafe_code, clippy::as_conversions, clippy::ptr_as_ptr, clippy::implicit_return, clippy::undocumented_unsafe_blocks ) ] unsafe { *Box::from_raw( < T as CloneDyn >::__clone_dyn( src, DontCallMe ) as *mut T ) @@ -185,7 +188,7 @@ mod private // 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 ) ] + #[ allow( unsafe_code, clippy::implicit_return, clippy::as_conversions, clippy::ptr_cast_constness, clippy::ptr_as_ptr, clippy::multiple_unsafe_ops_per_block, clippy::undocumented_unsafe_blocks, clippy::ref_as_ptr ) ] unsafe { let mut ptr = ref_dyn as *const T; @@ -207,13 +210,14 @@ mod private impl< T : Clone > Sealed for [ T ] {} impl Sealed for str {} } - use sealed::*; + use sealed::{ DontCallMe, Sealed }; } #[ cfg( feature = "enabled" ) ] #[ doc( inline ) ] #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use own::*; /// Own namespace of the module. @@ -221,8 +225,9 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { - use super::*; + use super::orphan; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use orphan::*; } @@ -231,8 +236,9 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { - use super::*; + use super::exposed; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use exposed::*; } @@ -241,8 +247,9 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { - use super::*; + use super::prelude; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use prelude::*; } @@ -251,8 +258,9 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { - use super::*; + use super::private; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use private:: { CloneDyn, diff --git a/module/core/collection_tools/Cargo.toml b/module/core/collection_tools/Cargo.toml index 86dcfa51b3..d69009a758 100644 --- a/module/core/collection_tools/Cargo.toml +++ b/module/core/collection_tools/Cargo.toml @@ -11,16 +11,14 @@ documentation = "https://docs.rs/collection_tools" repository = "https://github.com/Wandalen/wTools/tree/master/module/core/collection_tools" homepage = "https://github.com/Wandalen/wTools/tree/master/module/core/collection_tools" description = """ -Collection of general purpose tools to manipulate collections( containers like Vec/HashMap/HashSet ). +General purpose tools to manipulate collections( containers like Vec/HashMap/HashSet ). """ categories = [ "algorithms", "development-tools" ] keywords = [ "fundamental", "general-purpose" ] - [lints] workspace = true - [package.metadata.docs.rs] features = [ "full" ] all-features = false @@ -28,31 +26,26 @@ all-features = false [features] no_std = [ - # "test_tools/no_std", ] use_alloc = [ - "no_std", # qqq : for Anton : why is that better? -- use_alloc means that we do not use std, but alloc and hashbrown + "no_std", "hashbrown", - # "test_tools/use_alloc", // why is it needed? -- not needed, removed ] default = [ "enabled", - # "reexports", "collection_constructors", "collection_into_constructors", ] full = [ "enabled", - # "reexports", "collection_constructors", "collection_into_constructors", ] enabled = [] -# reexports = [] # Collection constructors, like `hmap!{ "key" => "val" }` collection_constructors = [] @@ -63,7 +56,7 @@ collection_into_constructors = [] [dependencies] ## external -hashbrown = { version = "~0.14.3", optional = true, default-features = false, features = [ "default" ] } +hashbrown = { workspace = true, optional = true, default-features = false, features = [ "default" ] } [dev-dependencies] test_tools = { workspace = true } diff --git a/module/core/collection_tools/Readme.md b/module/core/collection_tools/Readme.md index 1430c6d6ef..b247a692b0 100644 --- a/module/core/collection_tools/Readme.md +++ b/module/core/collection_tools/Readme.md @@ -1,11 +1,11 @@ -# Module :: collection_tools +# Module :: `collection_tools` [![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_collection_tools_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_collection_tools_push.yml) [![docs.rs](https://img.shields.io/docsrs/collection_tools?color=e3e8f0&logo=docs.rs)](https://docs.rs/collection_tools) [![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%2Fcollection_tools%2Fexamples%2Fcollection_tools_trivial.rs,RUN_POSTFIX=--example%20collection_tools_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) -Collection of general purpose tools to manipulate collections( containers like Vec/HashMap/HashSet... ). +General purpose tools to manipulate collections( containers like Vec/HashMap/HashSet... ). ### Basic Use Case :: Variadic Constructors for Collections @@ -71,7 +71,7 @@ assert_eq!( meta_list, meta_list ); ### Basic Use Case :: `no_std` `HashSet` / `HashMap` -When implementing a `no_std` environment with the `use_alloc` feature in your Rust project, you'll encounter a challenge: collections like `Vec` are imported differently depending on the availability of the `std` library. Moreover, to use data structures such as `HashSet` or `HashMap` in a `no_std` context, it's necessary to depend on third-party crates, as these are not provided by the `alloc` crate directly. This crate aims to simplify the process of designing Rust libraries or applications that require these collections in a `no_std` environment, offering a more streamlined approach to working with dynamic data structures without the standard library. +When implementing a `no_std` ( `!use_std` ) environment with the `use_alloc` feature in your Rust project, you'll encounter a challenge: collections like `Vec` are imported differently depending on the availability of the `std` library. Moreover, to use data structures such as `HashSet` or `HashMap` in a `no_std` context, it's necessary to depend on third-party crates, as these are not provided by the `alloc` crate directly. This crate aims to simplify the process of designing Rust libraries or applications that require these collections in a `no_std` environment, offering a more streamlined approach to working with dynamic data structures without the standard library. You can do @@ -98,7 +98,7 @@ Instead of # #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] # { -#[ cfg( feature = "use_alloc" ) ] +#[ cfg( all( feature = "no_std", feature = "use_alloc" ) ) ] use hashbrown::HashSet; // a `no_std` replacement for `HashSet` #[ cfg( not( feature = "no_std" ) ) ] use std::collections::HashSet; @@ -120,7 +120,8 @@ While strict macros require you to have all members of the same type, more relax For example: ```rust -# #[ cfg( all( feature = "enabled", feature = "collection_into_constructors", any( not( feature = "no_std" ), feature = "use_alloc" ) ) ) ] +# #[ cfg( all( feature = "enabled", feature = "collection_into_constructors" ) ) ] +# #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] # { use std::borrow::Cow; let vec : Vec< String > = collection_tools::into_vec!( "&str", "String".to_string(), Cow::from( "Cow" ) ); diff --git a/module/core/collection_tools/examples/collection_tools_trivial.rs b/module/core/collection_tools/examples/collection_tools_trivial.rs index 8a11bb85bf..79ff09bf0d 100644 --- a/module/core/collection_tools/examples/collection_tools_trivial.rs +++ b/module/core/collection_tools/examples/collection_tools_trivial.rs @@ -19,18 +19,15 @@ //! a `HashMap`, making your code cleaner and more concise. This is particularly useful in cases //! where you need to define a map with a known set of key-value pairs upfront. -#[ cfg( not( all -( -// not( feature = "use_alloc" ) ) ], - all( feature = "enabled", feature = "collection_constructors" ), - any( not( feature = "no_std" ), feature = "use_alloc" ) +#[ cfg( not( all( + feature = "enabled", + feature = "collection_constructors", + any( feature = "use_alloc", not( feature = "no_std" ) ) )))] -fn main(){} +fn main() {} -// zzz : aaa : rid of `#[ cfg( not( feature = "use_alloc" ) ) ]` -- Rid of by not relying on std -// #[ cfg( not( feature = "use_alloc" ) ) ] #[ cfg( all( feature = "enabled", feature = "collection_constructors" ) ) ] -#[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] +#[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] fn main() { use collection_tools::*; diff --git a/module/core/collection_tools/src/collection.rs b/module/core/collection_tools/src/collection.rs deleted file mode 100644 index 67315f35a4..0000000000 --- a/module/core/collection_tools/src/collection.rs +++ /dev/null @@ -1,32 +0,0 @@ -/// Not meant to be called directly. -#[ doc( hidden ) ] -#[ macro_export( local_inner_macros ) ] -macro_rules! count -{ - ( @single $( $x : tt )* ) => ( () ); - - ( - @count $( $rest : expr ),* - ) - => - ( - < [ () ] >::len( &[ $( count!( @single $rest ) ),* ] ) - ); -} - -/// [std::collections::BTreeMap] macros -pub mod bmap; -/// [std::collections::BTreeSet] macros -pub mod bset; -/// [std::collections::BinaryHeap] macros -pub mod heap; -/// [std::collections::HashMap] macros -pub mod hmap; -/// [std::collections::HashSet] macros -pub mod hset; -/// [std::collections::LinkedList] macros -pub mod llist; -/// [Vec] macros -pub mod vec; -/// [std::collections::VecDeque] macros -pub mod deque; diff --git a/module/core/collection_tools/src/collection/heap.rs b/module/core/collection_tools/src/collection/binary_heap.rs similarity index 88% rename from module/core/collection_tools/src/collection/heap.rs rename to module/core/collection_tools/src/collection/binary_heap.rs index 8d38492497..faaa934427 100644 --- a/module/core/collection_tools/src/collection/heap.rs +++ b/module/core/collection_tools/src/collection/binary_heap.rs @@ -1,6 +1,10 @@ +#[ allow( unused_imports, clippy::wildcard_imports ) ] +use super::*; + #[ doc( inline ) ] #[ allow( unused_imports ) ] - pub use alloc::collections::binary_heap::*; +#[ allow( clippy::pub_use ) ] +pub use alloc::collections::binary_heap::*; /// Creates a `BinaryHeap` from a list of elements. /// @@ -29,8 +33,8 @@ /// # Parameters /// /// - `$( $key:expr ),* $( , )?`: A comma-separated list of elements to insert into the `BinaryHeap`. -/// Each element can be of any type that implements the `Into` trait, where `T` is the -/// type stored in the `BinaryHeap`. +/// Each element can be of any type that implements the `Into` trait, where `T` is the +/// type stored in the `BinaryHeap`. /// /// # Returns /// @@ -57,7 +61,7 @@ macro_rules! heap => {{ let _cap = count!( @count $( $key ),* ); - let mut _heap = $crate::heap::BinaryHeap::with_capacity( _cap ); + let mut _heap = $crate::collection::BinaryHeap::with_capacity( _cap ); $( _heap.push( $key ); )* @@ -98,8 +102,8 @@ macro_rules! heap /// # Parameters /// /// - `$( $key:expr ),* $( , )?`: A comma-separated list of elements to insert into the `BinaryHeap`. -/// Each element can be of any type that implements the `Into` trait, where `T` is the -/// type stored in the `BinaryHeap`. +/// Each element can be of any type that implements the `Into` trait, where `T` is the +/// type stored in the `BinaryHeap`. /// /// # Returns /// @@ -146,7 +150,7 @@ macro_rules! into_heap => {{ let _cap = count!( @count $( $key ),* ); - let mut _heap = $crate::heap::BinaryHeap::with_capacity( _cap ); + let mut _heap = $crate::collection::BinaryHeap::with_capacity( _cap ); $( _heap.push( Into::into( $key ) ); )* diff --git a/module/core/collection_tools/src/collection/bmap.rs b/module/core/collection_tools/src/collection/btree_map.rs similarity index 89% rename from module/core/collection_tools/src/collection/bmap.rs rename to module/core/collection_tools/src/collection/btree_map.rs index e96f045e84..fc79de564b 100644 --- a/module/core/collection_tools/src/collection/bmap.rs +++ b/module/core/collection_tools/src/collection/btree_map.rs @@ -1,5 +1,9 @@ +#[ allow( unused_imports, clippy::wildcard_imports ) ] +use super::*; + #[ doc( inline ) ] #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use alloc::collections::btree_map::*; /// Creates a `BTreeMap` from a list of key-value pairs. @@ -29,8 +33,8 @@ pub use alloc::collections::btree_map::*; /// # Parameters /// /// - `$( $key:expr => $value:expr ),* $( , )?`: A comma-separated list of key-value pairs to insert into the `BTreeMap`. -/// Each key and value can be of any type that implements the `Into< K >` and `Into< V >` traits, where `K` and `V` are the -/// types stored in the `BTreeMap` as keys and values, respectively. +/// Each key and value can be of any type that implements the `Into< K >` and `Into< V >` traits, where `K` and `V` are the +/// types stored in the `BTreeMap` as keys and values, respectively. /// /// # Returns /// @@ -70,7 +74,7 @@ macro_rules! bmap ) => {{ - let mut _map = $crate::bmap::BTreeMap::new(); + let mut _map = $crate::collection::BTreeMap::new(); $( let _ = _map.insert( $key , $value ); )* @@ -111,8 +115,8 @@ macro_rules! bmap /// # Parameters /// /// - `$( $key:expr => $value:expr ),* $( , )?`: A comma-separated list of key-value pairs to insert into the `BTreeMap`. -/// Each key and value can be of any type that implements the `Into< K >` and `Into< V >` traits, where `K` and `V` are the -/// types stored in the `BTreeMap` as keys and values, respectively. +/// Each key and value can be of any type that implements the `Into< K >` and `Into< V >` traits, where `K` and `V` are the +/// types stored in the `BTreeMap` as keys and values, respectively. /// /// # Returns /// @@ -163,7 +167,7 @@ macro_rules! into_bmap ) => {{ - let mut _map = $crate::bmap::BTreeMap::new(); + let mut _map = $crate::collection::BTreeMap::new(); $( let _ = _map.insert( Into::into( $key ), Into::into( $value ) ); )* diff --git a/module/core/collection_tools/src/collection/bset.rs b/module/core/collection_tools/src/collection/btree_set.rs similarity index 89% rename from module/core/collection_tools/src/collection/bset.rs rename to module/core/collection_tools/src/collection/btree_set.rs index c0c6d249ed..d7b22ababc 100644 --- a/module/core/collection_tools/src/collection/bset.rs +++ b/module/core/collection_tools/src/collection/btree_set.rs @@ -1,5 +1,9 @@ +#[ allow( unused_imports, clippy::wildcard_imports ) ] +use super::*; + #[ doc( inline ) ] #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use alloc::collections::btree_set::*; /// Creates a `BTreeSet` from a list of elements. @@ -26,8 +30,8 @@ pub use alloc::collections::btree_set::*; /// # Parameters /// /// - `$( $key:expr ),* $( , )?`: A comma-separated list of elements to insert into the `BTreeSet`. -/// Each element can be of any type that implements the `Into` trait, where `T` is the -/// type stored in the `BTreeSet`. +/// Each element can be of any type that implements the `Into` trait, where `T` is the +/// type stored in the `BTreeSet`. /// /// # Returns /// @@ -56,7 +60,7 @@ macro_rules! bset ) => {{ - let mut _set = $crate::bset::BTreeSet::new(); + let mut _set = $crate::collection::BTreeSet::new(); $( _set.insert( $key ); )* @@ -97,8 +101,8 @@ macro_rules! bset /// # Parameters /// /// - `$( $key:expr ),* $( , )?`: A comma-separated list of elements to insert into the `BTreeSet`. -/// Each element can be of any type that implements the `Into` trait, where `T` is the -/// type stored in the `BTreeSet`. +/// Each element can be of any type that implements the `Into` trait, where `T` is the +/// type stored in the `BTreeSet`. /// /// # Returns /// @@ -149,7 +153,7 @@ macro_rules! into_bset ) => {{ - let mut _set = $crate::bset::BTreeSet::new(); + let mut _set = $crate::collection::BTreeSet::new(); $( _set.insert( Into::into( $key ) ); )* diff --git a/module/core/collection_tools/src/collection/hmap.rs b/module/core/collection_tools/src/collection/hash_map.rs similarity index 87% rename from module/core/collection_tools/src/collection/hmap.rs rename to module/core/collection_tools/src/collection/hash_map.rs index eceac4ee9b..2b2a8226a6 100644 --- a/module/core/collection_tools/src/collection/hmap.rs +++ b/module/core/collection_tools/src/collection/hash_map.rs @@ -1,10 +1,16 @@ -#[ cfg( feature = "use_alloc" ) ] +#[ allow( unused_imports ) ] +use super::*; + +// xxx : qqq : wrong +#[ cfg( all( feature = "no_std", feature = "use_alloc" ) ) ] #[ doc( inline ) ] #[ allow( unused_imports ) ] pub use crate::dependency::hashbrown::hash_map::*; + #[ cfg( not( feature = "no_std" ) ) ] #[ doc( inline ) ] #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use std::collections::hash_map::*; /// Creates a `HashMap` from a list of key-value pairs. @@ -14,7 +20,7 @@ pub use std::collections::hash_map::*; /// # Origin /// /// This collection can be reexported from different crates: -/// - from `std`, if `no_std` flag if off +/// - from `std`, if `use_std` is on ( `no_std` flag if off ) /// - from `hashbrown`, if `use_alloc` flag if on /// /// # Syntax @@ -36,8 +42,8 @@ pub use std::collections::hash_map::*; /// # Parameters /// /// - `$( $key:expr => $value:expr ),* $( , )?`: A comma-separated list of key-value pairs to insert into the `HashMap`. -/// Each key and value can be of any type that implements the `Into` and `Into` traits, where `K` and `V` are the -/// types stored in the `HashMap` as keys and values, respectively. +/// Each key and value can be of any type that implements the `Into` and `Into` traits, where `K` and `V` are the +/// types stored in the `HashMap` as keys and values, respectively. /// /// # Returns /// @@ -77,7 +83,7 @@ macro_rules! hmap => {{ let _cap = count!( @count $( $key ),* ); - let mut _map = $crate::hmap::HashMap::with_capacity( _cap ); + let mut _map = $crate::collection::HashMap::with_capacity( _cap ); $( let _ = _map.insert( $key, $value ); )* @@ -98,7 +104,7 @@ macro_rules! hmap /// # Origin /// /// This collection can be reexported from different crates: -/// - from `std`, if `no_std` flag if off +/// - from `std`, if `use_std` is on ( `no_std` flag if off ) /// - from `hashbrown`, if `use_alloc` flag if on /// /// # Syntax @@ -120,8 +126,8 @@ macro_rules! hmap /// # Parameters /// /// - `$( $key:expr => $value:expr ),* $( , )?`: A comma-separated list of key-value pairs to insert into the `HashMap`. -/// Each key and value can be of any type that implements the `Into` and `Into` traits, where `K` and `V` are the -/// types stored in the `HashMap` as keys and values, respectively. +/// Each key and value can be of any type that implements the `Into` and `Into` traits, where `K` and `V` are the +/// types stored in the `HashMap` as keys and values, respectively. /// /// # Returns /// @@ -172,7 +178,7 @@ macro_rules! into_hmap => {{ let _cap = count!( @count $( $key ),* ); - let mut _map = $crate::hmap::HashMap::with_capacity( _cap ); + let mut _map = $crate::collection::HashMap::with_capacity( _cap ); $( let _ = _map.insert( Into::into( $key ), Into::into( $value ) ); )* diff --git a/module/core/collection_tools/src/collection/hset.rs b/module/core/collection_tools/src/collection/hash_set.rs similarity index 89% rename from module/core/collection_tools/src/collection/hset.rs rename to module/core/collection_tools/src/collection/hash_set.rs index b9b2d682da..f2a73c5faf 100644 --- a/module/core/collection_tools/src/collection/hset.rs +++ b/module/core/collection_tools/src/collection/hash_set.rs @@ -1,10 +1,15 @@ +#[ allow( unused_imports ) ] +use super::*; + #[ cfg( feature = "use_alloc" ) ] #[ doc( inline ) ] #[ allow( unused_imports ) ] pub use crate::dependency::hashbrown::hash_set::*; + #[ cfg( not( feature = "no_std" ) ) ] #[ doc( inline ) ] #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use std::collections::hash_set::*; /// Creates a `HashSet` from a list of elements. @@ -14,7 +19,7 @@ pub use std::collections::hash_set::*; /// # Origin /// /// This collection can be reexported from different crates: -/// - from `std`, if `no_std` flag if off +/// - from `std`, if `use_std` is on ( `no_std` flag if off ) /// - from `hashbrown`, if `use_alloc` flag if on /// /// # Syntax @@ -36,8 +41,8 @@ pub use std::collections::hash_set::*; /// # Parameters /// /// - `$( $key:expr ),* $( , )?`: A comma-separated list of elements to insert into the `HashSet`. -/// Each element can be of any type that implements the `Into< T >` trait, where `T` is the -/// type stored in the `HashSet`. +/// Each element can be of any type that implements the `Into< T >` trait, where `T` is the +/// type stored in the `HashSet`. /// /// # Returns /// @@ -77,7 +82,7 @@ macro_rules! hset => {{ let _cap = count!( @count $( $key ),* ); - let mut _set = $crate::hset::HashSet::with_capacity( _cap ); + let mut _set = $crate::collection::HashSet::with_capacity( _cap ); $( let _ = _set.insert( $key ); )* @@ -96,9 +101,9 @@ macro_rules! hset /// type `T` used in the `HashSet`. Also, this means that sometimes you must specify the type of collection's items. /// /// # Origin -/// +/// /// This collection can be reexported from different crates: -/// - from `std`, if `no_std` flag if off +/// - from `std`, if `use_std` is on ( `no_std` flag if off ) /// - from `hashbrown`, if `use_alloc` flag if on /// /// # Syntax @@ -120,8 +125,8 @@ macro_rules! hset /// # Parameters /// /// - `$( $key:expr ),* $( , )?`: A comma-separated list of elements to insert into the `HashSet`. -/// Each element can be of any type that implements the `Into< T >` trait, where `T` is the -/// type stored in the `HashSet`. +/// Each element can be of any type that implements the `Into< T >` trait, where `T` is the +/// type stored in the `HashSet`. /// /// # Returns /// @@ -173,7 +178,7 @@ macro_rules! into_hset => {{ let _cap = count!( @count $( $key ),* ); - let mut _set = $crate::hset::HashSet::with_capacity( _cap ); + let mut _set = $crate::collection::HashSet::with_capacity( _cap ); $( let _ = _set.insert( Into::into( $key ) ); )* diff --git a/module/core/collection_tools/src/collection/llist.rs b/module/core/collection_tools/src/collection/linked_list.rs similarity index 91% rename from module/core/collection_tools/src/collection/llist.rs rename to module/core/collection_tools/src/collection/linked_list.rs index e6c8ddbe68..7fbaba79fa 100644 --- a/module/core/collection_tools/src/collection/llist.rs +++ b/module/core/collection_tools/src/collection/linked_list.rs @@ -1,5 +1,9 @@ +#[ allow( unused_imports, clippy::wildcard_imports ) ] +use super::*; + #[ doc( inline ) ] #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use alloc::collections::linked_list::*; /// Creates a `LinkedList` from a llist of elements. @@ -29,8 +33,8 @@ pub use alloc::collections::linked_list::*; /// # Parameters /// /// - `$( $key:expr ),* $( , )?`: A comma-separated llist of elements to insert into the `LinkedList`. -/// Each element can be of any type that implements the `Into` trait, where `T` is the -/// type stored in the `LinkedList`. +/// Each element can be of any type that implements the `Into` trait, where `T` is the +/// type stored in the `LinkedList`. /// /// # Returns /// @@ -70,7 +74,7 @@ macro_rules! llist {{ // "The LinkedList allows pushing and popping elements at either end in constant time." // So no `with_capacity` - let mut _lst = $crate::llist::LinkedList::new(); + let mut _lst = $crate::collection::LinkedList::new(); $( _lst.push_back( $key ); )* @@ -111,8 +115,8 @@ macro_rules! llist /// # Parameters /// /// - `$( $key:expr ),* $( , )?`: A comma-separated llist of elements to insert into the `LinkedList`. -/// Each element can be of any type that implements the `Into` trait, where `T` is the -/// type stored in the `LinkedList`. +/// Each element can be of any type that implements the `Into` trait, where `T` is the +/// type stored in the `LinkedList`. /// /// # Returns /// @@ -164,7 +168,7 @@ macro_rules! into_llist {{ // "The LinkedList allows pushing and popping elements at either end in constant time." // So no `with_capacity` - let mut _lst = $crate::llist::LinkedList::new(); + let mut _lst = $crate::collection::LinkedList::new(); $( _lst.push_back( Into::into( $key ) ); )* diff --git a/module/core/collection_tools/src/collection/mod.rs b/module/core/collection_tools/src/collection/mod.rs new file mode 100644 index 0000000000..22e59e8aae --- /dev/null +++ b/module/core/collection_tools/src/collection/mod.rs @@ -0,0 +1,173 @@ +/// Not meant to be called directly. +#[ doc( hidden ) ] +#[ macro_export( local_inner_macros ) ] +macro_rules! count +{ + ( @single $( $x : tt )* ) => ( () ); + + ( + @count $( $rest : expr ),* + ) + => + ( + < [ () ] >::len( &[ $( count!( @single $rest ) ),* ] ) + ); +} + +#[ cfg( feature = "enabled" ) ] +#[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] +extern crate alloc; + +/// [`std::collections::BTreeMap`] macros +pub mod btree_map; +/// [`std::collections::BTreeSet`] macros +pub mod btree_set; +/// [`std::collections::BinaryHeap`] macros +pub mod binary_heap; +/// [`std::collections::HashMap`] macros +pub mod hash_map; +/// [`std::collections::HashSet`] macros +pub mod hash_set; +/// [`std::collections::LinkedList`] macros +pub mod linked_list; +/// [Vec] macros +pub mod vector; +/// [`std::collections::VecDeque`] macros +pub mod vec_deque; + +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +#[ cfg( feature = "enabled" ) ] +#[ allow( clippy::pub_use ) ] +pub use own::*; + +/// Own namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod own +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super:: + { + btree_map, + btree_set, + binary_heap, + hash_map, + hash_set, + linked_list, + vector, + vec_deque, + }; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use orphan::*; + +} + +/// Parented namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod orphan +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use exposed::*; +} + +/// Exposed namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod exposed +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use prelude::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super::super::collection; + + #[ doc( inline ) ] + #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] + #[ cfg( feature = "collection_constructors" ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use crate:: + { + vec as dlist, + deque, + llist, + hset, + hmap, + bmap, + bset, + }; + + #[ doc( inline ) ] + #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] + #[ cfg( feature = "collection_into_constructors" ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use crate:: + { + into_vec, + into_vec as into_dlist, + into_vecd, + into_llist, + into_hset, + into_hmap, + into_bmap, + into_bset, + }; + + // #[ cfg( feature = "reexports" ) ] + #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use + { + btree_map::BTreeMap, + btree_set::BTreeSet, + binary_heap::BinaryHeap, + hash_map::HashMap, + hash_set::HashSet, + linked_list::LinkedList, + vector::Vec, + vec_deque::VecDeque, + }; + + // #[ cfg( feature = "reexports" ) ] + #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use + { + LinkedList as Llist, + Vec as Dlist, + VecDeque as Deque, + HashMap as Map, + HashMap as Hmap, + HashSet as Set, + HashSet as Hset, + BTreeMap as Bmap, + BTreeSet as Bset, + }; + + // qqq : cover by tests presence of all containers immidiately in collection_tools::* and in collection_tools::exposed::* + +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; +} diff --git a/module/core/collection_tools/src/collection/deque.rs b/module/core/collection_tools/src/collection/vec_deque.rs similarity index 91% rename from module/core/collection_tools/src/collection/deque.rs rename to module/core/collection_tools/src/collection/vec_deque.rs index 66b106c6ec..218f64e7ed 100644 --- a/module/core/collection_tools/src/collection/deque.rs +++ b/module/core/collection_tools/src/collection/vec_deque.rs @@ -1,5 +1,9 @@ +#[ allow( unused_imports, clippy::wildcard_imports ) ] +use super::*; + #[ doc( inline ) ] #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use alloc::collections::vec_deque::*; /// Creates a `VecDeque` from a list of elements. @@ -35,8 +39,8 @@ pub use alloc::collections::vec_deque::*; /// # Parameters /// /// - `$( $key:expr ),* $( , )?`: A comma-separated list of elements to insert into the `VecDeque`. -/// Each element can be of any type that implements the `Into< T >` trait, where `T` is the -/// type stored in the `VecDeque`. +/// Each element can be of any type that implements the `Into< T >` trait, where `T` is the +/// type stored in the `VecDeque`. /// /// # Returns /// @@ -75,7 +79,7 @@ macro_rules! deque => {{ let _cap = count!( @count $( $key ),* ); - let mut _vecd = $crate::deque::VecDeque::with_capacity( _cap ); + let mut _vecd = $crate::collection::VecDeque::with_capacity( _cap ); $( _vecd.push_back( $key ); )* @@ -116,8 +120,8 @@ macro_rules! deque /// # Parameters /// /// - `$( $key:expr ),* $( , )?`: A comma-separated list of elements to insert into the `VecDeque`. -/// Each element can be of any type that implements the `Into< T >` trait, where `T` is the -/// type stored in the `VecDeque`. +/// Each element can be of any type that implements the `Into< T >` trait, where `T` is the +/// type stored in the `VecDeque`. /// /// # Returns /// @@ -168,7 +172,7 @@ macro_rules! into_vecd => {{ let _cap = count!( @count $( $key ),* ); - let mut _vecd = $crate::deque::VecDeque::with_capacity( _cap ); + let mut _vecd = $crate::collection::VecDeque::with_capacity( _cap ); $( _vecd.push_back( Into::into( $key ) ); )* diff --git a/module/core/collection_tools/src/collection/vec.rs b/module/core/collection_tools/src/collection/vector.rs similarity index 89% rename from module/core/collection_tools/src/collection/vec.rs rename to module/core/collection_tools/src/collection/vector.rs index 2c19db388f..568642d0c4 100644 --- a/module/core/collection_tools/src/collection/vec.rs +++ b/module/core/collection_tools/src/collection/vector.rs @@ -1,8 +1,14 @@ +#[ allow( unused_imports, clippy::wildcard_imports ) ] +use super::*; + #[ doc( inline ) ] #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use alloc::vec::*; + #[ doc( inline ) ] #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use core::slice::{ Iter, IterMut }; /// Creates a `Vec` from a list of elements. @@ -32,8 +38,8 @@ pub use core::slice::{ Iter, IterMut }; /// # Parameters /// /// - `$( $key : expr ),* $( , )?`: A comma-separated list of elements to insert into the `Vec`. -/// Each element can be of any type that implements the `Into` trait, where `T` is the -/// type stored in the `Vec`. +/// Each element can be of any type that implements the `Into` trait, where `T` is the +/// type stored in the `Vec`. /// /// # Returns /// @@ -73,7 +79,7 @@ macro_rules! vec => {{ let _cap = count!( @count $( $key ),* ); - let mut _vec = $crate::vec::Vec::with_capacity( _cap ); + let mut _vec = $crate::collection::Vec::with_capacity( _cap ); $( _vec.push( $key ); )* @@ -114,8 +120,8 @@ macro_rules! vec /// # Parameters /// /// - `$( $key : expr ),* $( , )?`: A comma-separated list of elements to insert into the `Vec`. -/// Each element can be of any type that implements the `Into` trait, where `T` is the -/// type stored in the `Vec`. +/// Each element can be of any type that implements the `Into` trait, where `T` is the +/// type stored in the `Vec`. /// /// # Returns /// @@ -167,7 +173,7 @@ macro_rules! into_vec => {{ let _cap = count!( @count $( $key ),* ); - let mut _vec = $crate::vec::Vec::with_capacity( _cap ); + let mut _vec = $crate::collection::Vec::with_capacity( _cap ); $( _vec.push( Into::into( $key ) ); )* diff --git a/module/core/collection_tools/src/lib.rs b/module/core/collection_tools/src/lib.rs index e447f16f85..18b8e84037 100644 --- a/module/core/collection_tools/src/lib.rs +++ b/module/core/collection_tools/src/lib.rs @@ -3,18 +3,19 @@ #![ 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/collection_tools/latest/collection_tools/" ) ] #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] - -#[ cfg( feature = "enabled" ) ] -#[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] -extern crate alloc; +#![ allow( clippy::mod_module_files ) ] +// #[ cfg( feature = "enabled" ) ] +// #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] +// extern crate alloc; /// Module containing all collection macros #[ cfg( feature = "enabled" ) ] -#[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] -mod collection; -#[ cfg( feature = "enabled" ) ] -#[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] -pub use collection::*; +#[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] +pub mod collection; + +// #[ cfg( feature = "enabled" ) ] +// #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] +// pub use collection::*; /// Namespace with dependencies. #[ cfg( feature = "enabled" ) ] @@ -29,6 +30,7 @@ pub mod dependency #[ doc( inline ) ] #[ allow( unused_imports ) ] #[ cfg( feature = "enabled" ) ] +#[ allow( clippy::pub_use ) ] pub use own::*; /// Own namespace of the module. @@ -36,10 +38,15 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { - use super::*; + // use super::*; #[ doc( inline ) ] - pub use orphan::*; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super::orphan::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super::collection::own::*; } @@ -48,9 +55,16 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use exposed::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use collection::orphan::*; + } /// Exposed namespace of the module. @@ -58,79 +72,37 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use prelude::*; #[ doc( inline ) ] - #[ cfg( any( feature = "use_alloc", all( feature = "collection_constructors", not( feature = "no_std" ) ) ) ) ] - pub use crate:: - { - vec as dlist, - deque, - llist, - hset, - hmap, - bmap, - bset, - }; - - #[ doc( inline ) ] - #[ cfg( any( feature = "use_alloc", all( feature = "collection_into_constructors", not( feature = "no_std" ) ) ) ) ] - pub use crate:: - { - into_vec, - into_vec as into_dlist, - into_vecd, - into_llist, - into_hset, - into_hmap, - into_bmap, - into_bset, - }; - - // #[ cfg( feature = "reexports" ) ] - #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use crate:: - { - bmap::BTreeMap, - bset::BTreeSet, - heap::BinaryHeap, - hmap::HashMap, - hset::HashSet, - llist::LinkedList, - vec::Vec, - deque::VecDeque, - }; - - // #[ cfg( feature = "reexports" ) ] - #[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use - { - LinkedList as Llist, - Vec as Dlist, - VecDeque as Deque, - HashMap as Map, - HashMap as Hmap, - HashSet as Set, - HashSet as Hset, - BTreeMap as Bmap, - BTreeSet as Bset, - }; - - // qqq : cover by tests presence of all containers immidiately in collection_tools::* and in collection_tools::exposed::* + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use collection::exposed::*; } /// Prelude to use essentials: `use my_module::prelude::*`. #[ cfg( feature = "enabled" ) ] +#[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] #[ allow( unused_imports ) ] pub mod prelude { - use super::*; + use super::collection; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use collection::prelude::*; + } + +// pub use own::collection as xxx; +// pub use hmap as xxx; +// pub use own::HashMap as xxx; +// pub fn x() +// { +// let x : HashMap< usize, usize > = hmap!{}; +// } diff --git a/module/core/collection_tools/tests/inc/bmap.rs b/module/core/collection_tools/tests/inc/bmap.rs index af3d54dae5..113e69f810 100644 --- a/module/core/collection_tools/tests/inc/bmap.rs +++ b/module/core/collection_tools/tests/inc/bmap.rs @@ -68,7 +68,7 @@ fn iters() impl IntoIterator for MyContainer { type Item = ( i32, i32 ); - type IntoIter = the_module::bmap::IntoIter< i32, i32 >; + type IntoIter = the_module::btree_map::IntoIter< i32, i32 >; fn into_iter( self ) -> Self::IntoIter { @@ -79,7 +79,7 @@ fn iters() impl< 'a > IntoIterator for &'a MyContainer { type Item = ( &'a i32, &'a i32 ); - type IntoIter = the_module::bmap::Iter< 'a, i32, i32 >; + type IntoIter = the_module::btree_map::Iter< 'a, i32, i32 >; fn into_iter( self ) -> Self::IntoIter { diff --git a/module/core/collection_tools/tests/inc/bset.rs b/module/core/collection_tools/tests/inc/bset.rs index 2a427d0a26..9fb625bf30 100644 --- a/module/core/collection_tools/tests/inc/bset.rs +++ b/module/core/collection_tools/tests/inc/bset.rs @@ -67,7 +67,7 @@ fn iters() impl IntoIterator for MyContainer { type Item = i32; - type IntoIter = the_module::bset::IntoIter< i32 >; + type IntoIter = the_module::btree_set::IntoIter< i32 >; fn into_iter( self ) -> Self::IntoIter { @@ -78,7 +78,7 @@ fn iters() impl< 'a > IntoIterator for &'a MyContainer { type Item = &'a i32; - type IntoIter = the_module::bset::Iter< 'a, i32 >; + type IntoIter = the_module::btree_set::Iter< 'a, i32 >; fn into_iter( self ) -> Self::IntoIter { diff --git a/module/core/collection_tools/tests/inc/deque.rs b/module/core/collection_tools/tests/inc/deque.rs index 98ab6498bd..d58c72d8cc 100644 --- a/module/core/collection_tools/tests/inc/deque.rs +++ b/module/core/collection_tools/tests/inc/deque.rs @@ -66,7 +66,7 @@ fn iters() impl IntoIterator for MyContainer { type Item = i32; - type IntoIter = the_module::deque::IntoIter< i32 >; + type IntoIter = the_module::vec_deque::IntoIter< i32 >; fn into_iter( self ) -> Self::IntoIter { @@ -77,7 +77,7 @@ fn iters() impl< 'a > IntoIterator for &'a MyContainer { type Item = &'a i32; - type IntoIter = the_module::deque::Iter< 'a, i32 >; + type IntoIter = the_module::vec_deque::Iter< 'a, i32 >; fn into_iter( self ) -> Self::IntoIter { @@ -88,7 +88,7 @@ fn iters() impl< 'a > IntoIterator for &'a mut MyContainer { type Item = &'a mut i32; - type IntoIter = the_module::deque::IterMut< 'a, i32 >; + type IntoIter = the_module::vec_deque::IterMut< 'a, i32 >; fn into_iter( self ) -> Self::IntoIter { diff --git a/module/core/collection_tools/tests/inc/heap.rs b/module/core/collection_tools/tests/inc/heap.rs index a342548cfc..ad251e0b39 100644 --- a/module/core/collection_tools/tests/inc/heap.rs +++ b/module/core/collection_tools/tests/inc/heap.rs @@ -62,7 +62,7 @@ fn iters() impl IntoIterator for MyContainer { type Item = i32; - type IntoIter = the_module::heap::IntoIter< i32 >; + type IntoIter = the_module::binary_heap::IntoIter< i32 >; fn into_iter( self ) -> Self::IntoIter { @@ -73,7 +73,7 @@ fn iters() impl< 'a > IntoIterator for &'a MyContainer { type Item = &'a i32; - type IntoIter = the_module::heap::Iter< 'a, i32 >; + type IntoIter = the_module::binary_heap::Iter< 'a, i32 >; fn into_iter( self ) -> Self::IntoIter { diff --git a/module/core/collection_tools/tests/inc/hmap.rs b/module/core/collection_tools/tests/inc/hmap.rs index 629c7155a6..042b4c8653 100644 --- a/module/core/collection_tools/tests/inc/hmap.rs +++ b/module/core/collection_tools/tests/inc/hmap.rs @@ -77,7 +77,7 @@ fn iters() impl IntoIterator for MyContainer { type Item = ( i32, i32 ); - type IntoIter = the_module::hmap::IntoIter< i32, i32 >; + type IntoIter = the_module::hash_map::IntoIter< i32, i32 >; fn into_iter( self ) -> Self::IntoIter { @@ -88,7 +88,7 @@ fn iters() impl< 'a > IntoIterator for &'a MyContainer { type Item = ( &'a i32, &'a i32 ); - type IntoIter = the_module::hmap::Iter< 'a, i32, i32 >; + type IntoIter = the_module::hash_map::Iter< 'a, i32, i32 >; fn into_iter( self ) -> Self::IntoIter { @@ -99,7 +99,7 @@ fn iters() impl< 'a > IntoIterator for &'a mut MyContainer { type Item = ( &'a i32, &'a mut i32 ); - type IntoIter = the_module::hmap::IterMut< 'a, i32, i32 >; + type IntoIter = the_module::hash_map::IterMut< 'a, i32, i32 >; fn into_iter( self ) -> Self::IntoIter { diff --git a/module/core/collection_tools/tests/inc/hset.rs b/module/core/collection_tools/tests/inc/hset.rs index c844836874..b3af31cb2d 100644 --- a/module/core/collection_tools/tests/inc/hset.rs +++ b/module/core/collection_tools/tests/inc/hset.rs @@ -74,7 +74,7 @@ fn iters() impl IntoIterator for MyContainer { type Item = i32; - type IntoIter = the_module::hset::IntoIter< i32 >; + type IntoIter = the_module::hash_set::IntoIter< i32 >; fn into_iter( self ) -> Self::IntoIter { @@ -85,7 +85,7 @@ fn iters() impl< 'a > IntoIterator for &'a MyContainer { type Item = &'a i32; - type IntoIter = the_module::hset::Iter< 'a, i32 >; + type IntoIter = the_module::hash_set::Iter< 'a, i32 >; fn into_iter( self ) -> Self::IntoIter { diff --git a/module/core/collection_tools/tests/inc/llist.rs b/module/core/collection_tools/tests/inc/llist.rs index 68620e2a69..3a861b0ec2 100644 --- a/module/core/collection_tools/tests/inc/llist.rs +++ b/module/core/collection_tools/tests/inc/llist.rs @@ -67,7 +67,7 @@ fn iters() impl IntoIterator for MyContainer { type Item = i32; - type IntoIter = the_module::llist::IntoIter< i32 >; + type IntoIter = the_module::linked_list::IntoIter< i32 >; fn into_iter( self ) -> Self::IntoIter { @@ -78,7 +78,7 @@ fn iters() impl< 'a > IntoIterator for &'a MyContainer { type Item = &'a i32; - type IntoIter = the_module::llist::Iter< 'a, i32 >; + type IntoIter = the_module::linked_list::Iter< 'a, i32 >; fn into_iter( self ) -> Self::IntoIter { @@ -89,7 +89,7 @@ fn iters() impl< 'a > IntoIterator for &'a mut MyContainer { type Item = &'a mut i32; - type IntoIter = the_module::llist::IterMut< 'a, i32 >; + type IntoIter = the_module::linked_list::IterMut< 'a, i32 >; fn into_iter( self ) -> Self::IntoIter { diff --git a/module/core/collection_tools/tests/inc/mod.rs b/module/core/collection_tools/tests/inc/mod.rs index ddd10e261d..86855a9d84 100644 --- a/module/core/collection_tools/tests/inc/mod.rs +++ b/module/core/collection_tools/tests/inc/mod.rs @@ -9,6 +9,7 @@ mod llist; mod vec; mod deque; +mod namespace_test; mod components; // qqq : make subdirectory for each container -- done diff --git a/module/core/collection_tools/tests/inc/namespace_test.rs b/module/core/collection_tools/tests/inc/namespace_test.rs new file mode 100644 index 0000000000..841ecac64f --- /dev/null +++ b/module/core/collection_tools/tests/inc/namespace_test.rs @@ -0,0 +1,12 @@ +use super::*; + +#[ test ] +fn exposed_main_namespace() +{ + + let _v : Vec< u32 > = the_module::collection::Vec::new(); + let _v : Vec< u32 > = the_module::exposed::collection::Vec::new(); + use the_module::exposed::*; + let _v : Vec< u32 > = collection::Vec::new(); + +} \ No newline at end of file diff --git a/module/core/collection_tools/tests/inc/vec.rs b/module/core/collection_tools/tests/inc/vec.rs index c1a5f66804..5bf78631ba 100644 --- a/module/core/collection_tools/tests/inc/vec.rs +++ b/module/core/collection_tools/tests/inc/vec.rs @@ -1,7 +1,7 @@ use super::*; #[ test ] -#[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] +#[ cfg( any( feature = "use_alloc", not( feature = "no_std" ) ) ) ] fn reexport() { @@ -86,7 +86,7 @@ fn iters() impl IntoIterator for MyContainer { type Item = i32; - type IntoIter = the_module::vec::IntoIter< i32 >; + type IntoIter = the_module::vector::IntoIter< i32 >; // qqq : should work -- works fn into_iter( self ) -> Self::IntoIter @@ -98,7 +98,7 @@ fn iters() impl< 'a > IntoIterator for &'a MyContainer { type Item = &'a i32; - type IntoIter = the_module::vec::Iter< 'a, i32 >; + type IntoIter = the_module::vector::Iter< 'a, i32 >; fn into_iter( self ) -> Self::IntoIter { @@ -109,7 +109,7 @@ fn iters() impl< 'a > IntoIterator for &'a mut MyContainer { type Item = &'a mut i32; - type IntoIter = the_module::vec::IterMut< 'a, i32 >; + type IntoIter = the_module::vector::IterMut< 'a, i32 >; fn into_iter( self ) -> Self::IntoIter { diff --git a/module/core/collection_tools/tests/tests.rs b/module/core/collection_tools/tests/tests.rs index a36c5debec..ecc936c445 100644 --- a/module/core/collection_tools/tests/tests.rs +++ b/module/core/collection_tools/tests/tests.rs @@ -1,4 +1,4 @@ -// usual tests +#![ allow( unused_imports ) ] #[ path="../../../../module/step/meta/src/module/aggregating.rs" ] mod aggregating; diff --git a/module/core/data_type/Readme.md b/module/core/data_type/Readme.md index 62c1031498..ddadd7fb57 100644 --- a/module/core/data_type/Readme.md +++ b/module/core/data_type/Readme.md @@ -1,6 +1,6 @@ -# Module :: data_type +# Module :: `data_type` [![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_data_type_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_data_type_push.yml) [![docs.rs](https://img.shields.io/docsrs/data_type?color=e3e8f0&logo=docs.rs)](https://docs.rs/data_type) [![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%2Fdata_type%2Fexamples%2Fdata_type_trivial.rs,RUN_POSTFIX=--example%20data_type_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) @@ -30,7 +30,7 @@ Macro [types](https://docs.rs/type_constructor/latest/type_constructor/types/mac ### Basic Use Case :: make - variadic constructor -Implement traits [From_0], [From1] up to MakeN to provide the interface to construct your structure with a different set of arguments. +Implement traits [`From_0`], [From1] up to `MakeN` to provide the interface to construct your structure with a different set of arguments. In this example structure, Struct1 could be constructed either without arguments, with a single argument, or with two arguments. - Constructor without arguments fills fields with zero. - Constructor with a single argument sets both fields to the value of the argument. diff --git a/module/core/data_type/src/dt.rs b/module/core/data_type/src/dt.rs index 69c9e80518..91b3babd3d 100644 --- a/module/core/data_type/src/dt.rs +++ b/module/core/data_type/src/dt.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } @@ -11,6 +11,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -20,6 +21,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -29,6 +31,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] diff --git a/module/core/data_type/src/lib.rs b/module/core/data_type/src/lib.rs index 7cdff4fae2..b645eb9a71 100644 --- a/module/core/data_type/src/lib.rs +++ b/module/core/data_type/src/lib.rs @@ -33,6 +33,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -45,6 +46,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -54,6 +56,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] diff --git a/module/core/derive_tools/Readme.md b/module/core/derive_tools/Readme.md index 746b6e4ec7..f5e6fddf2e 100644 --- a/module/core/derive_tools/Readme.md +++ b/module/core/derive_tools/Readme.md @@ -1,4 +1,4 @@ -# Module :: derive_tools +# Module :: `derive_tools` diff --git a/module/core/derive_tools/src/lib.rs b/module/core/derive_tools/src/lib.rs index 62468ed1dc..fe3c51ebbf 100644 --- a/module/core/derive_tools/src/lib.rs +++ b/module/core/derive_tools/src/lib.rs @@ -31,7 +31,7 @@ // #[ cfg( feature = "enabled" ) ] // pub mod wtools; -#[ cfg( all( feature = "derive_more" ) ) ] +#[ cfg( feature = "derive_more" ) ] #[ allow( unused_imports ) ] mod derive_more { @@ -110,6 +110,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -123,6 +124,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -133,11 +135,12 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use prelude::*; - #[ cfg( all( feature = "derive_more" ) ) ] + #[ cfg( feature = "derive_more" ) ] #[ doc( inline ) ] pub use super::derive_more::*; diff --git a/module/core/derive_tools_meta/Readme.md b/module/core/derive_tools_meta/Readme.md index 53f7fba9f0..91790856f2 100644 --- a/module/core/derive_tools_meta/Readme.md +++ b/module/core/derive_tools_meta/Readme.md @@ -1,5 +1,5 @@ -# Module :: derive_tools_meta +# Module :: `derive_tools_meta` [![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_derive_tools_meta_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_derive_tools_meta_push.yml) [![docs.rs](https://img.shields.io/docsrs/derive_tools_meta?color=e3e8f0&logo=docs.rs)](https://docs.rs/derive_tools_meta) [![discord](https://img.shields.io/discord/872391416519737405?color=eee&logo=discord&logoColor=eee&label=ask)](https://discord.gg/m3YfbXpUUY) diff --git a/module/core/derive_tools_meta/src/derive/as_ref.rs b/module/core/derive_tools_meta/src/derive/as_ref.rs index dba4eacacf..7a02d29b9b 100644 --- a/module/core/derive_tools_meta/src/derive/as_ref.rs +++ b/module/core/derive_tools_meta/src/derive/as_ref.rs @@ -1,4 +1,5 @@ +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools::{ attr, diag, item_struct, Result }; diff --git a/module/core/derive_tools_meta/src/derive/deref.rs b/module/core/derive_tools_meta/src/derive/deref.rs index ac2217c1c8..ad5489bd03 100644 --- a/module/core/derive_tools_meta/src/derive/deref.rs +++ b/module/core/derive_tools_meta/src/derive/deref.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools::{ attr, diag, generic_params, Result, struct_like::StructLike }; @@ -11,7 +12,7 @@ pub fn deref( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStr let item_name = &parsed.ident(); let ( _generics_with_defaults, generics_impl, generics_ty, generics_where ) - = generic_params::decompose( &parsed.generics() ); + = generic_params::decompose( parsed.generics() ); let result = match parsed { @@ -84,6 +85,7 @@ pub fn deref( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStr /// } /// ``` /// +#[ allow( clippy::unnecessary_wraps ) ] fn generate_unit ( item_name : &syn::Ident, @@ -322,9 +324,9 @@ fn generate_enum None => return generate_unit ( item_name, - &generics_impl, - &generics_ty, - &generics_where, + generics_impl, + generics_ty, + generics_where, ), }; @@ -343,18 +345,18 @@ fn generate_enum generate_unit ( item_name, - &generics_impl, - &generics_ty, - &generics_where, + generics_impl, + generics_ty, + generics_where, ), syn::Fields::Unnamed( ref item ) => generate_enum_tuple_variants ( item_name, - &generics_impl, - &generics_ty, - &generics_where, + generics_impl, + generics_ty, + generics_where, &idents, item, ), @@ -363,9 +365,9 @@ fn generate_enum generate_enum_named_variants ( item_name, - &generics_impl, - &generics_ty, - &generics_where, + generics_impl, + generics_ty, + generics_where, &idents, item, ), diff --git a/module/core/derive_tools_meta/src/derive/from.rs b/module/core/derive_tools_meta/src/derive/from.rs index 585df90183..59a7462435 100644 --- a/module/core/derive_tools_meta/src/derive/from.rs +++ b/module/core/derive_tools_meta/src/derive/from.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools:: { @@ -10,8 +11,10 @@ use macro_tools:: }; mod field_attributes; +#[ allow( clippy::wildcard_imports ) ] use field_attributes::*; mod item_attributes; +#[ allow( clippy::wildcard_imports ) ] use item_attributes::*; // @@ -27,15 +30,15 @@ pub fn from( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStre let item_name = &parsed.ident(); let ( _generics_with_defaults, generics_impl, generics_ty, generics_where ) - = generic_params::decompose( &parsed.generics() ); + = generic_params::decompose( parsed.generics() ); let result = match parsed { StructLike::Unit( ref item ) | StructLike::Struct( ref item ) => { - let mut field_types = item_struct::field_types( &item ); - let field_names = item_struct::field_names( &item ); + let mut field_types = item_struct::field_types( item ); + let field_names = item_struct::field_names( item ); match ( field_types.len(), field_names ) { @@ -55,7 +58,7 @@ pub fn from( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStre &generics_ty, &generics_where, field_names.next().unwrap(), - &field_types.next().unwrap(), + field_types.next().unwrap(), ), ( 1, None ) => generate_single_field @@ -64,7 +67,7 @@ pub fn from( input : proc_macro::TokenStream ) -> Result< proc_macro2::TokenStre &generics_impl, &generics_ty, &generics_where, - &field_types.next().unwrap(), + field_types.next().unwrap(), ), ( _, Some( field_names ) ) => generate_multiple_fields_named @@ -252,7 +255,7 @@ fn generate_single_field_named } // qqq : document, add example of generated code -- done -/// Generates `From`` implementation for structs with a single named field +/// Generates `From` implementation for structs with a single named field /// /// # Example of generated code /// @@ -441,6 +444,7 @@ fn generate_multiple_fields< 'a > } // qqq : document, add example of generated code +#[ allow ( clippy::format_in_format_args ) ] fn variant_generate ( item_name : &syn::Ident, @@ -462,7 +466,7 @@ fn variant_generate return Ok( qt!{} ) } - if fields.len() <= 0 + if fields.is_empty() { return Ok( qt!{} ) } diff --git a/module/core/derive_tools_meta/src/derive/from/field_attributes.rs b/module/core/derive_tools_meta/src/derive/from/field_attributes.rs index 5aeb72bd56..53d1c60393 100644 --- a/module/core/derive_tools_meta/src/derive/from/field_attributes.rs +++ b/module/core/derive_tools_meta/src/derive/from/field_attributes.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools:: { @@ -25,6 +26,7 @@ pub struct FieldAttributes impl FieldAttributes { + #[ allow( clippy::single_match ) ] pub fn from_attrs< 'a >( attrs : impl Iterator< Item = &'a syn::Attribute > ) -> Result< Self > { let mut result = Self::default(); @@ -50,7 +52,7 @@ impl FieldAttributes { let key_ident = attr.path().get_ident().ok_or_else( || error( attr ) )?; - let key_str = format!( "{}", key_ident ); + let key_str = format!( "{key_ident}" ); // attributes does not have to be known // if attr::is_standard( &key_str ) @@ -61,7 +63,7 @@ impl FieldAttributes match key_str.as_ref() { FieldAttributeConfig::KEYWORD => result.assign( FieldAttributeConfig::from_meta( attr )? ), - "debug" => {}, + // "debug" => {}, _ => {}, // _ => return Err( error( attr ) ), } @@ -95,17 +97,18 @@ impl AttributeComponent for FieldAttributeConfig { const KEYWORD : &'static str = "from"; + #[ allow( clippy::match_wildcard_for_single_variants ) ] fn from_meta( attr : &syn::Attribute ) -> Result< Self > { match attr.meta { syn::Meta::List( ref meta_list ) => { - return syn::parse2::< FieldAttributeConfig >( meta_list.tokens.clone() ); + syn::parse2::< FieldAttributeConfig >( meta_list.tokens.clone() ) }, syn::Meta::Path( ref _path ) => { - return Ok( Default::default() ) + Ok( FieldAttributeConfig::default() ) }, _ => return_syn_err!( attr, "Expects an attribute of format `#[ from( on ) ]`. \nGot: {}", qt!{ #attr } ), } diff --git a/module/core/derive_tools_meta/src/derive/from/item_attributes.rs b/module/core/derive_tools_meta/src/derive/from/item_attributes.rs index f60b4fbbe4..4c81f3bcf1 100644 --- a/module/core/derive_tools_meta/src/derive/from/item_attributes.rs +++ b/module/core/derive_tools_meta/src/derive/from/item_attributes.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools:: { @@ -23,6 +24,7 @@ pub struct ItemAttributes impl ItemAttributes { + #[ allow( clippy::single_match ) ] pub fn from_attrs< 'a >( attrs : impl Iterator< Item = &'a syn::Attribute > ) -> Result< Self > { let mut result = Self::default(); @@ -48,7 +50,7 @@ impl ItemAttributes { let key_ident = attr.path().get_ident().ok_or_else( || error( attr ) )?; - let key_str = format!( "{}", key_ident ); + let key_str = format!( "{key_ident}" ); // attributes does not have to be known // if attr::is_standard( &key_str ) @@ -59,7 +61,7 @@ impl ItemAttributes match key_str.as_ref() { ItemAttributeConfig::KEYWORD => result.assign( ItemAttributeConfig::from_meta( attr )? ), - "debug" => {} + // "debug" => {} _ => {}, // _ => return Err( error( attr ) ), // attributes does not have to be known @@ -92,17 +94,18 @@ impl AttributeComponent for ItemAttributeConfig { const KEYWORD : &'static str = "from"; + #[ allow( clippy::match_wildcard_for_single_variants ) ] fn from_meta( attr : &syn::Attribute ) -> Result< Self > { match attr.meta { syn::Meta::List( ref meta_list ) => { - return syn::parse2::< ItemAttributeConfig >( meta_list.tokens.clone() ); + syn::parse2::< ItemAttributeConfig >( meta_list.tokens.clone() ) }, syn::Meta::Path( ref _path ) => { - return Ok( Default::default() ) + Ok( ItemAttributeConfig::default() ) }, _ => return_syn_err!( attr, "Expects an attribute of format `#[ from( on ) ]`. \nGot: {}", qt!{ #attr } ), } diff --git a/module/core/derive_tools_meta/src/lib.rs b/module/core/derive_tools_meta/src/lib.rs index 2b323bbdc0..310fb2bf09 100644 --- a/module/core/derive_tools_meta/src/lib.rs +++ b/module/core/derive_tools_meta/src/lib.rs @@ -345,7 +345,7 @@ pub fn deref_mut( input : proc_macro::TokenStream ) -> proc_macro::TokenStream } /// -/// Derive macro to implement AsRef when-ever it's possible to do automatically. +/// Derive macro to implement `AsRef` when-ever it's possible to do automatically. /// /// ### Sample :: struct instead of macro. /// diff --git a/module/core/diagnostics_tools/src/diag/rta.rs b/module/core/diagnostics_tools/src/diag/rta.rs index 27f8d991ec..4bd27b3bba 100644 --- a/module/core/diagnostics_tools/src/diag/rta.rs +++ b/module/core/diagnostics_tools/src/diag/rta.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -289,4 +289,3 @@ pub mod prelude }; } - diff --git a/module/core/diagnostics_tools/src/lib.rs b/module/core/diagnostics_tools/src/lib.rs index a3415c710e..8ed4ccb486 100644 --- a/module/core/diagnostics_tools/src/lib.rs +++ b/module/core/diagnostics_tools/src/lib.rs @@ -31,7 +31,6 @@ pub mod own #[ doc( inline ) ] pub use orphan::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super::diag::orphan::*; } @@ -54,7 +53,6 @@ pub mod exposed #[ doc( inline ) ] pub use prelude::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super::diag::exposed::*; } @@ -65,6 +63,5 @@ pub mod prelude { use super::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super::diag::prelude::*; } diff --git a/module/core/error_tools/Cargo.toml b/module/core/error_tools/Cargo.toml index de02c81004..dafae99166 100644 --- a/module/core/error_tools/Cargo.toml +++ b/module/core/error_tools/Cargo.toml @@ -48,8 +48,9 @@ error_untyped = [ "anyhow" ] # = entry [dependencies] -anyhow = { version = "~1.0", optional = true } -thiserror = { version = "~1.0", optional = true } +anyhow = { workspace = true, optional = true } +thiserror = { workspace = true, optional = true } [dev-dependencies] test_tools = { workspace = true } +# xxx : qqq : review \ No newline at end of file diff --git a/module/core/error_tools/Readme.md b/module/core/error_tools/Readme.md index 727ed9d8b7..f5e679a074 100644 --- a/module/core/error_tools/Readme.md +++ b/module/core/error_tools/Readme.md @@ -1,6 +1,6 @@ -# Module :: error_tools +# Module :: `error_tools` [![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_error_tools_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_error_tools_push.yml) [![docs.rs](https://img.shields.io/docsrs/error_tools?color=e3e8f0&logo=docs.rs)](https://docs.rs/error_tools) [![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%2Ferror_tools%2Fexamples%2Ferror_tools_trivial.rs,RUN_POSTFIX=--example%20error_tools_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) diff --git a/module/core/error_tools/examples/error_tools_trivial.rs b/module/core/error_tools/examples/error_tools_trivial.rs index cc6fc29f24..e6ddd65432 100644 --- a/module/core/error_tools/examples/error_tools_trivial.rs +++ b/module/core/error_tools/examples/error_tools_trivial.rs @@ -17,5 +17,5 @@ fn main() fn f1() -> error_tools::untyped::Result< () > { let _read = std::fs::read_to_string( "Cargo.toml" )?; - Err( error_tools::BasicError::new( "Some error" ).into() ) + Err( error_tools::untyped::format_err!( "Some error" ) ) } diff --git a/module/core/error_tools/src/error.rs b/module/core/error_tools/src/error.rs deleted file mode 100644 index 730f9c477c..0000000000 --- a/module/core/error_tools/src/error.rs +++ /dev/null @@ -1,265 +0,0 @@ -/// Internal namespace. -mod private -{ - pub use std::error::Error as ErrorTrait; - - /// This trait allows adding extra context or information to an error, creating a tuple of the additional - /// context and the original error. This is particularly useful for error handling when you want to include - /// more details in the error without losing the original error value. - /// - /// The `ErrWith` trait provides methods to wrap an error with additional context, either by using a closure - /// that generates the context or by directly providing the context. - /// - /// ``` - pub trait ErrWith< ReportErr, ReportOk, E > - { - /// Takes a closure `f` that returns a value of type `ReportErr`, and uses it to wrap an error of type `(ReportErr, E)` - /// in the context of a `Result` of type `ReportOk`. - /// - /// This method allows you to add additional context to an error by providing a closure that generates the context. - /// - /// # Arguments - /// - /// * `f` - A closure that returns the additional context of type `ReportErr`. - /// - /// # Returns - /// - /// A `Result` of type `ReportOk` if the original result is `Ok`, or a tuple `(ReportErr, E)` containing the additional - /// context and the original error if the original result is `Err`. - /// - /// # Example - /// - /// ```rust - /// use error_tools::ErrWith; - /// let result : Result< (), std::io::Error > = Err( std::io::Error::new( std::io::ErrorKind::Other, "an error occurred" ) ); - /// let result_with_context : Result< (), ( &str, std::io::Error ) > = result.err_with( || "additional context" ); - /// ``` - fn err_with< F >( self, f : F ) -> std::result::Result< ReportOk, ( ReportErr, E ) > - where - F : FnOnce() -> ReportErr; - - /// Takes a reference to a `ReportErr` value and uses it to wrap an error of type `(ReportErr, E)` - /// in the context of a `Result` of type `ReportOk`. - /// - /// This method allows you to add additional context to an error by providing a reference to the context. - /// - /// # Arguments - /// - /// * `report` - A reference to the additional context of type `ReportErr`. - /// - /// # Returns - /// - /// A `Result` of type `ReportOk` if the original result is `Ok`, or a tuple `(ReportErr, E)` containing the additional - /// context and the original error if the original result is `Err`. - /// - /// # Example - /// - /// ```rust - /// use error_tools::ErrWith; - /// let result : Result< (), std::io::Error > = Err( std::io::Error::new( std::io::ErrorKind::Other, "an error occurred" ) ); - /// let report = "additional context"; - /// let result_with_report : Result< (), ( &str, std::io::Error ) > = result.err_with_report( &report ); - /// ``` - fn err_with_report( self, report : &ReportErr ) -> std::result::Result< ReportOk, ( ReportErr, E ) > - where - ReportErr : Clone; - - } - - impl< ReportErr, ReportOk, E, IntoError > ErrWith< ReportErr, ReportOk, E > - for std::result::Result< ReportOk, IntoError > - where - IntoError : Into< E >, - { - - fn err_with< F >( self, f : F ) -> std::result::Result< ReportOk, ( ReportErr, E ) > - where - F : FnOnce() -> ReportErr, - { - self.map_err( | e | ( f(), e.into() ) ) - } - - #[ inline( always ) ] - fn err_with_report( self, report : &ReportErr ) -> std::result::Result< ReportOk, ( ReportErr, E ) > - where - ReportErr : Clone, - Self : Sized, - { - self.map_err( | e | ( report.clone(), e.into() ) ) - } - - } - - /// A type alias for a `Result` that contains an error which is a tuple of a report and an original error. - /// - /// This is useful when you want to report additional information along with an error. The `ResultWithReport` type - /// helps in defining such results more concisely. - pub type ResultWithReport< Report, Error > = Result< Report, ( Report, Error ) >; - - /// - /// Macro to generate an error descriptor. - /// - /// ### Basic use-case. - /// ```rust - /// # use error_tools::{ BasicError, err }; - /// fn f1() -> BasicError - /// { - /// return err!( "No attr" ); - /// } - /// ``` - /// - - #[ macro_export ] - macro_rules! err - { - - ( $msg : expr ) => - { - $crate::BasicError::new( $msg ).into() - }; - ( $msg : expr, $( $arg : expr ),+ $(,)? ) => - { - $crate::BasicError::new( format!( $msg, $( $arg ),+ ) ).into() - }; - - } - - /// - /// Macro to return an Err( error ) generating error descriptor. - /// - /// ### Basic use-case. - /// ```rust - /// # use error_tools::{ BasicError, return_err }; - /// fn f1() -> Result< (), BasicError > - /// { - /// return_err!( "No attr" ); - /// } - /// ``` - /// - - #[ macro_export ] - macro_rules! return_err - { - - ( $msg : expr ) => - { - return Result::Err( $crate::err!( $msg ) ) - }; - ( $msg : expr, $( $arg : expr ),+ $(,)? ) => - { - return Result::Err( $crate::err!( $msg, $( $arg ),+ ) ) - }; - - } - - // zzz : review - - /// baic implementation of generic BasicError - - #[ derive( core::fmt::Debug, core::clone::Clone, core::cmp::PartialEq, core::cmp::Eq ) ] - pub struct BasicError - { - msg : String, - } - - impl BasicError - { - /// Constructor expecting message with description. - pub fn new< Msg : Into< String > >( msg : Msg ) -> BasicError - { - BasicError { msg : msg.into() } - } - /// Message with description getter. - pub fn msg( &self ) -> &String - { - &self.msg - } - } - - impl core::fmt::Display for BasicError - { - fn fmt(&self, f: &mut core::fmt::Formatter< '_ >) -> core::fmt::Result - { - write!( f, "{}", self.msg ) - } - } - - impl ErrorTrait for BasicError - { - fn description( &self ) -> &str - { - &self.msg - } - } - - impl< T > From< BasicError > for Result< T, BasicError > - { - /// Returns the argument unchanged. - #[ inline( always ) ] - fn from( src : BasicError ) -> Self - { - Result::Err( src ) - } - } - - pub use err; - pub use return_err; - - // qqq : write standard mod interface without using mod_interface /* aaa : Dmytro : added to each library file */ -} - -#[ doc( inline ) ] -#[ allow( unused_imports ) ] -pub use own::*; - -/// Own namespace of the module. -#[ allow( unused_imports ) ] -pub mod own -{ - use super::*; - #[ doc( inline ) ] - pub use orphan::*; -} - -/// Shared with parent namespace of the module -#[ allow( unused_imports ) ] -pub mod orphan -{ - use super::*; - #[ doc( inline ) ] - pub use exposed::*; -} - -/// Exposed namespace of the module. -#[ allow( unused_imports ) ] -pub mod exposed -{ - use super::*; - - #[ doc( inline ) ] - pub use private:: - { - ErrWith, - ResultWithReport, - }; - - #[ doc( inline ) ] - pub use prelude::*; -} - -/// Prelude to use essentials: `use my_module::prelude::*`. -#[ allow( unused_imports ) ] -pub mod prelude -{ - use super::*; - - #[ doc( inline ) ] - pub use private:: - { - err, - return_err, - ErrorTrait, - BasicError, - }; - -} diff --git a/module/core/error_tools/src/assert.rs b/module/core/error_tools/src/error/assert.rs similarity index 74% rename from module/core/error_tools/src/assert.rs rename to module/core/error_tools/src/error/assert.rs index 50c72b0bdf..18ba821186 100644 --- a/module/core/error_tools/src/assert.rs +++ b/module/core/error_tools/src/error/assert.rs @@ -1,8 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { /// - /// Macro asserts that two expressions are identical to each other. Unlike std::assert_eq it is removed from a release build. + /// Macro asserts that two expressions are identical to each other. Unlike `std::assert_eq` it is removed from a release build. /// #[ macro_export ] @@ -58,7 +58,7 @@ mod private // }}; } - /// Macro asserts that two expressions are identical to each other. Unlike std::assert_eq it is removed from a release build. Alias of debug_assert_id. + /// Macro asserts that two expressions are identical to each other. Unlike `std::assert_eq` it is removed from a release build. Alias of `debug_assert_id`. #[ macro_export ] macro_rules! debug_assert_identical @@ -70,7 +70,7 @@ mod private }; } - /// Macro asserts that two expressions are not identical to each other. Unlike std::assert_eq it is removed from a release build. + /// Macro asserts that two expressions are not identical to each other. Unlike `std::assert_eq` it is removed from a release build. #[ macro_export ] macro_rules! debug_assert_ni @@ -83,7 +83,7 @@ mod private }; } - /// Macro asserts that two expressions are not identical to each other. Unlike std::assert_eq it is removed from a release build. + /// Macro asserts that two expressions are not identical to each other. Unlike `std::assert_eq` it is removed from a release build. #[ macro_export ] macro_rules! debug_assert_not_identical @@ -108,9 +108,13 @@ mod private // }; // } + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use debug_assert_id; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use debug_assert_identical; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use debug_assert_ni; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use debug_assert_not_identical; } @@ -118,21 +122,26 @@ mod private #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use orphan::*; } #[ doc( inline ) ] #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use own::*; /// Shared with parent namespace of the module #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use exposed::*; } @@ -140,8 +149,10 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use prelude::*; } @@ -149,9 +160,14 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { + #[ allow( clippy::wildcard_imports ) ] use super::*; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use private::debug_assert_id; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use private::debug_assert_identical; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use private::debug_assert_ni; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use private::debug_assert_not_identical; } diff --git a/module/core/error_tools/src/error/mod.rs b/module/core/error_tools/src/error/mod.rs new file mode 100644 index 0000000000..0de7d2fafd --- /dev/null +++ b/module/core/error_tools/src/error/mod.rs @@ -0,0 +1,374 @@ +/// Define a private namespace for all its items. +mod private +{ + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use std::error::Error as ErrorTrait; + + /// This trait allows adding extra context or information to an error, creating a tuple of the additional + /// context and the original error. This is particularly useful for error handling when you want to include + /// more details in the error without losing the original error value. + /// + /// The `ErrWith` trait provides methods to wrap an error with additional context, either by using a closure + /// that generates the context or by directly providing the context. + /// + /// ``` + pub trait ErrWith< ReportErr, ReportOk, E > + { + /// Takes a closure `f` that returns a value of type `ReportErr`, and uses it to wrap an error of type `(ReportErr, E)` + /// in the context of a `Result` of type `ReportOk`. + /// + /// This method allows you to add additional context to an error by providing a closure that generates the context. + /// + /// # Arguments + /// + /// * `f` - A closure that returns the additional context of type `ReportErr`. + /// + /// # Returns + /// + /// A `Result` of type `ReportOk` if the original result is `Ok`, or a tuple `(ReportErr, E)` containing the additional + /// context and the original error if the original result is `Err`. + /// + /// # Errors + /// + /// qqq: errors + /// + /// # Example + /// + /// ```rust + /// use error_tools::ErrWith; + /// let result : Result< (), std::io::Error > = Err( std::io::Error::new( std::io::ErrorKind::Other, "an error occurred" ) ); + /// let result_with_context : Result< (), ( &str, std::io::Error ) > = result.err_with( || "additional context" ); + /// ``` + fn err_with< F >( self, f : F ) -> core::result::Result< ReportOk, ( ReportErr, E ) > + where + F : FnOnce() -> ReportErr; + + /// Takes a reference to a `ReportErr` value and uses it to wrap an error of type `(ReportErr, E)` + /// in the context of a `Result` of type `ReportOk`. + /// + /// This method allows you to add additional context to an error by providing a reference to the context. + /// + /// # Arguments + /// + /// * `report` - A reference to the additional context of type `ReportErr`. + /// + /// # Returns + /// + /// A `Result` of type `ReportOk` if the original result is `Ok`, or a tuple `(ReportErr, E)` containing the additional + /// context and the original error if the original result is `Err`. + /// + /// # Errors + /// + /// qqq: Errors + /// + /// # Example + /// + /// ```rust + /// use error_tools::ErrWith; + /// let result : Result< (), std::io::Error > = Err( std::io::Error::new( std::io::ErrorKind::Other, "an error occurred" ) ); + /// let report = "additional context"; + /// let result_with_report : Result< (), ( &str, std::io::Error ) > = result.err_with_report( &report ); + /// ``` + fn err_with_report( self, report : &ReportErr ) -> core::result::Result< ReportOk, ( ReportErr, E ) > + where + ReportErr : Clone; + + } + + impl< ReportErr, ReportOk, E, IntoError > ErrWith< ReportErr, ReportOk, E > + for core::result::Result< ReportOk, IntoError > + where + IntoError : Into< E >, + { + + #[ allow( clippy::implicit_return, clippy::min_ident_chars ) ] + #[ inline ] + fn err_with< F >( self, f : F ) -> core::result::Result< ReportOk, ( ReportErr, E ) > + where + F : FnOnce() -> ReportErr, + { + self.map_err( | error | ( f(), error.into() ) ) + } + + #[ inline( always ) ] + #[ allow( clippy::implicit_return ) ] + fn err_with_report( self, report : &ReportErr ) -> core::result::Result< ReportOk, ( ReportErr, E ) > + where + ReportErr : Clone, + Self : Sized, + { + self.map_err( | error | ( report.clone(), error.into() ) ) + } + + } + + /// A type alias for a `Result` that contains an error which is a tuple of a report and an original error. + /// + /// This is useful when you want to report additional information along with an error. The `ResultWithReport` type + /// helps in defining such results more concisely. + pub type ResultWithReport< Report, Error > = Result< Report, ( Report, Error ) >; + +// /// +// /// Macro to generate an error descriptor. +// /// +// /// ### Basic use-case. +// /// ```rust +// /// # use error_tools::{ BasicError, err }; +// /// fn f1() -> BasicError +// /// { +// /// return err!( "No attr" ); +// /// } +// /// ``` +// /// +// +// #[ macro_export ] +// macro_rules! err +// { +// +// ( $msg : expr ) => +// { +// $crate::BasicError::new( $msg ).into() +// }; +// ( $msg : expr, $( $arg : expr ),+ $(,)? ) => +// { +// $crate::BasicError::new( format!( $msg, $( $arg ),+ ) ).into() +// }; +// +// } +// +// /// +// /// Macro to return an Err( error ) generating error descriptor. +// /// +// /// ### Basic use-case. +// /// ```rust +// /// # use error_tools::{ BasicError, return_err }; +// /// fn f1() -> Result< (), BasicError > +// /// { +// /// return_err!( "No attr" ); +// /// } +// /// ``` +// /// +// +// #[ macro_export ] +// macro_rules! return_err +// { +// +// ( $msg : expr ) => +// { +// return Result::Err( $crate::err!( $msg ) ) +// }; +// ( $msg : expr, $( $arg : expr ),+ $(,)? ) => +// { +// return Result::Err( $crate::err!( $msg, $( $arg ),+ ) ) +// }; +// +// } +// +// // zzz : review +// // xxx : rid of +// +// /// baic implementation of generic BasicError +// +// #[ derive( core::fmt::Debug, core::clone::Clone, core::cmp::PartialEq, core::cmp::Eq ) ] +// pub struct BasicError +// { +// msg : String, +// } +// +// impl BasicError +// { +// /// Constructor expecting message with description. +// pub fn new< Msg : Into< String > >( msg : Msg ) -> BasicError +// { +// BasicError { msg : msg.into() } +// } +// /// Message with description getter. +// pub fn msg( &self ) -> &String +// { +// &self.msg +// } +// } +// +// impl core::fmt::Display for BasicError +// { +// fn fmt(&self, f: &mut core::fmt::Formatter< '_ >) -> core::fmt::Result +// { +// write!( f, "{}", self.msg ) +// } +// } +// +// impl ErrorTrait for BasicError +// { +// fn description( &self ) -> &str +// { +// &self.msg +// } +// } +// +// impl< T > From< BasicError > for Result< T, BasicError > +// { +// /// Returns the argument unchanged. +// #[ inline( always ) ] +// fn from( src : BasicError ) -> Self +// { +// Result::Err( src ) +// } +// } +// +// pub use err; +// pub use return_err; + + // qqq : write standard mod interface without using mod_interface /* aaa : Dmytro : added to each library file */ +} + +/// Assertions. +#[ cfg( feature = "enabled" ) ] +pub mod assert; + +#[ cfg( feature = "enabled" ) ] +#[ cfg( feature = "error_typed" ) ] +/// Typed exceptions handling mechanism. +pub mod typed; + +#[ cfg( feature = "enabled" ) ] +#[ cfg( feature = "error_untyped" ) ] +/// Untyped exceptions handling mechanism. +pub mod untyped; + +#[ cfg( feature = "enabled" ) ] +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] +pub use own::*; + +/// Own namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod own +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use orphan::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use assert::orphan::*; + + #[ cfg( feature = "error_untyped" ) ] + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use untyped::orphan::*; + + #[ cfg( feature = "error_typed" ) ] + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use typed::orphan::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use private:: + { + // err, + // return_err, + ErrorTrait, + // BasicError, + }; + + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super::assert; + #[ cfg( feature = "error_typed" ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super::typed; + #[ cfg( feature = "error_untyped" ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super::untyped; + +} + +/// Shared with parent namespace of the module +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod orphan +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use exposed::*; +} + +/// Exposed namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod exposed +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use prelude::*; + + // Expose itself. + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super::super::error; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use private:: + { + ErrWith, + ResultWithReport, + }; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use assert::exposed::*; + + #[ cfg( feature = "error_untyped" ) ] + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use untyped::exposed::*; + + #[ cfg( feature = "error_typed" ) ] + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use typed::exposed::*; + +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod prelude +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + + // #[ doc( inline ) ] + // pub use private:: + // { + // // err, + // // return_err, + // ErrorTrait, + // // BasicError, + // }; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use assert::prelude::*; + + #[ cfg( feature = "error_untyped" ) ] + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use untyped::prelude::*; + + #[ cfg( feature = "error_typed" ) ] + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use typed::prelude::*; + +} diff --git a/module/core/error_tools/src/error/typed.rs b/module/core/error_tools/src/error/typed.rs new file mode 100644 index 0000000000..0845523e35 --- /dev/null +++ b/module/core/error_tools/src/error/typed.rs @@ -0,0 +1,73 @@ +/// Define a private namespace for all its items. +mod private +{ + +} + +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] +pub use own::*; + +/// Own namespace of the module. +#[ allow( unused_imports ) ] +pub mod own +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use orphan::*; +} + +/// Shared with parent namespace of the module +#[ allow( unused_imports ) ] +pub mod orphan +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super::super::typed; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super::super::typed as for_lib; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use exposed::*; + + #[ doc( inline ) ] + #[ allow( unused_imports ) ] + #[ allow( clippy::pub_use ) ] + pub use ::thiserror:: + { + Error, + }; + +} + +/// Exposed namespace of the module. +#[ allow( unused_imports ) ] +pub mod exposed +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use prelude::*; + +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ allow( unused_imports ) ] +pub mod prelude +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + + #[ doc( inline ) ] + #[ allow( unused_imports ) ] + #[ allow( clippy::pub_use ) ] + pub use thiserror; + +} \ No newline at end of file diff --git a/module/core/error_tools/src/error/untyped.rs b/module/core/error_tools/src/error/untyped.rs new file mode 100644 index 0000000000..d4d65afe67 --- /dev/null +++ b/module/core/error_tools/src/error/untyped.rs @@ -0,0 +1,83 @@ +/// Define a private namespace for all its items. +mod private +{ + +} + +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] +pub use own::*; + +/// Own namespace of the module. +#[ allow( unused_imports ) ] +pub mod own +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use orphan::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use ::anyhow:: + { + Chain, + Context, + Error, + Ok, + Result, + format_err, + bail as return_err, + ensure, + bail, + }; + +} + +/// Shared with parent namespace of the module +#[ allow( unused_imports ) ] +pub mod orphan +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super::super::untyped; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use super::super::untyped as for_app; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use exposed::*; + + // #[ doc( inline ) ] + // pub use ::anyhow:: + // { + // format_err, + // ensure, + // bail, + // }; + +} + +/// Exposed namespace of the module. +#[ allow( unused_imports ) ] +pub mod exposed +{ + #[ allow( clippy::wildcard_imports ) ] + use super::*; + + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use prelude::*; + +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; +} \ No newline at end of file diff --git a/module/core/error_tools/src/lib.rs b/module/core/error_tools/src/lib.rs index 30a25af03b..dbf07d7fb2 100644 --- a/module/core/error_tools/src/lib.rs +++ b/module/core/error_tools/src/lib.rs @@ -3,12 +3,10 @@ #![ 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/error_tools/latest/error_tools/" ) ] #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] +#![ allow( clippy::mod_module_files ) ] -/// Assertions. -#[ cfg( feature = "enabled" ) ] -pub mod assert; - -/// Alias for std::error::BasicError. +/// Alias for `std::error::BasicError`. +#[ allow( clippy::pub_use ) ] #[ cfg( feature = "enabled" ) ] #[ cfg( not( feature = "no_std" ) ) ] pub mod error; @@ -19,132 +17,86 @@ pub mod dependency { #[ doc( inline ) ] - #[ allow( unused_imports ) ] #[ cfg( feature = "error_typed" ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use ::thiserror; #[ doc( inline ) ] - #[ allow( unused_imports ) ] #[ cfg( feature = "error_untyped" ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use ::anyhow; } #[ cfg( feature = "enabled" ) ] -#[ cfg( feature = "error_typed" ) ] -/// Typed exceptions handling mechanism. -pub mod typed; - -#[ cfg( feature = "enabled" ) ] -#[ cfg( feature = "error_untyped" ) ] -/// Untyped exceptions handling mechanism. -pub mod untyped; - -#[ cfg( feature = "enabled" ) ] +#[ cfg( not( feature = "no_std" ) ) ] #[ doc( inline ) ] #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use own::*; /// Own namespace of the module. #[ cfg( feature = "enabled" ) ] +#[ cfg( not( feature = "no_std" ) ) ] #[ allow( unused_imports ) ] pub mod own { use super::*; - #[ allow( unused_imports ) ] - use super::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use assert::orphan::*; - - #[ cfg( not( feature = "no_std" ) ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use error::orphan::*; - - #[ cfg( feature = "error_untyped" ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use untyped::orphan::*; - - #[ cfg( feature = "error_typed" ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use typed::orphan::*; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use error::own::*; } /// Shared with parent namespace of the module #[ cfg( feature = "enabled" ) ] +#[ cfg( not( feature = "no_std" ) ) ] #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use exposed::*; + #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] + pub use error::orphan::*; + } /// Exposed namespace of the module. #[ cfg( feature = "enabled" ) ] +#[ cfg( not( feature = "no_std" ) ) ] #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use prelude::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use assert::exposed::*; - - #[ cfg( not( feature = "no_std" ) ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use error::exposed::*; - #[ cfg( feature = "error_untyped" ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use untyped::exposed::*; - - #[ cfg( feature = "error_typed" ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use typed::exposed::*; - } /// Prelude to use essentials: `use my_module::prelude::*`. #[ cfg( feature = "enabled" ) ] +#[ cfg( not( feature = "no_std" ) ) ] #[ allow( unused_imports ) ] pub mod prelude { - use super::*; - #[ allow( unused_imports ) ] - use super::*; + use super::error; #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use assert::prelude::*; - - #[ cfg( not( feature = "no_std" ) ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use error::prelude::*; - #[ cfg( feature = "error_untyped" ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use untyped::prelude::*; - - #[ cfg( feature = "error_typed" ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use typed::prelude::*; - } diff --git a/module/core/error_tools/src/result.rs b/module/core/error_tools/src/result.rs deleted file mode 100644 index ea5a3c3b48..0000000000 --- a/module/core/error_tools/src/result.rs +++ /dev/null @@ -1,43 +0,0 @@ -// /// Internal namespace. -// mod private -// { -// use crate::error::BasicError; -// -// /// Type alias for Result with BasicError. -// pub type Result< T, E = BasicError > = std::result::Result< T, E >; -// } -// -// /// Own namespace of the module. -// pub mod own -// { -// #[ doc( inline ) ] -// #[ allow( unused_imports ) ] -// pub use orphan::*; -// } -// -// #[ doc( inline ) ] -// #[ allow( unused_imports ) ] -// pub use own::*; -// -// /// Shared with parent namespace of the module -// pub mod orphan -// { -// #[ doc( inline ) ] -// #[ allow( unused_imports ) ] -// pub use exposed::*; -// } -// -// /// Exposed namespace of the module. -// pub mod exposed -// { -// #[ doc( inline ) ] -// #[ allow( unused_imports ) ] -// pub use prelude::*; -// } -// -// /// Prelude to use essentials: `use my_module::prelude::*`. -// pub mod prelude -// { -// pub use private::Result; -// } -// diff --git a/module/core/error_tools/tests/inc/basic_test.rs b/module/core/error_tools/tests/inc/basic_test.rs index 61462b17f9..32cb4c4bba 100644 --- a/module/core/error_tools/tests/inc/basic_test.rs +++ b/module/core/error_tools/tests/inc/basic_test.rs @@ -1,5 +1,5 @@ #![ allow( deprecated ) ] -#![ allow( unused_imports ) ] +// #![ allow( unused_imports ) ] use super::*; // @@ -7,117 +7,116 @@ use super::*; #[ cfg( not( feature = "no_std" ) ) ] tests_impls! { - fn basic() - { - use std::error::Error; - - // test.case( "basic" ); - - let err1 = the_module::BasicError::new( "Some error" ); - a_id!( err1.to_string(), "Some error" ); - a_id!( err1.description(), "Some error" ); - a_id!( err1.msg(), "Some error" ); - a_id!( format!( "err1 : {}", err1 ), "err1 : Some error" ); - - // test.case( "compare" ); - - let err1 = the_module::BasicError::new( "Some error" ); - let err2 = the_module::BasicError::new( "Some error" ); - a_id!( err1, err2 ); - a_id!( err1.description(), err2.description() ); - - // test.case( "clone" ); - - let err1 = the_module::BasicError::new( "Some error" ); - let err2 = err1.clone(); - a_id!( err1, err2 ); - a_id!( err1.description(), err2.description() ); - } - - // - - fn use1() - { - use std::error::Error as ErrorTrait; - use the_module::BasicError as Error; - - // test.case( "basic" ); - - let err1 = Error::new( "Some error" ); - a_id!( err1.to_string(), "Some error" ); - a_id!( err1.description(), "Some error" ); - a_id!( err1.msg(), "Some error" ); - a_id!( format!( "err1 : {}", err1 ), "err1 : Some error" ); - } - - // - - fn use2() - { - use the_module::{ BasicError, ErrorTrait }; - - // test.case( "basic" ); - - let err1 = BasicError::new( "Some error" ); - a_id!( err1.to_string(), "Some error" ); - a_id!( err1.description(), "Some error" ); - a_id!( err1.msg(), "Some error" ); - a_id!( format!( "err1 : {}", err1 ), "err1 : Some error" ); - } - - // - - fn use3() - { - use std::error::Error; - - // test.case( "basic" ); - - let err1 = the_module::BasicError::new( "Some error" ); - a_id!( err1.to_string(), "Some error" ); - a_id!( err1.description(), "Some error" ); - a_id!( err1.msg(), "Some error" ); - a_id!( format!( "err1 : {}", err1 ), "err1 : Some error" ); - } - - // - - fn err_basic() - { - // test.case( "basic" ); - let err : the_module::BasicError = the_module::err!( "abc" ); - a_id!( err.to_string(), "abc" ); - - // test.case( "with args" ); - let err : the_module::BasicError = the_module::err!( "abc{}{}", "def", "ghi" ); - a_id!( err.to_string(), "abcdefghi" ); - } +// fn basic() +// { +// use std::error::Error; +// +// // test.case( "basic" ); +// +// let err1 = the_module::BasicError::new( "Some error" ); +// a_id!( err1.to_string(), "Some error" ); +// a_id!( err1.description(), "Some error" ); +// a_id!( err1.msg(), "Some error" ); +// a_id!( format!( "err1 : {}", err1 ), "err1 : Some error" ); +// +// // test.case( "compare" ); +// +// let err1 = the_module::BasicError::new( "Some error" ); +// let err2 = the_module::BasicError::new( "Some error" ); +// a_id!( err1, err2 ); +// a_id!( err1.description(), err2.description() ); +// +// // test.case( "clone" ); +// +// let err1 = the_module::BasicError::new( "Some error" ); +// let err2 = err1.clone(); +// a_id!( err1, err2 ); +// a_id!( err1.description(), err2.description() ); +// } // - fn sample() - { - #[ cfg( not( feature = "no_std" ) ) ] - fn f1() -> the_module::untyped::Result< () > - { - let _read = std::fs::read_to_string( "Cargo.toml" )?; - Err( the_module::BasicError::new( "Some error" ).into() ) - // the_module::BasicError::new( "Some error" ).into() - // zzz : make it working maybe - } - - #[ cfg( not( feature = "no_std" ) ) ] - { - let err = f1(); - println!( "{err:#?}" ); - // < Err( - // < BasicError { - // < msg: "Some error", - // < }, - // < ) - } - } - +// fn use1() +// { +// use std::error::Error as ErrorTrait; +// use the_module::BasicError as Error; +// +// // test.case( "basic" ); +// +// let err1 = Error::new( "Some error" ); +// a_id!( err1.to_string(), "Some error" ); +// a_id!( err1.description(), "Some error" ); +// a_id!( err1.msg(), "Some error" ); +// a_id!( format!( "err1 : {}", err1 ), "err1 : Some error" ); +// } +// +// // +// +// fn use2() +// { +// use the_module::{ BasicError, ErrorTrait }; +// +// // test.case( "basic" ); +// +// let err1 = BasicError::new( "Some error" ); +// a_id!( err1.to_string(), "Some error" ); +// a_id!( err1.description(), "Some error" ); +// a_id!( err1.msg(), "Some error" ); +// a_id!( format!( "err1 : {}", err1 ), "err1 : Some error" ); +// } +// +// // +// +// fn use3() +// { +// use std::error::Error; +// +// // test.case( "basic" ); +// +// let err1 = the_module::BasicError::new( "Some error" ); +// a_id!( err1.to_string(), "Some error" ); +// a_id!( err1.description(), "Some error" ); +// a_id!( err1.msg(), "Some error" ); +// a_id!( format!( "err1 : {}", err1 ), "err1 : Some error" ); +// } +// +// // +// +// fn err_basic() +// { +// // test.case( "basic" ); +// let err : the_module::BasicError = the_module::err!( "abc" ); +// a_id!( err.to_string(), "abc" ); +// +// // test.case( "with args" ); +// let err : the_module::BasicError = the_module::err!( "abc{}{}", "def", "ghi" ); +// a_id!( err.to_string(), "abcdefghi" ); +// } +// +// // +// +// fn sample() +// { +// #[ cfg( not( feature = "no_std" ) ) ] +// fn f1() -> the_module::untyped::Result< () > +// { +// let _read = std::fs::read_to_string( "Cargo.toml" )?; +// Err( the_module::BasicError::new( "Some error" ).into() ) +// // the_module::BasicError::new( "Some error" ).into() +// // zzz : make it working maybe +// } +// +// #[ cfg( not( feature = "no_std" ) ) ] +// { +// let err = f1(); +// println!( "{err:#?}" ); +// // < Err( +// // < BasicError { +// // < msg: "Some error", +// // < }, +// // < ) +// } +// } } @@ -126,10 +125,10 @@ tests_impls! #[ cfg( not( feature = "no_std" ) ) ] tests_index! { - basic, - use1, - use2, - use3, - err_basic, - sample, + // basic, + // use1, + // use2, + // use3, + // err_basic, + // sample, } diff --git a/module/core/error_tools/tests/inc/mod.rs b/module/core/error_tools/tests/inc/mod.rs index 256c6e20bd..dc239e680e 100644 --- a/module/core/error_tools/tests/inc/mod.rs +++ b/module/core/error_tools/tests/inc/mod.rs @@ -1,8 +1,10 @@ #[ allow( unused_imports ) ] use super::*; -mod assert_test; mod basic_test; +mod namespace_test; + +mod assert_test; #[ cfg( not( feature = "no_std" ) ) ] mod err_with_test; mod untyped_test; diff --git a/module/core/error_tools/tests/inc/namespace_test.rs b/module/core/error_tools/tests/inc/namespace_test.rs new file mode 100644 index 0000000000..92e96b0610 --- /dev/null +++ b/module/core/error_tools/tests/inc/namespace_test.rs @@ -0,0 +1,12 @@ +use super::*; + +#[ test ] +fn exposed_main_namespace() +{ + + the_module::error::debug_assert_id!( 1, 1 ); + the_module::exposed::error::debug_assert_id!( 1, 1 ); + use the_module::exposed::*; + error::debug_assert_id!( 1, 1 ); + +} \ No newline at end of file diff --git a/module/core/error_tools/tests/tests.rs b/module/core/error_tools/tests/tests.rs index 0374c10521..f217bd0119 100644 --- a/module/core/error_tools/tests/tests.rs +++ b/module/core/error_tools/tests/tests.rs @@ -1,7 +1,6 @@ +#![ allow( unused_imports ) ] -#[ allow( unused_imports ) ] use error_tools as the_module; -#[ allow( unused_imports ) ] use test_tools::exposed::*; mod inc; diff --git a/module/core/for_each/src/lib.rs b/module/core/for_each/src/lib.rs index b106a5110b..00825e5b96 100644 --- a/module/core/for_each/src/lib.rs +++ b/module/core/for_each/src/lib.rs @@ -4,7 +4,7 @@ #![ doc( html_root_url = "https://docs.rs/for_each/latest/for_each/" ) ] #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( feature = "enabled" ) ] mod private { diff --git a/module/core/format_tools/src/format.rs b/module/core/format_tools/src/format.rs index 2abf7f18a4..6200a4f5d8 100644 --- a/module/core/format_tools/src/format.rs +++ b/module/core/format_tools/src/format.rs @@ -2,7 +2,7 @@ //! Collection of mechanisms for formatting and serialization into string. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -289,6 +289,7 @@ pub mod string; pub mod table; pub mod to_string; pub mod to_string_with_fallback; +pub mod text_wrap; /// A strucutre for diagnostic and demonstration purpose. #[ doc( hidden ) ] @@ -317,6 +318,7 @@ pub mod own table::orphan::*, to_string::orphan::*, to_string_with_fallback::orphan::*, + text_wrap::orphan::*, }; } @@ -369,6 +371,7 @@ pub mod exposed table::exposed::*, to_string::exposed::*, to_string_with_fallback::exposed::*, + text_wrap::exposed::*, }; } @@ -391,6 +394,7 @@ pub mod prelude table::prelude::*, to_string::prelude::*, to_string_with_fallback::prelude::*, + text_wrap::prelude::*, }; } diff --git a/module/core/format_tools/src/format/as_table.rs b/module/core/format_tools/src/format/as_table.rs index b1c48c159f..d269556525 100644 --- a/module/core/format_tools/src/format/as_table.rs +++ b/module/core/format_tools/src/format/as_table.rs @@ -2,7 +2,7 @@ //! Nice print's wrapper. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -32,7 +32,7 @@ mod private ) where RowKey : table::RowKey, - Row : Cells< CellKey>, + Row : Cells< CellKey >, CellKey : table::CellKey + ?Sized, // CellRepr : table::CellRepr ; @@ -41,7 +41,7 @@ mod private AsTable< 'table, Table, RowKey, Row, CellKey> where RowKey : table::RowKey, - Row : Cells< CellKey>, + Row : Cells< CellKey >, CellKey : table::CellKey + ?Sized, // CellRepr : table::CellRepr, { @@ -56,7 +56,7 @@ mod private for AsTable< 'table, Table, RowKey, Row, CellKey> where RowKey : table::RowKey, - Row : Cells< CellKey>, + Row : Cells< CellKey >, CellKey : table::CellKey + ?Sized, // CellRepr : table::CellRepr, { @@ -70,7 +70,7 @@ mod private for AsTable< 'table, Table, RowKey, Row, CellKey> where RowKey : table::RowKey, - Row : Cells< CellKey>, + Row : Cells< CellKey >, CellKey : table::CellKey + ?Sized, // CellRepr : table::CellRepr, { @@ -86,7 +86,7 @@ mod private for AsTable< 'table, Table, RowKey, Row, CellKey> where RowKey : table::RowKey, - Row : Cells< CellKey>, + Row : Cells< CellKey >, CellKey : table::CellKey + ?Sized, // CellRepr : table::CellRepr, { @@ -101,7 +101,7 @@ mod private where Table : fmt::Debug, RowKey : table::RowKey, - Row : Cells< CellKey>, + Row : Cells< CellKey >, CellKey : table::CellKey + ?Sized, // CellRepr : table::CellRepr, { @@ -146,7 +146,7 @@ mod private for AsTable< 'table, Table, RowKey, Row, CellKey> where RowKey : table::RowKey, - Row : Cells< CellKey>, + Row : Cells< CellKey >, CellKey : table::CellKey + ?Sized, // CellRepr : table::CellRepr, Self : Copy, diff --git a/module/core/format_tools/src/format/filter.rs b/module/core/format_tools/src/format/filter.rs index 191522e138..1551721570 100644 --- a/module/core/format_tools/src/format/filter.rs +++ b/module/core/format_tools/src/format/filter.rs @@ -2,7 +2,7 @@ //! Print data as table. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/core/format_tools/src/format/md_math.rs b/module/core/format_tools/src/format/md_math.rs index 196b0ee811..9aa70022d0 100644 --- a/module/core/format_tools/src/format/md_math.rs +++ b/module/core/format_tools/src/format/md_math.rs @@ -5,7 +5,7 @@ // xxx : use crate mdmath -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use core:: diff --git a/module/core/format_tools/src/format/output_format.rs b/module/core/format_tools/src/format/output_format.rs index 69acca8515..1bf58b75e6 100644 --- a/module/core/format_tools/src/format/output_format.rs +++ b/module/core/format_tools/src/format/output_format.rs @@ -28,10 +28,12 @@ //! ``` //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + use std::borrow::Cow; + use crate::*; use print:: { @@ -78,6 +80,36 @@ mod private } } + /// Print table, which is constructed with vectors and `Cow`s, with the + /// specified output formatter. + /// + /// This function is useful when you do not want to use `AsTable`, or implement `Fields`, and + /// other traits, but you just have string slices in vectors. + /// + /// `rows` should not contain header of the table, it will be automatically added if `has_header` + /// is true. + pub fn vector_table_write< 'data, 'context > + ( + column_names : Vec< Cow< 'data, str > >, + has_header : bool, + rows : Vec< Vec< Cow< 'data, str > > >, + c : &mut Context< 'context >, + ) -> fmt::Result + { + InputExtract::extract_from_raw_table + ( + column_names, + has_header, + rows, + c.printer.filter_col, + c.printer.filter_row, + | x | + { + c.printer.output_format.extract_write( x, c ) + } + ) + } + } mod table; @@ -106,6 +138,7 @@ pub mod own #[ doc( inline ) ] pub use private:: { + vector_table_write, }; } diff --git a/module/core/format_tools/src/format/output_format/records.rs b/module/core/format_tools/src/format/output_format/records.rs index 45a1206e41..1c89f34038 100644 --- a/module/core/format_tools/src/format/output_format/records.rs +++ b/module/core/format_tools/src/format/output_format/records.rs @@ -22,12 +22,12 @@ //! use crate::*; -use md_math::MdOffset; use print:: { InputExtract, Context, }; +use std::borrow::Cow; use core:: { fmt, @@ -59,6 +59,8 @@ pub struct Records pub cell_postfix : String, /// Separator used between table columns. pub cell_separator : String, + /// Limit table width. If the value is zero, then no limitation. + pub max_width: usize, // /// Horizontal line character. // pub h : char, // /// Vertical line character. @@ -91,6 +93,25 @@ impl Records static INSTANCE : OnceLock< Records > = OnceLock::new(); INSTANCE.get_or_init( || Records::default() ) } + + /// Calculate how much space is minimally needed in order to generate an output with this output formatter. + /// It will be impossible to render tables smaller than the result of `min_width()`. + /// + /// This function is similar to `output_format::Table::min_width`, but it does not contain a + /// `column_count` as it always equal to 2, and it aslo uses the `output_format::Records` + /// style parameters. + pub fn min_width + ( + &self, + ) -> usize + { + // 2 is used here, because `Records` displays 2 columns: keys and values. + self.row_prefix.chars().count() + + self.row_postfix.chars().count() + + 2 * ( self.cell_postfix.chars().count() + self.cell_prefix.chars().count() ) + + self.cell_separator.chars().count() + + 2 + } } impl Default for Records @@ -108,6 +129,8 @@ impl Default for Records let table_postfix = "".to_string(); let table_separator = "\n".to_string(); + let max_width = 0; + // let h = '─'; // let v = '|'; // let t_l = '├'; @@ -131,6 +154,7 @@ impl Default for Records cell_prefix, cell_postfix, cell_separator, + max_width, // h, // v, // t_l, @@ -155,70 +179,88 @@ impl TableOutputFormat for Records c : & mut Context< 'buf >, ) -> fmt::Result { + use format::text_wrap::{ text_wrap, width_calculate }; + + if self.max_width != 0 && self.max_width < self.min_width() + { + return Err( fmt::Error ); + } + + // 2 because there are only 2 columns: key and value. + let columns_max_width = if self.max_width == 0 { 0 } else { self.max_width - self.min_width() + 2 }; - let label_width = x.header().fold( 0, | acc, cell | acc.max( cell.1[ 0 ] ) ); + let keys : Vec< ( Cow< 'data, str >, [ usize; 2 ] ) > = x.header().collect(); + let keys_width = width_calculate( &keys ); write!( c.buf, "{}", self.table_prefix )?; - let mut first = true; - // Write each record - for ( irow, row ) in x.rows() - { + let mut printed_tables_count = 0; - if !row.vis + for ( itable_descriptor, table_descriptor ) in x.row_descriptors.iter().enumerate() + { + if !table_descriptor.vis || ( x.has_header && itable_descriptor == 0 ) { continue; } - if first - { - first = false; - } - else + if printed_tables_count > 0 { write!( c.buf, "{}", self.table_separator )?; } - let slice_width = x.data[ irow ].iter().fold( 0, | acc, cell | acc.max( cell.1[ 0 ] ) ); + printed_tables_count += 1; + + writeln!( c.buf, " = {}", table_descriptor.irow )?; - writeln!( c.buf, " = {}", irow )?; + let values = &x.data[ itable_descriptor ]; + let values_width = width_calculate( &values ); - for ( icol, _col ) in x.col_descriptors.iter().enumerate() + let table_for_wrapping : Vec< Vec< ( Cow< 'data, str >, [ usize; 2] ) > > = + keys.iter().enumerate().map( | ( ikey, key ) | { - let cell = &x.data[ irow ][ icol ]; - let height = cell.1[ 1 ]; + vec![ key.clone(), values[ ikey ].clone() ] + }).collect(); - for islice in 0..height + let wrapped_text = text_wrap + ( + table_for_wrapping.iter(), + &[ keys_width, values_width ], + columns_max_width, + keys_width + values_width, + ); + + for ( irow, cols ) in wrapped_text.data.into_iter().enumerate() + { + if irow != 0 { - let label = x.header_slice( islice, icol ); - let md_index = [ islice, icol, irow ]; - let slice = x.slices[ x.slices_dim.md_offset( md_index ) ]; - - if icol > 0 || islice > 0 - { - write!( c.buf, "{}", self.row_separator )?; - } - - write!( c.buf, "{}", self.row_prefix )?; - - write!( c.buf, "{}", self.cell_prefix )?; - write!( c.buf, "{: usize + { + self.row_prefix.chars().count() + + self.row_postfix.chars().count() + + column_count * ( self.cell_postfix.chars().count() + self.cell_prefix.chars().count() ) + + if column_count == 0 { 0 } else { ( column_count - 1 ) * self.cell_separator.chars().count() } + + column_count + } } impl TableOutputFormat for Table { fn extract_write< 'buf, 'data >( &self, x : &InputExtract< 'data >, c : &mut Context< 'buf > ) -> fmt::Result { - use md_math::MdOffset; + use format::text_wrap::text_wrap; let cell_prefix = &self.cell_prefix; let cell_postfix = &self.cell_postfix; @@ -173,103 +196,92 @@ impl TableOutputFormat for Table let row_separator = &self.row_separator; let h = self.h.to_string(); - let mut delimitting_header = self.delimitting_header; - let row_width = if delimitting_header + let column_count = x.col_descriptors.len(); + + if self.max_width != 0 && ( self.min_width( column_count ) > self.max_width ) { - let mut grid_width = x.mcells_vis[ 0 ] * ( cell_prefix.chars().count() + cell_postfix.chars().count() ); - grid_width += row_prefix.chars().count() + row_postfix.chars().count(); - if x.mcells_vis[ 0 ] > 0 - { - grid_width += ( x.mcells_vis[ 0 ] - 1 ) * ( cell_separator.chars().count() ); - } - x.mchars[ 0 ] + grid_width + return Err( fmt::Error ); } - else - { - 0 - }; - let mut prev_typ : Option< LineType > = None; - // dbg!( x.row_descriptors.len() ); - - for ( irow, row ) in x.row_descriptors.iter().enumerate() + let columns_nowrap_width = x.col_descriptors.iter().map( |c| c.width ).sum::(); + let visual_elements_width = self.min_width( column_count ) - column_count; + + let filtered_data = x.row_descriptors.iter().filter_map( | r | { - let height = row.height; - - if delimitting_header + if r.vis { - if let Some( prev_typ ) = prev_typ - { - if prev_typ == LineType::Header && row.typ == LineType::Regular - { - write!( c.buf, "{}", row_separator )?; - write!( c.buf, "{}", h.repeat( row_width ) )?; - delimitting_header = false - } - } - if row.vis - { - prev_typ = Some( row.typ ); - } + Some( &x.data[ r.irow ] ) } - - if !row.vis + else { - continue; + None + } + }); + + let wrapped_text = text_wrap + ( + filtered_data, + x.col_descriptors.iter().map( | c | c.width ).collect::< Vec< usize > >(), + if self.max_width == 0 { 0 } else { self.max_width - visual_elements_width }, + columns_nowrap_width + ); + + let new_columns_widthes = wrapped_text.column_widthes.iter().sum::(); + let new_row_width = new_columns_widthes + visual_elements_width; + + let mut printed_row_count = 0; + + for row in wrapped_text.data.iter() + { + if printed_row_count == wrapped_text.first_row_height && x.has_header && self.delimitting_header + { + write!( c.buf, "{}", row_separator )?; + write!( c.buf, "{}", h.repeat( new_row_width ) )?; + } + + if printed_row_count > 0 + { + write!( c.buf, "{}", row_separator )?; } - // dbg!( row.height ); + printed_row_count += 1; - for islice in 0..height - { + write!( c.buf, "{}", row_prefix )?; - if irow > 0 + for ( icol, col ) in row.iter().enumerate() + { + let cell_wrapped_width = col.wrap_width; + let column_width = wrapped_text.column_widthes[ icol ]; + let slice_width = col.content.chars().count(); + + if icol > 0 { - write!( c.buf, "{}", row_separator )?; + write!( c.buf, "{}", cell_separator )?; } - write!( c.buf, "{}", row_prefix )?; + write!( c.buf, "{}", cell_prefix )?; + + let lspaces = ( column_width - cell_wrapped_width ) / 2; + let rspaces = ( ( column_width - cell_wrapped_width ) as f32 / 2 as f32 ).round() as usize + cell_wrapped_width - slice_width; - for icol in 0 .. x.col_descriptors.len() + if lspaces > 0 { - let col = &x.col_descriptors[ icol ]; - let cell_width = x.data[ irow ][ icol ].1[0]; - let width = col.width; - let md_index = [ islice, icol, irow as usize ]; - let slice = x.slices[ x.slices_dim.md_offset( md_index ) ]; - - // println!( "md_index : {md_index:?} | md_offset : {} | slice : {slice}", x.slices_dim.md_offset( md_index ) ); - - if icol > 0 - { - write!( c.buf, "{}", cell_separator )?; - } - - write!( c.buf, "{}", cell_prefix )?; - - // println!( "icol : {icol} | irow : {irow} | width : {width} | cell_width : {cell_width}" ); - let lspaces = ( width - cell_width ) / 2; - let rspaces = ( width - cell_width + 1 ) / 2 + cell_width - slice.len(); - // println!( "icol : {icol} | irow : {irow} | width : {width} | cell_width : {cell_width} | lspaces : {lspaces} | rspaces : {rspaces}" ); - - if lspaces > 0 - { - write!( c.buf, "{: 0 - { - write!( c.buf, "{:>width$}", " ", width = rspaces )?; - } + write!( c.buf, "{: 0 + { + write!( c.buf, "{:>width$}", " ", width = rspaces )?; } - write!( c.buf, "{}", row_postfix )?; + write!( c.buf, "{}", cell_postfix )?; } + write!( c.buf, "{}", row_postfix )?; } Ok(()) } -} +} \ No newline at end of file diff --git a/module/core/format_tools/src/format/print.rs b/module/core/format_tools/src/format/print.rs index 858bd7dd57..8ad31f189b 100644 --- a/module/core/format_tools/src/format/print.rs +++ b/module/core/format_tools/src/format/print.rs @@ -2,15 +2,14 @@ //! Print data as table. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::*; - use md_math::MdOffset; use std:: { - borrow::Cow, + borrow::{ Cow, Borrow }, collections::HashMap, }; use core:: @@ -230,9 +229,15 @@ mod private #[ derive( Debug, Default ) ] pub struct RowDescriptor { + + + /// Index of the row. pub irow : usize, + /// Height of the row. pub height : usize, + /// Type of the line: header or regular. pub typ : LineType, + /// Visibility of the row. pub vis : bool, } @@ -241,8 +246,11 @@ mod private #[ derive( Debug, Default ) ] pub struct ColDescriptor< 'label > { + /// Index of the column. pub icol : usize, + /// Column width. pub width : usize, + /// Label of the column. pub label : &'label str, } @@ -282,11 +290,6 @@ mod private // string, size, pub data : Vec< Vec< ( Cow< 'data, str >, [ usize ; 2 ] ) > >, // xxx : use maybe flat vector - /// Dimensions of slices for retrieving data from multi-matrix. - pub slices_dim : [ usize ; 3 ], - /// Extracted slices or strings for further processing. - pub slices : Vec< &'data str >, - } // @@ -340,70 +343,122 @@ mod private /// Returns a slice from the header, or an empty string if no header is present. /// - /// This function retrieves a specific slice from the header row based on the provided indices. - /// If the table does not have a header, it returns an empty string. - /// /// # Arguments /// - /// - `islice`: The slice index within the header cell. /// - `icol`: The column index within the header row. /// /// # Returns /// - /// A string slice representing the header content at the specified indices. + /// A string slice representing the header content. /// - pub fn header_slice( & self, islice : usize, icol : usize ) -> & str + pub fn header_slice( & self, icol : usize ) -> & str { if self.has_header { - let md_index = [ islice, icol, 0 ]; - self.slices[ self.slices_dim.md_offset( md_index ) ] + self.data[ 0 ][ icol ].0.borrow() } else { "" } } + + /// Extract input data from and collect it in a format consumable by output formatter. - pub fn extract< 't, 'context, Table, RowKey, Row, CellKey> + pub fn extract< 'context, Table, RowKey, Row, CellKey> ( - table : &'t Table, + table : &'data Table, filter_col : &'context ( dyn FilterCol + 'context ), filter_row : &'context ( dyn FilterRow + 'context ), callback : impl for< 'a2 > FnOnce( &'a2 InputExtract< 'a2 > ) -> fmt::Result, ) -> fmt::Result where - 'data : 't, - // 't : 'data, Table : TableRows< RowKey = RowKey, Row = Row, CellKey = CellKey >, Table : TableHeader< CellKey = CellKey >, RowKey : table::RowKey, - Row : Cells< CellKey> + 'data, + Row : Cells< CellKey > + 'data, + Row : Cells< CellKey > + 'data, CellKey : table::CellKey + ?Sized + 'data, // CellRepr : table::CellRepr, { - use md_math::MdOffset; + let mut key_to_ikey : HashMap< Cow< 'data, str >, usize > = HashMap::new(); + let mut keys_count = 0; + + let rows = table.rows().map( | r | + { + let mut unsorted : Vec< ( usize, Cow< 'data, str > ) > = r.cells().map( | ( key, c ) | + { + if !key_to_ikey.contains_key( key.borrow() ) + { + key_to_ikey.insert( key.borrow().into(), keys_count ); + keys_count += 1; + } + + ( key_to_ikey[ key.borrow() ], c.unwrap_or( Cow::from( "" ) ) ) + } ).collect(); + + unsorted.sort_by( | ( i1, _ ), ( i2, _ ) | i1.cmp(i2) ); + + unsorted.into_iter().map( | ( _, c ) | c).collect() + } ).collect(); + + let has_header = table.header().is_some(); + + let column_names = match table.header() + { + Some( header ) => header.map( | ( k, _ ) | Cow::from( k.borrow() ) ).collect(), + None => match table.rows().next() + { + Some( r ) => r.cells().map( | ( k, _ ) | Cow::from( k.borrow() ) ).collect(), + None => Vec::new() + } + }; + + Self::extract_from_raw_table + ( + column_names, + has_header, + rows, + filter_col, + filter_row, + callback, + ) + } + + /// Extract input data from a table that is constructed with vectors and `Cow`s and collect + /// it in a format consumable by output formatter. + /// + /// `rows` should not contain header of the table, it will be automatically added if `has_header` + /// is true. + pub fn extract_from_raw_table< 'context > + ( + column_names : Vec< Cow< 'data, str > >, + has_header : bool, + rows : Vec< Vec< Cow< 'data, str > > >, + filter_col : &'context ( dyn FilterCol + 'context ), + filter_row : &'context ( dyn FilterRow + 'context ), + callback : impl for< 'a2 > FnOnce( &'a2 InputExtract< 'a2 > ) -> fmt::Result, + ) -> fmt::Result + { // let mcells = table.mcells(); let mut mcells_vis = [ 0 ; 2 ]; let mut mcells = [ 0 ; 2 ]; let mut mchars = [ 0 ; 2 ]; // key width, index - let mut key_to_ikey : HashMap< &'t CellKey, usize > = HashMap::new(); + let mut key_to_ikey : HashMap< Cow< 'data, str >, usize > = HashMap::new(); let mut col_descriptors : Vec< ColDescriptor< '_ > > = Vec::with_capacity( mcells[ 0 ] ); let mut row_descriptors : Vec< RowDescriptor > = Vec::with_capacity( mcells[ 1 ] ); - let mut has_header = false; - let mut data : Vec< Vec< ( Cow< 't, str >, [ usize ; 2 ] ) > > = Vec::new(); - let rows = table.rows(); + let mut data : Vec< Vec< ( Cow< 'data, str >, [ usize ; 2 ] ) > > = Vec::new(); let mut irow : usize = 0; let filter_col_need_args = filter_col.need_args(); // let filter_row_need_args = filter_row.need_args(); - let mut row_add = | row_iter : &'_ mut dyn _IteratorTrait< Item = ( &'t CellKey, Cow< 't, str > ) >, typ : LineType | + let mut row_add = | row_data : Vec< Cow< 'data, str > >, typ : LineType | { irow = row_descriptors.len(); @@ -413,18 +468,21 @@ mod private let mut ncol = 0; let mut ncol_vis = 0; - let fields : Vec< ( Cow< 't, str >, [ usize ; 2 ] ) > = row_iter + let fields : Vec< ( Cow< 'data, str >, [ usize ; 2 ] ) > = row_data + .into_iter() + .enumerate() .filter_map ( - | ( key, val ) | + | ( ikey, val ) | { + let key = &column_names[ ikey ]; let l = col_descriptors.len(); ncol += 1; if filter_col_need_args { - if !filter_col.filter_col( key.borrow() ) + if !filter_col.filter_col( key.as_ref() ) { return None; } @@ -442,7 +500,7 @@ mod private let sz = string::size( &val ); key_to_ikey - .entry( key ) + .entry( key.clone() ) .and_modify( | icol | { let col = &mut col_descriptors[ *icol ]; @@ -481,18 +539,9 @@ mod private // process header first - if let Some( header ) = table.header() + if has_header { - rows.len().checked_add( 1 ).expect( "Table has too many rows" ); - // assert!( header.len() <= usize::MAX, "Header of a table has too many cells" ); - has_header = true; - - let mut row2 = header.map( | ( key, title ) | - { - ( key, Cow::Borrowed( title ) ) - }); - - row_add( &mut row2, LineType::Header ); + row_add( column_names.clone(), LineType::Header ); } // Collect rows @@ -501,53 +550,14 @@ mod private { // assert!( row.cells().len() <= usize::MAX, "Row of a table has too many cells" ); - let mut row2 = row - .cells() - .map - ( - | ( key, val ) | - { - - let val = match val - { - Some( val ) => - { - val - } - None => - { - Cow::Borrowed( "" ) - } - }; - - return ( key, val ); - } - ); - - row_add( &mut row2, LineType::Regular ); + row_add( row, LineType::Regular ); } // calculate size in chars mchars[ 0 ] = col_descriptors.iter().fold( 0, | acc, col | acc + col.width ); mchars[ 1 ] = row_descriptors.iter().fold( 0, | acc, row | acc + if row.vis { row.height } else { 0 } ); - - // cook slices multi-matrix - - let mut slices_dim = [ 1, mcells[ 0 ], mcells[ 1 ] ]; - slices_dim[ 0 ] = row_descriptors - .iter() - .fold( 0, | acc : usize, row | acc.max( row.height ) ) - ; - - let slices_len = slices_dim[ 0 ] * slices_dim[ 1 ] * slices_dim[ 2 ]; - let slices : Vec< &str > = vec![ "" ; slices_len ]; - - // assert_eq!( mcells, mcells, r#"Incorrect multidimensional size of table - // mcells <> mcells - // {mcells:?} <> {mcells:?}"# ); - // println!( "mcells : {mcells:?} | mcells : {mcells:?} | mcells_vis : {mcells_vis:?}" ); - + let mut x = InputExtract::< '_ > { mcells, @@ -557,42 +567,16 @@ mod private row_descriptors, data, has_header, - slices_dim, - slices, }; - // extract slices - - let mut slices : Vec< &str > = vec![]; - std::mem::swap( &mut x.slices, &mut slices ); - - let mut irow : isize = -1; - for row_data in x.data.iter() + if x.data.len() > 0 { - - irow += 1; - for icol in 0 .. x.col_descriptors.len() { - let cell = &row_data[ icol ]; - string::lines( cell.0.as_ref() ) - .enumerate() - .for_each( | ( layer, s ) | - { - let md_index = [ layer, icol, irow as usize ]; - slices[ x.slices_dim.md_offset( md_index ) ] = s; - }) - ; - if irow == 0 - { - x.col_descriptors[ icol ].label = cell.0.as_ref(); - } + x.col_descriptors[ icol ].label = x.data[ 0 ][ icol ].0.as_ref(); } - } - std::mem::swap( &mut x.slices, &mut slices ); - return callback( &x ); } @@ -617,6 +601,8 @@ pub mod own Context, Printer, InputExtract, + RowDescriptor, + ColDescriptor, }; } @@ -658,4 +644,4 @@ pub mod prelude use super::*; } -// \ No newline at end of file +// diff --git a/module/core/format_tools/src/format/string.rs b/module/core/format_tools/src/format/string.rs index 511f44c473..ee34e9e718 100644 --- a/module/core/format_tools/src/format/string.rs +++ b/module/core/format_tools/src/format/string.rs @@ -4,7 +4,7 @@ // xxx : move to crate string_tools -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -114,6 +114,47 @@ mod private Lines::new( src.as_ref() ) } + /// Returns an iterator over the lines of a string slice with text wrapping. + /// + /// This function provides an iterator that yields each line of the input string slice. + /// It is based on previous iterator `lines` but it also includes text wrapping that is + /// controlled via `limit_width` argument. If the string contains a trailing new line, + /// then an empty string will be yielded in this iterator. + /// + /// # Arguments + /// + /// * `src` - A reference to a type that can be converted to a string slice. This allows + /// for flexibility in passing various string-like types. + /// + /// * `limit_width` - text wrapping limit. Lines that are longer than this parameter will + // be split into smaller lines. + /// + /// # Returns + /// + /// An iterator of type `LinesWithLimit` that yields each line as a `&str`. + /// + /// # Examples + /// + /// ``` + /// let text = "Hello\nWorld\n"; + /// let mut lines = format_tools::string::lines_with_limit( text, 3 ); + /// assert_eq!( lines.next(), Some( "Hel" ) ); + /// assert_eq!( lines.next(), Some( "lo" ) ); + /// assert_eq!( lines.next(), Some( "Wor" ) ); + /// assert_eq!( lines.next(), Some( "ld" ) ); + /// assert_eq!( lines.next(), Some( "" ) ); + /// assert_eq!( lines.next(), None ); + /// ``` + pub fn lines_with_limit< S : AsRef< str > + ?Sized > + ( + src : & S, + limit_width : usize + ) + -> LinesWithLimit< '_ > + { + LinesWithLimit::new( src.as_ref(), limit_width ) + } + /// An iterator over the lines of a string slice. /// /// This struct implements the `Iterator` trait, allowing you to iterate over the lines @@ -128,6 +169,7 @@ mod private has_trailing_newline : bool, finished : bool, } + impl< 'a > Lines< 'a > { fn new( input : &'a str ) -> Self @@ -172,6 +214,70 @@ mod private } } + /// An iterator over the lines of a string slice with text wrapping. + /// + /// This struct implements the `Iterator` trait, allowing you to iterate over the parts + /// of a string. It uses `Lines` iterator and splits lines if they are longer that the + /// `limit_width` parameter. If the string contains a trailing new line, then an empty + /// string will be yielded in this iterator. + /// + /// If `limit_width` is equal to 0, then no wrapping is applied, and behaviour of this + /// iterator is equals to `Lines` iterator. + #[ derive( Debug ) ] + pub struct LinesWithLimit< 'a > + { + lines : Lines< 'a >, + limit_width : usize, + cur : Option< &'a str >, + } + + impl< 'a > LinesWithLimit< 'a > + { + fn new( input : &'a str, limit_width : usize ) -> Self + { + LinesWithLimit + { + lines : lines( input ), + limit_width, + cur : None, + } + } + } + + impl< 'a > Iterator for LinesWithLimit< 'a > + { + type Item = &'a str; + + fn next( &mut self ) -> Option< Self::Item > + { + if self.cur.is_none() || self.cur.is_some_and( str::is_empty ) + { + self.cur = self.lines.next(); + } + + match self.cur + { + None => return None, + + Some( cur ) => + { + if self.limit_width == 0 + { + self.cur = None; + Some( cur ) + } + else + { + let (chunk, rest) = cur.split_at(self.limit_width.min(cur.len())); + self.cur = Some( rest ); + + Some(chunk) + } + } + } + } + } + } #[ allow( unused_imports ) ] @@ -191,6 +297,8 @@ pub mod own size, lines, Lines, + lines_with_limit, + LinesWithLimit, }; } diff --git a/module/core/format_tools/src/format/table.rs b/module/core/format_tools/src/format/table.rs index d3dc8bd71c..1fab2ab744 100644 --- a/module/core/format_tools/src/format/table.rs +++ b/module/core/format_tools/src/format/table.rs @@ -2,7 +2,7 @@ //! Table interface. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -12,7 +12,11 @@ mod private // fmt, borrow::Borrow, }; - use std::borrow::Cow; + use std:: + { + borrow::Cow, + collections::HashMap, + }; use reflect_tools:: { IteratorTrait, @@ -72,7 +76,7 @@ mod private // = - /// Marker trait to tag structures for whcih table trait deducing should be done from trait Fields, which is reflection. + /// Marker trait to tag structures for which table trait deducing should be done from trait Fields, which is reflection. pub trait TableWithFields {} // = @@ -92,6 +96,16 @@ mod private ; } + impl Cells< str > for HashMap< String, String > + { + fn cells< 'a, 'b >( &'a self ) -> impl IteratorTrait< Item = ( &'b str, Option< Cow< 'b, str > > ) > + where + 'a : 'b, + { + self.iter().map( | ( k, v ) | ( k.as_str(), Some( Cow::from( v ) ) ) ) + } + } + impl< Row, CellKey > Cells< CellKey > for Row where @@ -188,7 +202,7 @@ mod private > + 'k + 'v, RowKey : table::RowKey, - Row : TableWithFields + Cells< CellKey >, + Row : Cells< CellKey >, CellKey : table::CellKey + ?Sized, // CellRepr : table::CellRepr, { @@ -264,7 +278,7 @@ mod private where Self : TableRows< RowKey = RowKey, Row = Row, CellKey = CellKey >, RowKey : table::RowKey, - Row : TableWithFields + Cells< CellKey >, + Row : Cells< CellKey >, CellKey : table::CellKey + ?Sized, // CellRepr : table::CellRepr, { diff --git a/module/core/format_tools/src/format/text_wrap.rs b/module/core/format_tools/src/format/text_wrap.rs new file mode 100644 index 0000000000..695ac287cd --- /dev/null +++ b/module/core/format_tools/src/format/text_wrap.rs @@ -0,0 +1,256 @@ +//! +//! Text wrapping function. +//! + +/// Define a private namespace for all its items. +mod private +{ + + use std::borrow::Cow; + + use crate::*; + + /// Struct that represents a wrapped tabular data. It is similar to `InputExtract`, + /// but we cannot use it as it does not wrap the text and it contains wrong column + /// widthes and heights (as they are dependent on wrapping too). + #[ derive( Debug ) ] + pub struct WrappedInputExtract< 'data > + { + /// Tabular data of rows and columns. + /// Note: these cells does not represent the actual information cells in the + /// original table. These cells are wrapped and used only for displaying. This also + /// means that one row in original table can be represented here with one or more + /// rows. + pub data: Vec< Vec< WrappedCell< 'data > > >, + + /// New widthes of columns that include wrapping. + pub column_widthes : Vec< usize >, + + /// Size of the first row of the table. + /// This parameter is used in case header of the table should be displayed. + pub first_row_height : usize, + } + + /// Struct that represents a content of a wrapped cell. + /// It contains the slice of the cell as well as its original width. + /// + /// Parameter `wrap_width` is needed as text in `output_format::Table` is centered. + /// However it is centered according to whole cell size and not the size of wrapped + /// text slice. + /// + /// Example that depicts the importance of `wrap_width` parameter: + /// + /// 1) | [ | 2) | [ | + /// | line1, | | line1, | + /// | line2 | | line2 | + /// | ] | | ] | + /// + /// The first case seems to be properly formatted, while the second case took centering + /// too literally. That is why `wrap_width` is introduced, and additional spaces to the + /// right side should be included by the output formatter. + #[ derive( Debug ) ] + pub struct WrappedCell< 'data > + { + /// Width of the cell. In calculations use this width instead of slice length in order + /// to properly center the text. See example in the doc string of the parent struct. + pub wrap_width : usize, + + /// Actual content of the cell. + pub content : Cow< 'data, str > + } + + /// Wrap table cells. + /// + /// `InputExtract` contains cells with full content, so it represents the logical + /// structure of the table. `WrappedInputExtract` wraps original cells to smaller + /// cells. The resulting data is more low-level and corresponds to the table that + /// will be actually printed to the console (or other output type). + /// + /// `InputExtract` is not directly passed to this function, as it made to be general. + /// Instead you pass table cells in `data` argument and pass a vector of column widthes + /// in `columns_width_list` generated by `InputExtract`. + /// + /// `columns_width_list` is a slice, this is more effective and general than just a `Vec`. + /// In table style, there could be many columns, but in records style there will be + /// always 2 columns - this number is known at compile time, so we can use a slice object. + /// + /// Notice: + /// 1. Data passed to this function should contain only visible rows and columns. + /// It does not perform additional filtering. + /// 2. `data` parameters is **vector of rows of columns** (like and ordinary table). + /// This means that in styles like `Records` where headers and rows turned into columns + /// You have to transpose your data before passing it to this function. + /// + /// Wrapping is controlled by `columns_max_width` and `columns_nowrap_width` parameters. + /// + /// - `columns_max_width` is the size that is allowed to be occupied by columns. + /// It equals to maximum table width minus lengthes of visual elements (prefixes, + /// postfixes, separators, etc.). + /// + /// - `columns_nowrap_width` is the sum of column widthes of cells without wrapping (basically, + /// the sum of widthes of column descriptors in `InputExtract`). + /// + /// The function will perform wrapping and shrink the columns so that they occupy not + /// more than `columns_max_width`. + /// + /// If `columns_max_width` is equal to 0, then no wrapping will be performed. + pub fn text_wrap< 'data > + ( + data : impl Iterator< Item = &'data Vec< ( Cow< 'data, str >, [ usize; 2 ] ) > >, + columns_width_list : impl AsRef< [ usize ] >, + columns_max_width : usize, + columns_nowrap_width : usize, + ) + -> WrappedInputExtract< 'data > + { + let columns_width_list = columns_width_list.as_ref(); + + let mut first_row_height = 0; + let mut new_data = Vec::new(); + let mut column_widthes = Vec::new(); + + if columns_max_width == 0 || columns_max_width >= columns_nowrap_width + { + column_widthes.extend( columns_width_list.iter() ); + } + else + { + let shrink_factor : f32 = ( columns_max_width as f32 ) / ( columns_nowrap_width as f32 ); + + for ( icol, col_width ) in columns_width_list.iter().enumerate() + { + let col_limit_float = ( *col_width as f32 ) * shrink_factor; + let col_limit = col_limit_float.floor() as usize; + + let col_width_to_put = if icol == columns_width_list.len() - 1 + { + columns_max_width - column_widthes.iter().sum::() + } + else + { + col_limit.max(1) + }; + + column_widthes.push( col_width_to_put ); + } + } + + for ( irow, row ) in data.enumerate() + { + let mut wrapped_rows : Vec< Vec< Cow< 'data, str > > > = vec![]; + + for ( icol, col ) in row.iter().enumerate() + { + let col_limit = column_widthes[ icol ]; + let wrapped_col = string::lines_with_limit( col.0.as_ref(), col_limit ).map( Cow::from ).collect(); + wrapped_rows.push( wrapped_col ); + } + + let max_rows = wrapped_rows.iter().map( Vec::len ).max().unwrap_or(0); + + let mut transposed : Vec< Vec< WrappedCell< 'data > > > = Vec::new(); + + if max_rows == 0 + { + transposed.push( vec![] ); + } + + for i in 0..max_rows + { + let mut row_vec : Vec< WrappedCell< 'data > > = Vec::new(); + + for col_lines in &wrapped_rows + { + if col_lines.len() > i + { + let wrap_width = col_lines.iter().map( |c| c.len() ).max().unwrap_or(0); + row_vec.push( WrappedCell { wrap_width , content : col_lines[ i ].clone() } ); + } + else + { + row_vec.push( WrappedCell { wrap_width : 0, content : Cow::from( "" ) } ); + } + } + + transposed.push( row_vec ); + } + + if irow == 0 + { + first_row_height += transposed.len(); + } + + new_data.extend( transposed ); + } + + WrappedInputExtract + { + data: new_data, + first_row_height, + column_widthes + } + } + + /// Calculate width of the column without wrapping. + pub fn width_calculate< 'data > + ( + column : &'data Vec< ( Cow< 'data, str >, [ usize; 2 ] ) > + ) + -> usize + { + column.iter().map( |k| + { + string::lines( k.0.as_ref() ).map( |l| l.chars().count() ).max().unwrap_or( 0 ) + } ).max().unwrap_or( 0 ) + } + +} + +#[ allow( unused_imports ) ] +pub use own::*; + +/// Own namespace of the module. +#[ allow( unused_imports ) ] +pub mod own +{ + use super::*; + #[ doc( inline ) ] + pub use orphan::*; + + #[ doc( inline ) ] + pub use + { + }; + + #[ doc( inline ) ] + pub use private:: + { + text_wrap, + width_calculate, + }; + +} + +/// Orphan namespace of the module. +#[ allow( unused_imports ) ] +pub mod orphan +{ + use super::*; + #[ doc( inline ) ] + pub use exposed::*; +} + +/// Exposed namespace of the module. +#[ allow( unused_imports ) ] +pub mod exposed +{ + use super::*; + pub use super::super::output_format; +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; +} diff --git a/module/core/format_tools/src/format/to_string.rs b/module/core/format_tools/src/format/to_string.rs index 6446e90fa2..8bc9bb538f 100644 --- a/module/core/format_tools/src/format/to_string.rs +++ b/module/core/format_tools/src/format/to_string.rs @@ -2,7 +2,7 @@ //! Flexible ToString augmentation. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/core/format_tools/src/format/to_string_with_fallback.rs b/module/core/format_tools/src/format/to_string_with_fallback.rs index e79b827896..fb5966bf38 100644 --- a/module/core/format_tools/src/format/to_string_with_fallback.rs +++ b/module/core/format_tools/src/format/to_string_with_fallback.rs @@ -2,7 +2,7 @@ //! Flexible ToString augmentation. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::*; diff --git a/module/core/format_tools/tests/inc/collection_test.rs b/module/core/format_tools/tests/inc/collection_test.rs index 6b17ce0975..0d066004e2 100644 --- a/module/core/format_tools/tests/inc/collection_test.rs +++ b/module/core/format_tools/tests/inc/collection_test.rs @@ -401,3 +401,46 @@ fn llist_basic() } // qqq : xxx : implement for other containers + +#[ test ] +fn vec_of_hashmap() +{ + let data : Vec< HashMap< String, String > > = vec! + [ + { + let mut map = HashMap::new(); + map.insert( "id".to_string(), "1".to_string() ); + map.insert( "created_at".to_string(), "1627845583".to_string() ); + map + }, + { + let mut map = HashMap::new(); + map.insert( "id".to_string(), "2".to_string() ); + map.insert( "created_at".to_string(), "13".to_string() ); + map + }, + ]; + + use std::borrow::Cow; + + use the_module::TableFormatter; + + let _as_table : AsTable< '_, Vec< HashMap< String, String > >, &str, HashMap< String, String >, str> = AsTable::new( &data ); + let as_table = AsTable::new( &data ); + + let rows = TableRows::rows( &as_table ); + assert_eq!( rows.len(), 2 ); + + let mut output = String::new(); + let mut context = the_module::print::Context::new( &mut output, Default::default() ); + + let _got = the_module::TableFormatter::fmt( &as_table, &mut context ); + + let got = as_table.table_to_string(); + + println!("{}", got); + + assert!( got.contains( "│ id │ created_at │" ) || got.contains( "│ created_at │ id │" ) ); + assert!( got.contains( "│ 1 │ 1627845583 │" ) || got.contains( "│ 1627845583 │ 1 │" ) ); + assert!( got.contains( "│ 2 │ 13 │" ) || got.contains( "│ 13 │ 2 │" ) ); +} \ No newline at end of file diff --git a/module/core/format_tools/tests/inc/format_records_test.rs b/module/core/format_tools/tests/inc/format_records_test.rs index 72f23a5ff5..77b8de7364 100644 --- a/module/core/format_tools/tests/inc/format_records_test.rs +++ b/module/core/format_tools/tests/inc/format_records_test.rs @@ -316,4 +316,136 @@ fn filter_row_callback() // -// xxx : enable \ No newline at end of file +// xxx : enable + +#[ test ] +fn test_width_limiting() +{ + use the_module::string; + + for width in min_width()..max_width() + { + println!("width: {}", width); + + let test_objects = test_object::test_objects_gen(); + let as_table = AsTable::new( &test_objects ); + + let mut format = output_format::Records::default(); + format.max_width = width; + + let mut output = String::new(); + let printer = print::Printer::with_format( &format ); + let mut context = print::Context::new( &mut output, printer ); + + let got = the_module::TableFormatter::fmt( &as_table, &mut context ); + + assert!( got.is_ok() ); + + for line in string::lines( &output ) + { + if line.starts_with(" = ") + { + continue; + } + + if line.chars().count() > width + { + println!("{}", output); + } + + assert!( line.chars().count() <= width ); + } + } +} + +#[ test ] +fn test_error_on_unsatisfiable_limit() +{ + // 0 is a special value that signifies no limit. + for width in 1..( min_width() ) + { + println!( "width: {}", width ); + + let test_objects = test_object::test_objects_gen(); + let as_table = AsTable::new( &test_objects ); + + let mut format = output_format::Records::default(); + format.max_width = width; + + let mut output = String::new(); + let printer = print::Printer::with_format( &format ); + let mut context = print::Context::new( &mut output, printer ); + + let got = the_module::TableFormatter::fmt( &as_table, &mut context ); + + assert!( got.is_err() ); + } +} + +#[ test ] +fn test_table_not_grows() +{ + use the_module::string; + + let expected_width = max_width(); + + // The upper bound was chosen arbitrarily. + for width in ( expected_width + 1 )..500 + { + println!( "width: {}", width ); + + let test_objects = test_object::test_objects_gen(); + let as_table = AsTable::new( &test_objects ); + + let mut format = output_format::Records::default(); + format.max_width = width; + + let mut output = String::new(); + let printer = print::Printer::with_format( &format ); + let mut context = print::Context::new( &mut output, printer ); + + let got = the_module::TableFormatter::fmt( &as_table, &mut context ); + + assert!( got.is_ok() ); + println!("{}", output); + + for line in string::lines( &output ) + { + if line.starts_with(" = ") + { + continue; + } + + assert!( line.chars().count() <= expected_width ); + } + } +} + +/// Utility function for calculating minimum table width with `test_objects_gen()` with +/// the default table style. +fn min_width() -> usize +{ + let format = output_format::Records::default(); + format.min_width() +} + +/// Utility function for calculating default table width with `test_objects_gen()` with +/// the default table style with table width limit equals to 0. +fn max_width() -> usize +{ + use the_module::string; + + let test_objects = test_object::test_objects_gen(); + let as_table = AsTable::new( &test_objects ); + + let format = output_format::Records::default(); + + let mut output = String::new(); + let printer = print::Printer::with_format( &format ); + let mut context = print::Context::new( &mut output, printer ); + + let got = the_module::TableFormatter::fmt( &as_table, &mut context ); + assert!( got.is_ok() ); + + string::lines( &output ).map( |s| s.chars().count() ).max().unwrap_or(0) +} \ No newline at end of file diff --git a/module/core/format_tools/tests/inc/format_table_test.rs b/module/core/format_tools/tests/inc/format_table_test.rs index eb8a3b17dd..945696f572 100644 --- a/module/core/format_tools/tests/inc/format_table_test.rs +++ b/module/core/format_tools/tests/inc/format_table_test.rs @@ -326,3 +326,148 @@ fn filter_row_callback() // // xxx : implement test for vector of vectors + +// + +#[ test ] +fn no_subtract_with_overflow() +{ + let test_objects = test_object::test_objects_gen_with_unicode(); + + let format = output_format::Table::default(); + let printer = print::Printer::with_format( &format ); + + let as_table = AsTable::new( &test_objects ); + let mut output = String::new(); + let mut context = print::Context::new( &mut output, printer ); + + let result = the_module::TableFormatter::fmt( &as_table, &mut context ); + + assert!( result.is_ok() ); +} + +#[ test ] +fn test_width_limiting() +{ + use the_module::string; + + for max_width in min_width()..max_width() + { + println!("max_width: {}", max_width); + + let test_objects = test_object::test_objects_gen(); + let as_table = AsTable::new( &test_objects ); + + let mut format = output_format::Table::default(); + format.max_width = max_width; + + let mut output = String::new(); + let printer = print::Printer::with_format( &format ); + let mut context = print::Context::new( &mut output, printer ); + + let got = the_module::TableFormatter::fmt( &as_table, &mut context ); + + assert!( got.is_ok() ); + + for line in string::lines( &output ) + { + assert_eq!( max_width, line.chars().count() ); + } + } +} + +#[ test ] +fn test_error_on_unsatisfiable_limit() +{ + // 0 is a special value that signifies no limit. Therefore, the lower bound is 1. + for max_width in 1..( min_width() ) + { + println!( "max_width: {}", max_width ); + + let test_objects = test_object::test_objects_gen(); + let as_table = AsTable::new( &test_objects ); + + let mut format = output_format::Table::default(); + format.max_width = max_width; + + let mut output = String::new(); + let printer = print::Printer::with_format( &format ); + let mut context = print::Context::new( &mut output, printer ); + + let got = the_module::TableFormatter::fmt( &as_table, &mut context ); + + assert!( got.is_err() ); + } +} + +#[ test ] +fn test_table_not_grows() +{ + use the_module::string; + + let expected_width = max_width(); + + // The upper bound was chosen arbitrarily. + for max_width in ( expected_width + 1 )..500 + { + println!( "max_width: {}", max_width ); + + let test_objects = test_object::test_objects_gen(); + let as_table = AsTable::new( &test_objects ); + + let mut format = output_format::Table::default(); + format.max_width = max_width; + + let mut output = String::new(); + let printer = print::Printer::with_format( &format ); + let mut context = print::Context::new( &mut output, printer ); + + let got = the_module::TableFormatter::fmt( &as_table, &mut context ); + + assert!( got.is_ok() ); + + for line in string::lines( &output ) + { + assert_eq!( expected_width, line.chars().count() ); + } + } +} + +/// Utility function for calculating minimum table width with `test_objects_gen()` with +/// the default table style. +fn min_width() -> usize +{ + use the_module::Fields; + + let format = output_format::Table::default(); + let test_objects = test_object::test_objects_gen(); + let col_count = test_objects[0].fields().count(); + + format.min_width( col_count ) +} + +/// Utility function for calculating default table width with `test_objects_gen()` with +/// the default table style without any maximum width. +fn max_width() -> usize +{ + use the_module::string; + + let test_objects = test_object::test_objects_gen(); + let as_table = AsTable::new( &test_objects ); + + let format = output_format::Table::default(); + + let mut output = String::new(); + let printer = print::Printer::with_format( &format ); + let mut context = print::Context::new( &mut output, printer ); + + let got = the_module::TableFormatter::fmt( &as_table, &mut context ); + assert!( got.is_ok() ); + + for line in string::lines( &output ) + { + return line.chars().count(); + } + + 0 +} \ No newline at end of file diff --git a/module/core/format_tools/tests/inc/print_test.rs b/module/core/format_tools/tests/inc/print_test.rs new file mode 100644 index 0000000000..dd45f73de8 --- /dev/null +++ b/module/core/format_tools/tests/inc/print_test.rs @@ -0,0 +1,191 @@ +#[ allow( unused_imports ) ] +use super::*; + +use the_module:: +{ + Fields, + IteratorTrait, + AsTable, + Cells, + TableSize, + TableRows, + TableHeader, + Context, + WithRef, + MaybeAs, +}; + +use std:: +{ + collections::HashMap, + borrow::Cow, +}; + +/// Struct representing a test object with various fields. +#[ derive( Clone, Debug ) ] +pub struct TestObject +{ + pub id : String, + pub created_at : i64, + pub file_ids : Vec< String >, + pub tools : Option< Vec< HashMap< String, String > > >, +} + +impl Fields< &'static str, MaybeAs< '_, str, WithRef > > +for TestObject +{ + type Value< 'v > = MaybeAs< 'v, str, WithRef >; + + fn fields( &self ) -> impl IteratorTrait< Item = ( &'static str, MaybeAs< '_, str, WithRef > ) > + { + // use format_tools::ref_or_display_or_debug_multiline::field; + use format_tools::ref_or_display_or_debug::field; + let mut dst : Vec< ( &'static str, MaybeAs< '_, str, WithRef > ) > = Vec::new(); + + dst.push( field!( &self.id ) ); + dst.push( field!( &self.created_at ) ); + dst.push( field!( &self.file_ids ) ); + + if let Some( tools ) = &self.tools + { + dst.push( field!( tools ) ); + } + else + { + dst.push( ( "tools", MaybeAs::none() ) ); + } + + dst.into_iter() + } +} + +// + +fn test_objects_gen() -> Vec< TestObject > +{ + + vec! + [ + TestObject + { + id : "1".to_string(), + created_at : 1627845583, + file_ids : vec![ "file1".to_string(), "file2".to_string() ], + tools : None + }, + TestObject + { + id : "2".to_string(), + created_at : 13, + file_ids : vec![ "file3".to_string(), "file4\nmore details".to_string() ], + tools : Some + ( + vec! + [ + { + let mut map = HashMap::new(); + map.insert( "tool1".to_string(), "value1".to_string() ); + map + }, + { + let mut map = HashMap::new(); + map.insert( "tool2".to_string(), "value2".to_string() ); + map + } + ] + ), + }, + ] + +} + +// + +#[ test ] +fn table_to_string() +// where + // for< 'a > AsTable< 'a, Vec< TestObject >, usize, TestObject, &'static str, String, &'static str > : TableFormatter< 'a >, +{ + use the_module::TableToString; + let test_objects = test_objects_gen(); + + let cells = Cells::< &'static str, WithRef >::cells( &test_objects[ 0 ] ); + assert_eq!( cells.len(), 4 ); + let cells = Cells::< &'static str, WithRef >::cells( &test_objects[ 1 ] ); + assert_eq!( cells.len(), 4 ); + drop( cells ); + + let as_table : AsTable< '_, Vec< TestObject >, usize, TestObject, &str, WithRef > = AsTable::new( &test_objects ); + let size = TableSize::mcells( &as_table ); + assert_eq!( size, [ 2, 4 ] ); + let rows = TableRows::rows( &as_table ); + assert_eq!( rows.len(), 2 ); + dbg!( rows.collect::< Vec< _ > >() ); + let header = TableHeader::header( &as_table ); + assert!( header.is_some() ); + let header = header.unwrap(); + assert_eq!( header.len(), 4 ); + assert_eq!( header.clone().collect::< Vec< _ > >(), vec! + [ + ( "id", Cow::Owned( "id".to_string() ) ), + ( "created_at", Cow::Owned( "created_at".to_string() ) ), + ( "file_ids", Cow::Owned( "file_ids".to_string() ) ), + ( "tools", Cow::Owned( "tools".to_string() ) ) + ]); + dbg!( header.collect::< Vec< _ > >() ); + + let mut output = String::new(); + let mut context = Context::new( &mut output, Default::default() ); + let got = the_module::TableFormatter::fmt( &as_table, &mut context ); + assert!( got.is_ok() ); + println!( "{}", &output ); + + // with explicit arguments + + let as_table : AsTable< '_, Vec< TestObject >, usize, TestObject, &str, WithRef > = AsTable::new( &test_objects ); + let table_string = as_table.table_to_string(); + assert!( table_string.contains( "id" ) ); + assert!( table_string.contains( "created_at" ) ); + assert!( table_string.contains( "file_ids" ) ); + assert!( table_string.contains( "tools" ) ); + + // without explicit arguments + + println!( "" ); + let as_table = AsTable::new( &test_objects ); + let table_string = as_table.table_to_string(); + assert!( table_string.contains( "id" ) ); + assert!( table_string.contains( "created_at" ) ); + assert!( table_string.contains( "file_ids" ) ); + assert!( table_string.contains( "tools" ) ); + println!( "{table_string}" ); + +} + +#[ test ] +fn custom_formatter() +{ + // use the_module::TableToString; + let test_objects = test_objects_gen(); + + let mut output = String::new(); + let mut formatter = the_module::Styles::default(); + formatter.cell_separator = " | ".into(); + formatter.row_prefix = "> ".into(); + formatter.row_postfix = " <".into(); + + let as_table = AsTable::new( &test_objects ); + let mut context = Context::new( &mut output, formatter ); + let got = the_module::TableFormatter::fmt( &as_table, &mut context ); + assert!( got.is_ok() ); + // let table_string = got.unwrap(); + + assert!( output.contains( "id" ) ); + assert!( output.contains( "created_at" ) ); + assert!( output.contains( "file_ids" ) ); + assert!( output.contains( "tools" ) ); + println!( "{output}" ); + +} + +// xxx diff --git a/module/core/format_tools/tests/inc/table_test.rs b/module/core/format_tools/tests/inc/table_test.rs index c5fd38a8e9..af57655085 100644 --- a/module/core/format_tools/tests/inc/table_test.rs +++ b/module/core/format_tools/tests/inc/table_test.rs @@ -298,3 +298,62 @@ fn iterator_over_strings() // assert!( got.contains( "│ 1627845583 │ [ │ │" ) ); } + +#[ test ] +fn test_vector_table() +{ + let column_names : Vec< Cow< 'static, str > > = vec![ + "id".into(), + "created_at".into(), + "file_ids".into(), + "tools".into(), + ]; + + let rows : Vec< Vec< Cow< 'static, str > > > = vec! + [ + vec! + [ + "1".into(), + "1627845583".into(), + "[ file1, file2 ]".into(), + "".into(), + ], + + vec! + [ + "2".into(), + "13".into(), + "[ file3, file4 ]".into(), + "[ tool1 ]".into(), + ], + ]; + + use the_module:: + { + output_format, + filter, + print, + }; + + let mut output = String::new(); + let mut context = print::Context::new( &mut output, Default::default() ); + + let res = output_format::vector_table_write + ( + column_names, + true, + rows, + &mut context, + ); + + assert!( res.is_ok() ); + + println!( "{}", output ); + + let exp = r#"│ id │ created_at │ file_ids │ tools │ +────────────────────────────────────────────────── +│ 1 │ 1627845583 │ [ file1, file2 ] │ │ +│ 2 │ 13 │ [ file3, file4 ] │ [ tool1 ] │"#; + + a_id!( output.as_str(), exp ); +} \ No newline at end of file diff --git a/module/core/format_tools/tests/inc/test_object.rs b/module/core/format_tools/tests/inc/test_object.rs index f710266a4d..70c702d035 100644 --- a/module/core/format_tools/tests/inc/test_object.rs +++ b/module/core/format_tools/tests/inc/test_object.rs @@ -200,3 +200,17 @@ pub fn test_objects_gen() -> Vec< TestObject > ] } + +pub fn test_objects_gen_with_unicode() -> Vec< TestObject > +{ + vec! + [ + TestObject + { + id : "Юнікод".to_string(), + created_at : 100, + file_ids : vec![], + tools : None, + } + ] +} \ No newline at end of file diff --git a/module/core/format_tools/tests/inc/to_string_with_fallback_test.rs b/module/core/format_tools/tests/inc/to_string_with_fallback_test.rs index bd9947cd71..e0c39527c3 100644 --- a/module/core/format_tools/tests/inc/to_string_with_fallback_test.rs +++ b/module/core/format_tools/tests/inc/to_string_with_fallback_test.rs @@ -9,12 +9,12 @@ use the_module:: WithDebug, WithDisplay, // the_module::to_string_with_fallback::Ref, - to_string_with_fallback, + to_string_with_fallback }; use std:: { - // fmt, + fmt, // collections::HashMap, borrow::Cow, }; diff --git a/module/core/format_tools/tests/tests.rs b/module/core/format_tools/tests/tests.rs index 4fca6dbc07..c8e636300b 100644 --- a/module/core/format_tools/tests/tests.rs +++ b/module/core/format_tools/tests/tests.rs @@ -1,6 +1,6 @@ //! Primary tests. -#![ feature( trace_macros ) ] +// #![ feature( trace_macros ) ] #![ allow( unused_imports ) ] use format_tools as the_module; diff --git a/module/core/former/Readme.md b/module/core/former/Readme.md index d36ce4b061..0e429ab46b 100644 --- a/module/core/former/Readme.md +++ b/module/core/former/Readme.md @@ -23,7 +23,7 @@ This approach abstracts away the need for manually implementing a builder for ea ## Comparison -The Former crate and the abstract Builder pattern concept share a common goal: to construct complex objects step-by-step, ensuring they are always in a valid state and hiding internal structures. Both use a fluent interface for setting fields and support default values for fields that aren't explicitly set. They also have a finalization method to return the constructed object (.form() in Former, build() in [traditional Builder](https://refactoring.guru/design-patterns/builder)). +The Former crate and the abstract Builder pattern concept share a common goal: to construct complex objects step-by-step, ensuring they are always in a valid state and hiding internal structures. Both use a fluent interface for setting fields and support default values for fields that aren't explicitly set. They also have a finalization method to return the constructed object (`.form()` in Former, `build()` in [traditional Builder](https://refactoring.guru/design-patterns/builder)). However, the Former crate extends the traditional Builder pattern by automating the generation of builder methods using macros. This eliminates the need for manual implementation, which is often required in the abstract concept. Additionally, Former supports nested builders and subformers for complex data structures, allowing for more sophisticated object construction. @@ -660,7 +660,7 @@ Storage is not just a passive collection; it is an active part of a larger ecosy - **Former as an Active Manager**: The former is responsible for managing the storage, utilizing it to keep track of the object's evolving configuration. It orchestrates the formation process by handling intermediate states and preparing the object for its final form. - **Contextual Flexibility**: The context associated with the former adds an additional layer of flexibility, allowing the former to adjust its behavior based on the broader circumstances of the object's formation. This is particularly useful when the forming process involves conditions or states external to the object itself. -- **FormingEnd Callback**: The `FormingEnd` callback is a dynamic component that defines the final steps of the forming process. It can modify the storage based on final adjustments, validate the object's readiness, or integrate the object into a larger structure, such as embedding it as a subformer within another structure. +- **`FormingEnd` Callback**: The `FormingEnd` callback is a dynamic component that defines the final steps of the forming process. It can modify the storage based on final adjustments, validate the object's readiness, or integrate the object into a larger structure, such as embedding it as a subformer within another structure. These elements work in concert to ensure that the forming process is not only about building an object step-by-step but also about integrating it seamlessly into larger, more complex structures or systems. diff --git a/module/core/former/src/lib.rs b/module/core/former/src/lib.rs index 635a8e85e0..b692c6e9b6 100644 --- a/module/core/former/src/lib.rs +++ b/module/core/former/src/lib.rs @@ -22,6 +22,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -35,6 +36,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -45,6 +47,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] diff --git a/module/core/former_meta/Readme.md b/module/core/former_meta/Readme.md index 716940ba96..1fa3cb805f 100644 --- a/module/core/former_meta/Readme.md +++ b/module/core/former_meta/Readme.md @@ -1,13 +1,13 @@ -# Module :: former_meta +# Module :: `former_meta` [![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_former_meta_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_former_meta_push.yml) [![docs.rs](https://img.shields.io/docsrs/former_meta?color=e3e8f0&logo=docs.rs)](https://docs.rs/former_meta) [![discord](https://img.shields.io/discord/872391416519737405?color=eee&logo=discord&logoColor=eee&label=ask)](https://discord.gg/m3YfbXpUUY) -A flexible implementation of the Builder pattern supporting nested builders and collection-specific subformers. Implementation of its derive macro. Should not be used independently, instead use module::former which relies on the module. +A flexible implementation of the Builder pattern supporting nested builders and collection-specific subformers. Implementation of its derive macro. Should not be used independently, instead use `module::former` which relies on the module. -Not intended to be used without runtime. This module and runtime is aggregate in module::former is [here](https://github.com/Wandalen/wTools/tree/master/module/core/former). +Not intended to be used without runtime. This module and runtime is aggregate in `module::former` is [here](https://github.com/Wandalen/wTools/tree/master/module/core/former). ### To add to your project diff --git a/module/core/former_meta/src/component/component_assign.rs b/module/core/former_meta/src/component/component_assign.rs index de12fc7f5f..951e385778 100644 --- a/module/core/former_meta/src/component/component_assign.rs +++ b/module/core/former_meta/src/component/component_assign.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools::{ attr, diag, Result }; diff --git a/module/core/former_meta/src/component/component_from.rs b/module/core/former_meta/src/component/component_from.rs index c5613a48fa..c366ef3b1c 100644 --- a/module/core/former_meta/src/component/component_from.rs +++ b/module/core/former_meta/src/component/component_from.rs @@ -1,4 +1,4 @@ - +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools::{ attr, diag, Result }; diff --git a/module/core/former_meta/src/component/components_assign.rs b/module/core/former_meta/src/component/components_assign.rs index 6b495e7629..3716ef2161 100644 --- a/module/core/former_meta/src/component/components_assign.rs +++ b/module/core/former_meta/src/component/components_assign.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools::{ attr, diag, Result, format_ident }; use iter_tools::{ Itertools }; @@ -44,7 +45,7 @@ pub fn components_assign( input : proc_macro::TokenStream ) -> Result< proc_macr let component_assigns : Vec< _ > = component_assigns.into_iter().collect::< Result< _ > >()?; // code - let doc = format!( "Interface to assign instance from set of components exposed by a single argument." ); + let doc = "Interface to assign instance from set of components exposed by a single argument.".to_string(); let trait_bounds = qt! { #( #bounds1 )* IntoT : Clone }; let impl_bounds = qt! { #( #bounds2 )* #( #bounds1 )* IntoT : Clone }; let component_assigns = qt! { #( #component_assigns )* }; @@ -75,7 +76,7 @@ pub fn components_assign( input : proc_macro::TokenStream ) -> Result< proc_macr if has_debug { - let about = format!( "derive : ComponentsAssign\nstructure : {0}", item_name ); + let about = format!( "derive : ComponentsAssign\nstructure : {item_name}" ); diag::report_print( about, &original_input, &result ); } @@ -96,6 +97,7 @@ pub fn components_assign( input : proc_macro::TokenStream ) -> Result< proc_macr /// IntoT : Into< i32 > /// ``` /// +#[ allow( clippy::unnecessary_wraps ) ] fn generate_trait_bounds( field_type : &syn::Type ) -> Result< proc_macro2::TokenStream > { Ok @@ -116,6 +118,7 @@ fn generate_trait_bounds( field_type : &syn::Type ) -> Result< proc_macro2::Toke /// T : former::Assign< i32, IntoT >, /// ``` /// +#[ allow( clippy::unnecessary_wraps ) ] fn generate_impl_bounds( field_type : &syn::Type ) -> Result< proc_macro2::TokenStream > { Ok @@ -137,6 +140,7 @@ fn generate_impl_bounds( field_type : &syn::Type ) -> Result< proc_macro2::Token /// former::Assign::< i32, _ >::assign( self.component.clone() ); /// ``` /// +#[ allow( clippy::unnecessary_wraps ) ] fn generate_component_assign_call( field : &syn::Field ) -> Result< proc_macro2::TokenStream > { // let field_name = field.ident.as_ref().expect( "Expected the field to have a name" ); diff --git a/module/core/former_meta/src/component/from_components.rs b/module/core/former_meta/src/component/from_components.rs index d76029ca0a..c496ea15d9 100644 --- a/module/core/former_meta/src/component/from_components.rs +++ b/module/core/former_meta/src/component/from_components.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools::{ attr, diag, item_struct, Result }; @@ -78,7 +79,7 @@ pub fn from_components( input : proc_macro::TokenStream ) -> Result< proc_macro2 // diag::report_print( "derive : FromComponents", original_input, &result ); // } - Ok( result.into() ) + Ok( result ) } /// Generates trait bounds for the `From< T >` implementation, ensuring that `T` diff --git a/module/core/former_meta/src/derive_former.rs b/module/core/former_meta/src/derive_former.rs index b4d163608e..4a4515c199 100644 --- a/module/core/former_meta/src/derive_former.rs +++ b/module/core/former_meta/src/derive_former.rs @@ -1,4 +1,4 @@ - +#[ allow( clippy::wildcard_imports ) ] use super::*; use iter_tools::{ Itertools }; use macro_tools::{ attr, diag, generic_params, generic_args, typ, derive, Result }; @@ -7,10 +7,13 @@ use proc_macro2::TokenStream; // qqq : implement interfaces for other collections mod field_attrs; +#[ allow( clippy::wildcard_imports ) ] use field_attrs::*; mod field; +#[ allow( clippy::wildcard_imports ) ] use field::*; mod struct_attrs; +#[ allow( clippy::wildcard_imports ) ] use struct_attrs::*; /// Generates the code for implementing the `FormerMutator` trait for a specified former definition type. @@ -40,7 +43,7 @@ use struct_attrs::*; /// } /// ``` /// - +#[ allow( clippy::format_in_format_args, clippy::unnecessary_wraps ) ] pub fn mutator ( item : &syn::Ident, @@ -114,20 +117,18 @@ fn doc_generate( item : &syn::Ident ) -> ( String, String ) let doc_former_mod = format! ( -r#" Implementation of former for [{}]. -"#, - item +r#" Implementation of former for [{item}]. +"# ); let doc_former_struct = format! ( r#" -Structure to form [{}]. Represents a forming entity designed to construct objects through a builder pattern. +Structure to form [{item}]. Represents a forming entity designed to construct objects through a builder pattern. This structure holds temporary storage and context during the formation process and utilizes a defined end strategy to finalize the object creation. -"#, - item +"# ); ( doc_former_mod, doc_former_struct ) @@ -138,7 +139,7 @@ utilizes a defined end strategy to finalize the object creation. /// /// Output examples can be found in [docs to former crate](https://docs.rs/former/latest/former/) /// - +#[ allow( clippy::too_many_lines ) ] pub fn former( input : proc_macro::TokenStream ) -> Result< TokenStream > { use macro_tools::IntoGenericArgs; @@ -185,7 +186,7 @@ specific needs of the broader forming context. It mandates the implementation of { < (), #item < #struct_generics_ty >, former::ReturnPreformed > }; - let former_definition_args = generic_args::merge( &generics.into_generic_args(), &extra.into() ).args; + let former_definition_args = generic_args::merge( &generics.into_generic_args(), &extra ).args; /* parameters for former */ @@ -196,7 +197,7 @@ specific needs of the broader forming context. It mandates the implementation of Definition : former::FormerDefinition< Storage = #former_storage < #struct_generics_ty > >, Definition::Types : former::FormerDefinitionTypes< Storage = #former_storage < #struct_generics_ty > >, }; - let extra = generic_params::merge( &generics, &extra.into() ); + let extra = generic_params::merge( generics, &extra.into() ); let ( former_generics_with_defaults, former_generics_impl, former_generics_ty, former_generics_where ) = generic_params::decompose( &extra ); @@ -218,7 +219,7 @@ specific needs of the broader forming context. It mandates the implementation of Formed = #item < #struct_generics_ty >, >, }; - let extra = generic_params::merge( &generics, &extra.into() ); + let extra = generic_params::merge( generics, &extra.into() ); let ( _former_perform_generics_with_defaults, former_perform_generics_impl, former_perform_generics_ty, former_perform_generics_where ) = generic_params::decompose( &extra ); @@ -229,7 +230,7 @@ specific needs of the broader forming context. It mandates the implementation of { < __Context = (), __Formed = #item < #struct_generics_ty > > }; - let former_definition_types_generics = generic_params::merge( &generics, &extra.into() ); + let former_definition_types_generics = generic_params::merge( generics, &extra.into() ); let ( former_definition_types_generics_with_defaults, former_definition_types_generics_impl, former_definition_types_generics_ty, former_definition_types_generics_where ) = generic_params::decompose( &former_definition_types_generics ); @@ -241,7 +242,7 @@ specific needs of the broader forming context. It mandates the implementation of { < __Context = (), __Formed = #item < #struct_generics_ty >, __End = former::ReturnPreformed > }; - let generics_of_definition = generic_params::merge( &generics, &extra.into() ); + let generics_of_definition = generic_params::merge( generics, &extra.into() ); let ( former_definition_generics_with_defaults, former_definition_generics_impl, former_definition_generics_ty, former_definition_generics_where ) = generic_params::decompose( &generics_of_definition ); @@ -294,7 +295,7 @@ specific needs of the broader forming context. It mandates the implementation of field.storage_field_preform(), field.former_field_setter ( - &item, + item, &original_input, &struct_generics_impl, &struct_generics_ty, @@ -317,7 +318,7 @@ specific needs of the broader forming context. It mandates the implementation of let former_mutator_code = mutator ( - &item, + item, &original_input, &struct_attrs.mutator, &former_definition_types, diff --git a/module/core/former_meta/src/derive_former/field.rs b/module/core/former_meta/src/derive_former/field.rs index 089470ea84..98edaccf49 100644 --- a/module/core/former_meta/src/derive_former/field.rs +++ b/module/core/former_meta/src/derive_former/field.rs @@ -1,4 +1,4 @@ - +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools::{ container_kind }; @@ -26,22 +26,22 @@ impl< 'a > FormerField< 'a > /** methods -from_syn +`from_syn` -storage_fields_none -storage_field_optional -storage_field_preform -storage_field_name -former_field_setter -scalar_setter -subform_entry_setter -subform_collection_setter +`storage_fields_none` +`storage_field_optional` +`storage_field_preform` +`storage_field_name` +`former_field_setter` +`scalar_setter` +`subform_entry_setter` +`subform_collection_setter` -scalar_setter_name -subform_scalar_setter_name, -subform_collection_setter_name -subform_entry_setter_name -scalar_setter_required +`scalar_setter_name` +`subform_scalar_setter_name`, +`subform_collection_setter_name` +`subform_entry_setter_name` +`scalar_setter_required` */ @@ -173,6 +173,7 @@ scalar_setter_required /// #[ inline( always ) ] + #[ allow( clippy::unnecessary_wraps ) ] pub fn storage_field_preform( &self ) -> Result< TokenStream > { @@ -228,7 +229,7 @@ scalar_setter_required { None => { - let panic_msg = format!( "Field '{}' isn't initialized", ident ); + let panic_msg = format!( "Field '{ident}' isn't initialized" ); qt! { { @@ -327,6 +328,7 @@ scalar_setter_required /// #[ inline ] + #[ allow( clippy::too_many_arguments ) ] pub fn former_field_setter ( &self, @@ -376,7 +378,7 @@ scalar_setter_required }; // subform collection setter - let ( setters_code, namespace_code ) = if let Some( _ ) = &self.attrs.subform_collection + let ( setters_code, namespace_code ) = if self.attrs.subform_collection.is_some() { let ( setters_code2, namespace_code2 ) = self.subform_collection_setter ( @@ -421,9 +423,9 @@ scalar_setter_required } /// - /// Generate a single scalar setter for the 'field_ident' with the 'setter_name' name. + /// Generate a single scalar setter for the '`field_ident`' with the '`setter_name`' name. /// - /// Used as a helper function for former_field_setter(), which generates alias setters + /// Used as a helper function for `former_field_setter()`, which generates alias setters /// /// # Example of generated code /// @@ -441,6 +443,7 @@ scalar_setter_required /// ``` #[ inline ] + #[ allow( clippy::format_in_format_args ) ] pub fn scalar_setter ( &self, @@ -494,8 +497,7 @@ field : {field_ident}"#, let doc = format! ( - "Scalar setter for the '{}' field.", - field_ident, + "Scalar setter for the '{field_ident}' field.", ); qt! @@ -515,12 +517,13 @@ field : {field_ident}"#, } /// - /// Generate a collection setter for the 'field_ident' with the 'setter_name' name. + /// Generate a collection setter for the '`field_ident`' with the '`setter_name`' name. /// /// See `tests/inc/former_tests/subform_collection_manual.rs` for example of generated code. /// #[ inline ] + #[ allow( clippy::too_many_lines, clippy::too_many_arguments ) ] pub fn subform_collection_setter ( &self, @@ -537,8 +540,9 @@ field : {field_ident}"#, let attr = self.attrs.subform_collection.as_ref().unwrap(); let field_ident = &self.ident; let field_typ = &self.non_optional_ty; - let params = typ::type_parameters( &field_typ, .. ); + let params = typ::type_parameters( field_typ, &( .. ) ); + #[ allow( clippy::useless_attribute, clippy::items_after_statements ) ] use convert_case::{ Case, Casing }; // example : `ParentSubformCollectionChildrenEnd` @@ -584,10 +588,7 @@ field : {field_ident}"#, let doc = format! ( - "Collection setter for the '{}' field. Method {} unlike method {} accept custom collection subformer.", - field_ident, - subform_collection, - field_ident, + "Collection setter for the '{field_ident}' field. Method {subform_collection} unlike method {field_ident} accept custom collection subformer." ); let setter1 = @@ -754,7 +755,7 @@ with the new content generated during the subforming process. format!( "{}", qt!{ #field_typ } ), ); - let subformer_definition_types = if let Some( ref _subformer_definition ) = subformer_definition + let subformer_definition_types = if let Some( _subformer_definition ) = subformer_definition { let subformer_definition_types_string = format!( "{}Types", qt!{ #subformer_definition } ); let subformer_definition_types : syn::Type = syn::parse_str( &subformer_definition_types_string )?; @@ -856,6 +857,7 @@ with the new content generated during the subforming process. /// #[ inline ] + #[ allow( clippy::format_in_format_args, clippy::too_many_lines, clippy::too_many_arguments ) ] pub fn subform_entry_setter ( &self, @@ -1146,6 +1148,7 @@ formation process of the `{item}`. /// See `tests/inc/former_tests/subform_scalar_manual.rs` for example of generated code. #[ inline ] + #[ allow( clippy::format_in_format_args, clippy::unnecessary_wraps, clippy::too_many_lines, clippy::too_many_arguments ) ] pub fn subform_scalar_setter ( &self, @@ -1490,12 +1493,12 @@ Essentially, this end action integrates the individually formed scalar value bac { if let Some( ref attr ) = self.attrs.scalar { - if let Some( ref name ) = attr.name.ref_internal() + if let Some( name ) = attr.name.ref_internal() { return name } } - return &self.ident; + self.ident } /// Get name of setter for subform scalar if such setter should be generated. @@ -1505,17 +1508,14 @@ Essentially, this end action integrates the individually formed scalar value bac { if attr.setter() { - if let Some( ref name ) = attr.name.ref_internal() + if let Some( name ) = attr.name.ref_internal() { - return Some( &name ) - } - else - { - return Some( &self.ident ) + return Some( name ) } + return Some( self.ident ) } } - return None; + None } /// Get name of setter for collection if such setter should be generated. @@ -1525,17 +1525,14 @@ Essentially, this end action integrates the individually formed scalar value bac { if attr.setter() { - if let Some( ref name ) = attr.name.ref_internal() - { - return Some( &name ) - } - else + if let Some( name ) = attr.name.ref_internal() { - return Some( &self.ident ) + return Some( name ) } + return Some( self.ident ) } } - return None; + None } /// Get name of setter for subform if such setter should be generated. @@ -1547,15 +1544,12 @@ Essentially, this end action integrates the individually formed scalar value bac { if let Some( ref name ) = attr.name.as_ref() { - return Some( &name ) - } - else - { - return Some( &self.ident ) + return Some( name ) } + return Some( self.ident ) } } - return None; + None } /// Is scalar setter required. Does not if collection of subformer setter requested. @@ -1567,13 +1561,13 @@ Essentially, this end action integrates the individually formed scalar value bac { if let Some( setter ) = attr.setter.internal() { - if setter == false + if !setter { return false } explicit = true; } - if let Some( ref _name ) = attr.name.ref_internal() + if let Some( _name ) = attr.name.ref_internal() { explicit = true; } @@ -1594,7 +1588,7 @@ Essentially, this end action integrates the individually formed scalar value bac return false; } - return true; + true } } diff --git a/module/core/former_meta/src/derive_former/field_attrs.rs b/module/core/former_meta/src/derive_former/field_attrs.rs index a662fe20ae..7f97619d9a 100644 --- a/module/core/former_meta/src/derive_former/field_attrs.rs +++ b/module/core/former_meta/src/derive_former/field_attrs.rs @@ -1,5 +1,5 @@ //! Attributes of a field. - +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools:: { @@ -85,7 +85,7 @@ impl FieldAttributes { // Get the attribute key as a string let key_ident = attr.path().get_ident().ok_or_else( || error( attr ) )?; - let key_str = format!( "{}", key_ident ); + let key_str = format!( "{key_ident}" ); // // Skip standard attributes // if attr::is_standard( &key_str ) @@ -102,7 +102,7 @@ impl FieldAttributes AttributeSubformScalarSetter::KEYWORD => result.assign( AttributeSubformScalarSetter::from_meta( attr )? ), AttributeSubformCollectionSetter::KEYWORD => result.assign( AttributeSubformCollectionSetter::from_meta( attr )? ), AttributeSubformEntrySetter::KEYWORD => result.assign( AttributeSubformEntrySetter::from_meta( attr )? ), - "debug" => {}, + // "debug" => {}, _ => {}, // _ => return Err( error( attr ) ), // attributes does not have to be known @@ -134,6 +134,7 @@ impl AttributeComponent for AttributeConfig const KEYWORD : &'static str = "former"; + #[ allow( clippy::match_wildcard_for_single_variants ) ] fn from_meta( attr : &syn::Attribute ) -> Result< Self > { match attr.meta @@ -144,7 +145,7 @@ impl AttributeComponent for AttributeConfig }, syn::Meta::Path( ref _path ) => { - syn::parse2::< AttributeConfig >( Default::default() ) + syn::parse2::< AttributeConfig >( TokenStream::default() ) }, _ => return_syn_err!( attr, "Expects an attribute of format #[ former( default = 13 ) ].\nGot: {}", qt!{ #attr } ), } @@ -270,6 +271,7 @@ impl AttributeComponent for AttributeScalarSetter const KEYWORD : &'static str = "scalar"; + #[ allow( clippy::match_wildcard_for_single_variants ) ] fn from_meta( attr : &syn::Attribute ) -> Result< Self > { match attr.meta @@ -280,7 +282,7 @@ impl AttributeComponent for AttributeScalarSetter }, syn::Meta::Path( ref _path ) => { - syn::parse2::< AttributeScalarSetter >( Default::default() ) + syn::parse2::< AttributeScalarSetter >( TokenStream::default() ) }, _ => return_syn_err!( attr, "Expects an attribute of format `#[ scalar( setter = false ) ]` or `#[ scalar( setter = true, name = my_name ) ]`. \nGot: {}", qt!{ #attr } ), } @@ -445,6 +447,7 @@ impl AttributeComponent for AttributeSubformScalarSetter const KEYWORD : &'static str = "subform_scalar"; + #[ allow( clippy::match_wildcard_for_single_variants ) ] fn from_meta( attr : &syn::Attribute ) -> Result< Self > { match attr.meta @@ -455,7 +458,7 @@ impl AttributeComponent for AttributeSubformScalarSetter }, syn::Meta::Path( ref _path ) => { - syn::parse2::< AttributeSubformScalarSetter >( Default::default() ) + syn::parse2::< AttributeSubformScalarSetter >( TokenStream::default() ) }, _ => return_syn_err!( attr, "Expects an attribute of format `#[ subform_scalar( setter = false ) ]` or `#[ subform_scalar( setter = true, name = my_name ) ]`. \nGot: {}", qt!{ #attr } ), } @@ -622,6 +625,7 @@ impl AttributeComponent for AttributeSubformCollectionSetter const KEYWORD : &'static str = "subform_collection"; + #[ allow( clippy::match_wildcard_for_single_variants ) ] fn from_meta( attr : &syn::Attribute ) -> Result< Self > { match attr.meta @@ -632,7 +636,7 @@ impl AttributeComponent for AttributeSubformCollectionSetter }, syn::Meta::Path( ref _path ) => { - syn::parse2::< AttributeSubformCollectionSetter >( Default::default() ) + syn::parse2::< AttributeSubformCollectionSetter >( TokenStream::default() ) }, _ => return_syn_err!( attr, "Expects an attribute of format `#[ subform_collection ]` or `#[ subform_collection( definition = former::VectorDefinition ) ]` if you want to use default collection defition. \nGot: {}", qt!{ #attr } ), } @@ -818,6 +822,7 @@ impl AttributeComponent for AttributeSubformEntrySetter const KEYWORD : &'static str = "subform_entry"; + #[ allow( clippy::match_wildcard_for_single_variants ) ] fn from_meta( attr : &syn::Attribute ) -> Result< Self > { match attr.meta @@ -828,7 +833,7 @@ impl AttributeComponent for AttributeSubformEntrySetter }, syn::Meta::Path( ref _path ) => { - syn::parse2::< AttributeSubformEntrySetter >( Default::default() ) + syn::parse2::< AttributeSubformEntrySetter >( TokenStream::default() ) }, _ => return_syn_err!( attr, "Expects an attribute of format `#[ subform_entry ]` or `#[ subform_entry( name : child )` ], \nGot: {}", qt!{ #attr } ), } diff --git a/module/core/former_meta/src/derive_former/struct_attrs.rs b/module/core/former_meta/src/derive_former/struct_attrs.rs index 31d6ab3491..f62fff702f 100644 --- a/module/core/former_meta/src/derive_former/struct_attrs.rs +++ b/module/core/former_meta/src/derive_former/struct_attrs.rs @@ -1,7 +1,7 @@ //! //! Attributes of the whole item. //! - +#[ allow( clippy::wildcard_imports ) ] use super::*; use macro_tools:: @@ -63,7 +63,7 @@ impl ItemAttributes { let key_ident = attr.path().get_ident().ok_or_else( || error( attr ) )?; - let key_str = format!( "{}", key_ident ); + let key_str = format!( "{key_ident}" ); // attributes does not have to be known // if attr::is_standard( &key_str ) @@ -76,7 +76,7 @@ impl ItemAttributes AttributeStorageFields::KEYWORD => result.assign( AttributeStorageFields::from_meta( attr )? ), AttributeMutator::KEYWORD => result.assign( AttributeMutator::from_meta( attr )? ), AttributePerform::KEYWORD => result.assign( AttributePerform::from_meta( attr )? ), - "debug" => {} + // "debug" => {} _ => {}, // _ => return Err( error( attr ) ), // attributes does not have to be known @@ -87,7 +87,7 @@ impl ItemAttributes } /// - /// Generate parts, used for generating `perform()`` method. + /// Generate parts, used for generating `perform()` method. /// /// Similar to `form()`, but will also invoke function from `perform` attribute, if specified. /// @@ -96,13 +96,13 @@ impl ItemAttributes /// ## perform : /// return result; /// - /// ## perform_output : - /// < T : ::core::default::Default > + /// ## `perform_output` : + /// < T : `::core::default::Default` > /// - /// ## perform_generics : + /// ## `perform_generics` : /// Vec< T > /// - + #[ allow( clippy::unnecessary_wraps ) ] pub fn performer( &self ) -> Result< ( TokenStream, TokenStream, TokenStream ) > { @@ -190,7 +190,7 @@ impl AttributeComponent for AttributeStorageFields { syn::Meta::List( ref meta_list ) => { - return syn::parse2::< AttributeStorageFields >( meta_list.tokens.clone() ); + syn::parse2::< AttributeStorageFields >( meta_list.tokens.clone() ) }, _ => return_syn_err!( attr, "Expects an attribute of format #[ storage_fields( a : i32, b : Option< String > ) ] .\nGot: {}", qt!{ #attr } ), @@ -260,6 +260,7 @@ pub struct AttributeMutator pub debug : AttributePropertyDebug, } +#[ allow( clippy::match_wildcard_for_single_variants ) ] impl AttributeComponent for AttributeMutator { const KEYWORD : &'static str = "mutator"; @@ -270,11 +271,11 @@ impl AttributeComponent for AttributeMutator { syn::Meta::List( ref meta_list ) => { - return syn::parse2::< AttributeMutator >( meta_list.tokens.clone() ); + syn::parse2::< AttributeMutator >( meta_list.tokens.clone() ) }, syn::Meta::Path( ref _path ) => { - return Ok( Default::default() ) + Ok( AttributeMutator::default() ) }, _ => return_syn_err!( attr, "Expects an attribute of format `#[ mutator( custom ) ]`. \nGot: {}", qt!{ #attr } ), } @@ -407,7 +408,7 @@ impl AttributeComponent for AttributePerform { syn::Meta::List( ref meta_list ) => { - return syn::parse2::< AttributePerform >( meta_list.tokens.clone() ); + syn::parse2::< AttributePerform >( meta_list.tokens.clone() ) }, _ => return_syn_err!( attr, "Expects an attribute of format #[ perform( fn parse( mut self ) -> Request ) ] .\nGot: {}", qt!{ #attr } ), diff --git a/module/core/former_types/Readme.md b/module/core/former_types/Readme.md index 30e14aaf08..742285fb8b 100644 --- a/module/core/former_types/Readme.md +++ b/module/core/former_types/Readme.md @@ -1,6 +1,6 @@ -# Module :: former_types +# Module :: `former_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_former_types_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_former_types_push.yml) [![docs.rs](https://img.shields.io/docsrs/former_types?color=e3e8f0&logo=docs.rs)](https://docs.rs/former_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%2Fformer_types%2Fexamples%2Fformer_types_trivial.rs,RUN_POSTFIX=--example%20former_types_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) diff --git a/module/core/former_types/src/collection.rs b/module/core/former_types/src/collection.rs index c740510fb3..8df9c34554 100644 --- a/module/core/former_types/src/collection.rs +++ b/module/core/former_types/src/collection.rs @@ -5,10 +5,11 @@ //! such as vectors, hash maps, and custom collection implementations. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// Facilitates the conversion of collection entries to their corresponding value representations. @@ -347,6 +348,8 @@ mod private { /// Begins the construction process of a collection with optional initial storage and context, /// setting up an `on_end` completion handler to finalize the collection's construction. + /// # Panics + /// qqq: doc #[ inline( always ) ] pub fn begin ( @@ -370,6 +373,8 @@ mod private /// Provides a variation of the `begin` method allowing for coercion of the end handler, /// facilitating ease of integration with different end conditions. + /// # Panics + /// qqq: docs #[ inline( always ) ] pub fn begin_coercing< IntoEnd > ( @@ -394,6 +399,8 @@ mod private } /// Finalizes the building process, returning the formed or a context incorporating it. + /// # Panics + /// qqq: doc #[ inline( always ) ] pub fn end( mut self ) -> Definition::Formed { @@ -412,6 +419,7 @@ mod private /// Replaces the current storage with a provided storage, allowing for resetting or /// redirection of the building process. #[ inline( always ) ] + #[ must_use ] pub fn replace( mut self, storage : Definition::Storage ) -> Self { self.storage = storage; @@ -462,6 +470,8 @@ mod private /// Appends an entry to the end of the storage, expanding the internal collection. #[ inline( always ) ] + #[ must_use ] + #[ allow( clippy::should_implement_trait ) ] pub fn add< IntoElement >( mut self, entry : IntoElement ) -> Self where IntoElement : core::convert::Into< E >, { @@ -521,6 +531,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -530,6 +541,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -539,6 +551,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] diff --git a/module/core/former_types/src/collection/binary_heap.rs b/module/core/former_types/src/collection/binary_heap.rs index ae76f5e4f8..86d350d967 100644 --- a/module/core/former_types/src/collection/binary_heap.rs +++ b/module/core/former_types/src/collection/binary_heap.rs @@ -5,6 +5,7 @@ //! as subformer, enabling fluid and intuitive manipulation of binary heaps via builder patterns. //! +#[ allow( clippy::wildcard_imports ) ] use crate::*; #[ allow( unused ) ] use collection_tools::BinaryHeap; @@ -241,6 +242,7 @@ impl< E > BinaryHeapExt< E > for BinaryHeap< E > where E : Ord { + #[ allow( clippy::default_constructed_unit_structs ) ] fn former() -> BinaryHeapFormer< E, (), BinaryHeap< E >, ReturnStorage > { BinaryHeapFormer::< E, (), BinaryHeap< E >, ReturnStorage >::new( ReturnStorage::default() ) diff --git a/module/core/former_types/src/collection/btree_map.rs b/module/core/former_types/src/collection/btree_map.rs index d1d97bfde8..9f3d01e698 100644 --- a/module/core/former_types/src/collection/btree_map.rs +++ b/module/core/former_types/src/collection/btree_map.rs @@ -4,7 +4,7 @@ //! this module abstracts the operations on binary tree map-like data structures, making them more flexible and easier to integrate as //! as subformer, enabling fluid and intuitive manipulation of binary tree maps via builder patterns. //! - +#[ allow( clippy::wildcard_imports ) ] use crate::*; use collection_tools::BTreeMap; @@ -238,6 +238,7 @@ impl< K, E > BTreeMapExt< K, E > for BTreeMap< K, E > where K : Ord, { + #[ allow( clippy::default_constructed_unit_structs ) ] fn former() -> BTreeMapFormer< K, E, (), BTreeMap< K, E >, ReturnStorage > { BTreeMapFormer::< K, E, (), BTreeMap< K, E >, ReturnStorage >::new( ReturnStorage::default() ) diff --git a/module/core/former_types/src/collection/btree_set.rs b/module/core/former_types/src/collection/btree_set.rs index 360c9484ae..d09e1793d6 100644 --- a/module/core/former_types/src/collection/btree_set.rs +++ b/module/core/former_types/src/collection/btree_set.rs @@ -4,7 +4,7 @@ //! this module abstracts the operations on binary tree set-like data structures, making them more flexible and easier to integrate as //! as subformer, enabling fluid and intuitive manipulation of binary tree sets via builder patterns. //! - +#[ allow( clippy::wildcard_imports ) ] use crate::*; #[ allow( unused ) ] use collection_tools::BTreeSet; @@ -230,6 +230,7 @@ impl< E > BTreeSetExt< E > for BTreeSet< E > where E : Ord { + #[ allow( clippy::default_constructed_unit_structs ) ] fn former() -> BTreeSetFormer< E, (), BTreeSet< E >, ReturnStorage > { BTreeSetFormer::< E, (), BTreeSet< E >, ReturnStorage >::new( ReturnStorage::default() ) diff --git a/module/core/former_types/src/collection/hash_map.rs b/module/core/former_types/src/collection/hash_map.rs index f6d6f1b58d..1c4444fa4a 100644 --- a/module/core/former_types/src/collection/hash_map.rs +++ b/module/core/former_types/src/collection/hash_map.rs @@ -5,9 +5,11 @@ //! as subformer, enabling fluid and intuitive manipulation of hashmaps via builder patterns. //! +#[ allow( clippy::wildcard_imports ) ] use crate::*; use collection_tools::HashMap; +#[ allow( clippy::implicit_hasher ) ] impl< K, V > Collection for HashMap< K, V > where K : core::cmp::Eq + core::hash::Hash, @@ -23,6 +25,7 @@ where } +#[ allow( clippy::implicit_hasher ) ] impl< K, V > CollectionAdd for HashMap< K, V > where K : core::cmp::Eq + core::hash::Hash, @@ -36,6 +39,7 @@ where } +#[ allow( clippy::implicit_hasher ) ] impl< K, V > CollectionAssign for HashMap< K, V > where K : core::cmp::Eq + core::hash::Hash, @@ -53,6 +57,7 @@ where // = storage +#[ allow( clippy::implicit_hasher ) ] impl< K, E > Storage for HashMap< K, E > where @@ -61,6 +66,7 @@ where type Preformed = HashMap< K, E >; } +#[ allow( clippy::implicit_hasher ) ] impl< K, E > StoragePreform for HashMap< K, E > where @@ -155,6 +161,7 @@ where // = Entity To +#[ allow( clippy::implicit_hasher ) ] impl< K, E, Definition > EntityToFormer< Definition > for HashMap< K, E > where K : ::core::cmp::Eq + ::core::hash::Hash, @@ -174,6 +181,7 @@ where type Former = HashMapFormer< K, E, Definition::Context, Definition::Formed, Definition::End >; } +#[ allow( clippy::implicit_hasher ) ] impl< K, E > crate::EntityToStorage for HashMap< K, E > where @@ -182,6 +190,7 @@ where type Storage = HashMap< K, E >; } +#[ allow( clippy::implicit_hasher ) ] impl< K, E, Context, Formed, End > crate::EntityToDefinition< Context, Formed, End > for HashMap< K, E > where @@ -192,6 +201,7 @@ where type Types = HashMapDefinitionTypes< K, E, Context, Formed >; } +#[ allow( clippy::implicit_hasher ) ] impl< K, E, Context, Formed > crate::EntityToDefinitionTypes< Context, Formed > for HashMap< K, E > where @@ -234,6 +244,7 @@ where fn former() -> HashMapFormer< K, E, (), HashMap< K, E >, ReturnStorage >; } +#[ allow( clippy::default_constructed_unit_structs, clippy::implicit_hasher ) ] impl< K, E > HashMapExt< K, E > for HashMap< K, E > where K : ::core::cmp::Eq + ::core::hash::Hash, diff --git a/module/core/former_types/src/collection/hash_set.rs b/module/core/former_types/src/collection/hash_set.rs index 16d5dec6c0..97d7ddd66e 100644 --- a/module/core/former_types/src/collection/hash_set.rs +++ b/module/core/former_types/src/collection/hash_set.rs @@ -1,8 +1,9 @@ //! This module provides a builder pattern implementation (`HashSetFormer`) for `HashSet`-like collections. It is designed to extend the builder pattern, allowing for fluent and dynamic construction of sets within custom data structures. - +#[ allow( clippy::wildcard_imports ) ] use crate::*; use collection_tools::HashSet; +#[ allow( clippy::implicit_hasher ) ] impl< K > Collection for HashSet< K > where K : core::cmp::Eq + core::hash::Hash, @@ -18,6 +19,7 @@ where } +#[ allow( clippy::implicit_hasher ) ] impl< K > CollectionAdd for HashSet< K > where K : core::cmp::Eq + core::hash::Hash, @@ -33,6 +35,7 @@ where } +#[ allow( clippy::implicit_hasher ) ] impl< K > CollectionAssign for HashSet< K > where K : core::cmp::Eq + core::hash::Hash, @@ -49,6 +52,7 @@ where } } +#[ allow( clippy::implicit_hasher ) ] impl< K > CollectionValToEntry< K > for HashSet< K > where K : core::cmp::Eq + core::hash::Hash, @@ -91,6 +95,7 @@ where // = storage +#[ allow( clippy::implicit_hasher ) ] impl< K > Storage for HashSet< K > where @@ -100,6 +105,7 @@ where type Preformed = HashSet< K >; } +#[ allow( clippy::implicit_hasher ) ] impl< K > StoragePreform for HashSet< K > where @@ -187,6 +193,7 @@ where // = entity to +#[ allow( clippy::implicit_hasher ) ] impl< K, Definition > EntityToFormer< Definition > for HashSet< K > where K : ::core::cmp::Eq + ::core::hash::Hash, @@ -205,6 +212,7 @@ where type Former = HashSetFormer< K, Definition::Context, Definition::Formed, Definition::End >; } +#[ allow( clippy::implicit_hasher ) ] impl< K > crate::EntityToStorage for HashSet< K > where @@ -213,6 +221,7 @@ where type Storage = HashSet< K >; } +#[ allow( clippy::implicit_hasher ) ] impl< K, Context, Formed, End > crate::EntityToDefinition< Context, Formed, End > for HashSet< K > where @@ -223,6 +232,7 @@ where type Types = HashSetDefinitionTypes< K, Context, Formed >; } +#[ allow( clippy::implicit_hasher ) ] impl< K, Context, Formed > crate::EntityToDefinitionTypes< Context, Formed > for HashSet< K > where @@ -260,10 +270,12 @@ where fn former() -> HashSetFormer< K, (), HashSet< K >, ReturnStorage >; } +#[ allow( clippy::implicit_hasher ) ] impl< K > HashSetExt< K > for HashSet< K > where K : ::core::cmp::Eq + ::core::hash::Hash, { + #[ allow( clippy::default_constructed_unit_structs ) ] fn former() -> HashSetFormer< K, (), HashSet< K >, ReturnStorage > { HashSetFormer::< K, (), HashSet< K >, ReturnStorage >::new( ReturnStorage::default() ) diff --git a/module/core/former_types/src/collection/linked_list.rs b/module/core/former_types/src/collection/linked_list.rs index abdb327074..1ace9637a9 100644 --- a/module/core/former_types/src/collection/linked_list.rs +++ b/module/core/former_types/src/collection/linked_list.rs @@ -4,7 +4,7 @@ //! this module abstracts the operations on list-like data structures, making them more flexible and easier to integrate as //! as subformer, enabling fluid and intuitive manipulation of lists via builder patterns. //! - +#[ allow( clippy::wildcard_imports ) ] use crate::*; #[ allow( unused ) ] use collection_tools::LinkedList; @@ -221,6 +221,7 @@ pub trait LinkedListExt< E > : sealed::Sealed impl< E > LinkedListExt< E > for LinkedList< E > { + #[ allow( clippy::default_constructed_unit_structs ) ] fn former() -> LinkedListFormer< E, (), LinkedList< E >, ReturnStorage > { LinkedListFormer::< E, (), LinkedList< E >, ReturnStorage >::new( ReturnStorage::default() ) diff --git a/module/core/former_types/src/collection/vector.rs b/module/core/former_types/src/collection/vector.rs index 96f7e577f1..5e88250511 100644 --- a/module/core/former_types/src/collection/vector.rs +++ b/module/core/former_types/src/collection/vector.rs @@ -4,7 +4,7 @@ //! this module abstracts the operations on vector-like data structures, making them more flexible and easier to integrate as //! as subformer, enabling fluid and intuitive manipulation of vectors via builder patterns. //! - +#[ allow( clippy::wildcard_imports ) ] use crate::*; #[ allow( unused ) ] use collection_tools::Vec; @@ -221,6 +221,7 @@ pub trait VecExt< E > : sealed::Sealed impl< E > VecExt< E > for Vec< E > { + #[ allow( clippy::default_constructed_unit_structs ) ] fn former() -> VectorFormer< E, (), Vec< E >, ReturnStorage > { VectorFormer::< E, (), Vec< E >, ReturnStorage >::new( ReturnStorage::default() ) diff --git a/module/core/former_types/src/collection/vector_deque.rs b/module/core/former_types/src/collection/vector_deque.rs index f3b08c6c01..ae207c612e 100644 --- a/module/core/former_types/src/collection/vector_deque.rs +++ b/module/core/former_types/src/collection/vector_deque.rs @@ -4,7 +4,7 @@ //! this module abstracts the operations on vector deque-like data structures, making them more flexible and easier to integrate as //! as subformer, enabling fluid and intuitive manipulation of vector deques via builder patterns. //! - +#[ allow( clippy::wildcard_imports ) ] use crate::*; #[ allow( unused ) ] use collection_tools::VecDeque; @@ -221,6 +221,7 @@ pub trait VecDequeExt< E > : sealed::Sealed impl< E > VecDequeExt< E > for VecDeque< E > { + #[ allow( clippy::default_constructed_unit_structs ) ] fn former() -> VecDequeFormer< E, (), VecDeque< E >, ReturnStorage > { VecDequeFormer::< E, (), VecDeque< E >, ReturnStorage >::new( ReturnStorage::default() ) diff --git a/module/core/former_types/src/component.rs b/module/core/former_types/src/component.rs index 9e846e2673..001619ad1e 100644 --- a/module/core/former_types/src/component.rs +++ b/module/core/former_types/src/component.rs @@ -37,7 +37,7 @@ /// obj.assign( "New Name" ); /// assert_eq!( obj.name, "New Name" ); /// ``` -#[ cfg( any( feature = "types_component_assign" ) ) ] +#[ cfg( feature = "types_component_assign" ) ] pub trait Assign< T, IntoT > where IntoT : Into< T >, @@ -51,6 +51,7 @@ where /// Sets or replaces the component on the object with the given value. /// Unlike function (`assing`) function (`impute`) also consumes self and return it what is useful for builder pattern. #[ inline( always ) ] + #[ must_use ] fn impute( mut self, component : IntoT ) -> Self where Self : Sized, @@ -94,7 +95,7 @@ where /// opt_struct.option_assign( MyStruct { name: "New Name".to_string() } ); /// assert_eq!( opt_struct.unwrap().name, "New Name" ); /// ``` -#[ cfg( any( feature = "types_component_assign" ) ) ] +#[ cfg( feature = "types_component_assign" ) ] pub trait OptionExt< T > : sealed::Sealed where T : Sized + Assign< T, T >, @@ -109,7 +110,7 @@ where fn option_assign( & mut self, src : T ); } -#[ cfg( any( feature = "types_component_assign" ) ) ] +#[ cfg( feature = "types_component_assign" ) ] impl< T > OptionExt< T > for Option< T > where T : Sized + Assign< T, T >, @@ -125,7 +126,7 @@ where } } -#[ cfg( any( feature = "types_component_assign" ) ) ] +#[ cfg( feature = "types_component_assign" ) ] mod sealed { pub trait Sealed {} @@ -172,7 +173,7 @@ mod sealed /// /// assert_eq!( user_profile.username, "john_doe" ); /// ``` -#[ cfg( any( feature = "types_component_assign" ) ) ] +#[ cfg( feature = "types_component_assign" ) ] pub trait AssignWithType { /// Sets the value of a component by its type. @@ -196,7 +197,7 @@ pub trait AssignWithType Self : Assign< T, IntoT >; } -#[ cfg( any( feature = "types_component_assign" ) ) ] +#[ cfg( feature = "types_component_assign" ) ] impl< S > AssignWithType for S { #[ inline( always ) ] diff --git a/module/core/former_types/src/forming.rs b/module/core/former_types/src/forming.rs index d95bea8666..46c9b87aff 100644 --- a/module/core/former_types/src/forming.rs +++ b/module/core/former_types/src/forming.rs @@ -163,6 +163,7 @@ use alloc::boxed::Box; /// a closure needs to be stored or passed around as an object implementing /// `FormingEnd`. #[ cfg( any( not( feature = "no_std" ), feature = "use_alloc" ) ) ] +#[ allow( clippy::type_complexity ) ] pub struct FormingEndClosure< Definition : crate::FormerDefinitionTypes > { closure : Box< dyn Fn( Definition::Storage, Option< Definition::Context > ) -> Definition::Formed >, diff --git a/module/core/former_types/src/lib.rs b/module/core/former_types/src/lib.rs index 39196a30e7..f4c1ac346c 100644 --- a/module/core/former_types/src/lib.rs +++ b/module/core/former_types/src/lib.rs @@ -29,7 +29,7 @@ mod collection; /// Component-based forming. #[ cfg( feature = "enabled" ) ] -#[ cfg( any( feature = "types_component_assign" ) ) ] +#[ cfg( feature = "types_component_assign" ) ] mod component; /// Namespace with dependencies. @@ -49,6 +49,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -59,6 +60,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -76,6 +78,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -103,10 +106,11 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] - #[ cfg( any( feature = "types_component_assign" ) ) ] + #[ cfg( feature = "types_component_assign" ) ] pub use component::*; #[ doc( inline ) ] diff --git a/module/core/fs_tools/src/fs/fs.rs b/module/core/fs_tools/src/fs/fs.rs index 25f60b2592..a10288843c 100644 --- a/module/core/fs_tools/src/fs/fs.rs +++ b/module/core/fs_tools/src/fs/fs.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/core/implements/src/lib.rs b/module/core/implements/src/lib.rs index 7bdfba2035..989d5e528e 100644 --- a/module/core/implements/src/lib.rs +++ b/module/core/implements/src/lib.rs @@ -16,7 +16,7 @@ #[ cfg( feature = "enabled" ) ] mod implements_impl; -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( feature = "enabled" ) ] mod private { diff --git a/module/core/impls_index/Cargo.toml b/module/core/impls_index/Cargo.toml index 1845411740..fc8c02eca0 100644 --- a/module/core/impls_index/Cargo.toml +++ b/module/core/impls_index/Cargo.toml @@ -27,8 +27,6 @@ all-features = false [features] default = [ "enabled" ] full = [ "enabled" ] -no_std = [] -use_alloc = [ "no_std" ] enabled = [ "impls_index_meta/enabled" ] [dependencies] @@ -36,4 +34,4 @@ impls_index_meta = { workspace = true } [dev-dependencies] test_tools = { workspace = true } -tempdir = { version = "0.3.7" } +#tempdir = { version = "0.3.7" } diff --git a/module/core/impls_index/src/impls_index/func.rs b/module/core/impls_index/src/impls_index/func.rs index 21448b2ef8..da33da0127 100644 --- a/module/core/impls_index/src/impls_index/func.rs +++ b/module/core/impls_index/src/impls_index/func.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/core/impls_index/src/impls_index/impls.rs b/module/core/impls_index/src/impls_index/impls.rs index 18d81346a8..b10b4498e3 100644 --- a/module/core/impls_index/src/impls_index/impls.rs +++ b/module/core/impls_index/src/impls_index/impls.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -382,14 +382,7 @@ pub mod exposed use super::*; #[ doc( inline ) ] pub use prelude::*; -} - -/// Prelude to use essentials: `use my_module::prelude::*`. -#[ allow( unused_imports ) ] -pub mod prelude -{ - use super::*; #[ doc( inline ) ] pub use private:: { @@ -403,9 +396,15 @@ pub mod prelude _impls_callback, }; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use ::impls_index_meta::impls3; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use impls3 as impls; + +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; } diff --git a/module/core/impls_index/src/impls_index/mod.rs b/module/core/impls_index/src/impls_index/mod.rs index f0d3a5f74f..5b54558d8d 100644 --- a/module/core/impls_index/src/impls_index/mod.rs +++ b/module/core/impls_index/src/impls_index/mod.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -31,6 +31,8 @@ pub mod own use super::*; #[ doc( inline ) ] pub use orphan::*; + #[ doc( inline ) ] + pub use ::impls_index_meta::*; } /// Shared with parent namespace of the module @@ -40,7 +42,6 @@ pub mod orphan use super::*; #[ doc( inline ) ] pub use exposed::*; - // pub use super::dependency; } /// Exposed namespace of the module. @@ -51,11 +52,9 @@ pub mod exposed #[ doc( inline ) ] pub use prelude::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use super::impls::exposed::*; + pub use impls::exposed::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use super::func::exposed::*; + pub use func::exposed::*; } /// Prelude to use essentials: `use my_module::prelude::*`. @@ -64,13 +63,7 @@ pub mod prelude { use super::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use super::impls::prelude::*; + pub use impls::prelude::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use super::func::prelude::*; - // #[ cfg( any( feature = "meta", feature = "impls_index_meta" ) ) ] - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use ::impls_index_meta::*; + pub use func::prelude::*; } diff --git a/module/core/impls_index/src/lib.rs b/module/core/impls_index/src/lib.rs index ec229443d8..ac0f33af0a 100644 --- a/module/core/impls_index/src/lib.rs +++ b/module/core/impls_index/src/lib.rs @@ -1,4 +1,4 @@ -#![ 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/impls_index/latest/impls_index/" ) ] @@ -30,7 +30,6 @@ pub mod own #[ doc( inline ) ] pub use orphan::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super::impls_index::orphan::*; } @@ -53,7 +52,6 @@ pub mod exposed #[ doc( inline ) ] pub use prelude::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super::impls_index::exposed::*; } @@ -64,6 +62,5 @@ pub mod prelude { use super::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super::impls_index::prelude::*; } diff --git a/module/core/impls_index/tests/inc/func_test.rs b/module/core/impls_index/tests/inc/func_test.rs index 7408b5b3ff..7b5d74bbcc 100644 --- a/module/core/impls_index/tests/inc/func_test.rs +++ b/module/core/impls_index/tests/inc/func_test.rs @@ -2,7 +2,7 @@ use super::*; #[ allow ( unused_imports ) ] -use the_module::prelude::*; +use the_module::exposed::*; // use test_tools::exposed::*; // diff --git a/module/core/impls_index/tests/inc/impls1_test.rs b/module/core/impls_index/tests/inc/impls1_test.rs index c8df2ca220..b49e010b01 100644 --- a/module/core/impls_index/tests/inc/impls1_test.rs +++ b/module/core/impls_index/tests/inc/impls1_test.rs @@ -1,120 +1,118 @@ // use test_tools::exposed::*; use super::*; -use the_module::prelude::impls1; +use the_module::exposed::impls1; +// use the_module::exposed::{ index }; // -tests_impls! +#[ test ] +fn impls_basic() { - fn impls_basic() + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); + impls1! { - - impls1! + fn f1() { - fn f1() - { - println!( "f1" ); - } - pub fn f2() - { - println!( "f2" ); - } - }; + println!( "f1" ); + } + pub fn f2() + { + println!( "f2" ); + } + }; - // trace_macros!( true ); - f1!(); - f2!(); - // trace_macros!( false ); + // trace_macros!( true ); + f1!(); + f2!(); + // trace_macros!( false ); - f1(); - f2(); + f1(); + f2(); - } + } + +// // test.case( "impls1 as" ); +// { +// +// impls1! +// { +// fn f1() +// { +// println!( "f1" ); +// } +// pub fn f2() +// { +// println!( "f2" ); +// } +// }; +// +// // trace_macros!( true ); +// f1!( as f1b ); +// f2!( as f2b ); +// // trace_macros!( false ); +// +// f1b(); +// f2b(); +// +// } +// +// // test.case( "impls1 as index" ); +// { +// +// impls1! +// { +// fn f1() +// { +// println!( "f1" ); +// } +// pub fn f2() +// { +// println!( "f2" ); +// } +// }; +// +// // trace_macros!( true ); +// index! +// { +// f1, +// f2 as f2b, +// } +// // trace_macros!( false ); +// +// f1(); +// f2b(); +// +// } - // // test.case( "impls1 as" ); - // { - // - // impls1! - // { - // fn f1() - // { - // println!( "f1" ); - // } - // pub fn f2() - // { - // println!( "f2" ); - // } - // }; - // - // // trace_macros!( true ); - // f1!( as f1b ); - // f2!( as f2b ); - // // trace_macros!( false ); - // - // f1b(); - // f2b(); - // - // } - // - // // test.case( "impls1 as index" ); - // { - // - // impls1! - // { - // fn f1() - // { - // println!( "f1" ); - // } - // pub fn f2() - // { - // println!( "f2" ); - // } - // }; - // - // // trace_macros!( true ); - // index! - // { - // f1, - // f2 as f2b, - // } - // // trace_macros!( false ); - // - // f1(); - // f2b(); - // - // } + // test.case( "macro" ); + { - // test.case( "macro" ); + impls1! { - - impls1! + fn f1() { - fn f1() + macro_rules! macro1 { - macro_rules! macro1 - { - ( $( $Arg : tt )* ) => { }; - } - macro1!(); + ( $( $Arg : tt )* ) => { }; } + macro1!(); } - - // trace_macros!( true ); - f1!(); - // trace_macros!( false ); - } + // trace_macros!( true ); + f1!(); + // trace_macros!( false ); + } + } // -tests_index! -{ - impls_basic, -} +// tests_index! +// { +// impls_basic, +// } diff --git a/module/core/impls_index/tests/inc/impls2_test.rs b/module/core/impls_index/tests/inc/impls2_test.rs index bb5d16eaab..20b83f0731 100644 --- a/module/core/impls_index/tests/inc/impls2_test.rs +++ b/module/core/impls_index/tests/inc/impls2_test.rs @@ -1,121 +1,119 @@ // use test_tools::exposed::*; use super::*; -use the_module::prelude::impls2; +use the_module::exposed::impls2; +use the_module::exposed::{ index }; // -tests_impls! +#[ test ] +fn impls_basic() { - fn impls_basic() + // test.case( "impls2 basic" ); { - // test.case( "impls2 basic" ); + impls2! { - - impls2! + fn f1() { - fn f1() - { - println!( "f1" ); - } - pub fn f2() - { - println!( "f2" ); - } - }; + println!( "f1" ); + } + pub fn f2() + { + println!( "f2" ); + } + }; - // trace_macros!( true ); - f1!(); - f2!(); - // trace_macros!( false ); + // trace_macros!( true ); + f1!(); + f2!(); + // trace_macros!( false ); - f1(); - f2(); + f1(); + f2(); - } + } - // test.case( "impls2 as" ); - { + // test.case( "impls2 as" ); + { - impls2! + impls2! + { + fn f1() { - fn f1() - { - println!( "f1" ); - } - pub fn f2() - { - println!( "f2" ); - } - }; + println!( "f1" ); + } + pub fn f2() + { + println!( "f2" ); + } + }; - // trace_macros!( true ); - f1!( as f1b ); - f2!( as f2b ); - // trace_macros!( false ); + // trace_macros!( true ); + f1!( as f1b ); + f2!( as f2b ); + // trace_macros!( false ); - f1b(); - f2b(); + f1b(); + f2b(); - } + } - // test.case( "impls2 as index" ); - { + // test.case( "impls2 as index" ); + { - impls2! + impls2! + { + fn f1() { - fn f1() - { - println!( "f1" ); - } - pub fn f2() - { - println!( "f2" ); - } - }; - - // trace_macros!( true ); - index! + println!( "f1" ); + } + pub fn f2() { - f1, - f2 as f2b, + println!( "f2" ); } - // trace_macros!( false ); - - f1(); - f2b(); + }; + // trace_macros!( true ); + index! + { + f1, + f2 as f2b, } + // trace_macros!( false ); - // test.case( "macro" ); - { + f1(); + f2b(); - impls2! + } + + // test.case( "macro" ); + { + + impls2! + { + fn f1() { - fn f1() + macro_rules! macro1 { - macro_rules! macro1 - { - ( $( $Arg : tt )* ) => { }; - } - macro1!(); + ( $( $Arg : tt )* ) => { }; } + macro1!(); } - - // trace_macros!( true ); - f1!(); - // trace_macros!( false ); - } + // trace_macros!( true ); + f1!(); + // trace_macros!( false ); + } + } // -tests_index! -{ - // fns, - impls_basic, -} +// tests_index! +// { +// // fns, +// impls_basic, +// } diff --git a/module/core/impls_index/tests/inc/impls3_test.rs b/module/core/impls_index/tests/inc/impls3_test.rs index 860acd126a..1fe454dfc7 100644 --- a/module/core/impls_index/tests/inc/impls3_test.rs +++ b/module/core/impls_index/tests/inc/impls3_test.rs @@ -1,5 +1,6 @@ use super::*; -use the_module::prelude::impls3; +use the_module::exposed::impls3; +use the_module::exposed::{ index }; // @@ -7,7 +8,7 @@ use the_module::prelude::impls3; fn basic() { - impls! + impls3! { fn f1() { diff --git a/module/core/impls_index/tests/inc/impls_basic_test.rs b/module/core/impls_index/tests/inc/impls_basic_test.rs index c488aec5a2..8a9ef8df85 100644 --- a/module/core/impls_index/tests/inc/impls_basic_test.rs +++ b/module/core/impls_index/tests/inc/impls_basic_test.rs @@ -1,6 +1,5 @@ use super::*; -#[ allow( unused_imports ) ] -use the_module::prelude::*; +use the_module::exposed::*; // trace_macros!( true ); tests_impls! diff --git a/module/core/impls_index/tests/inc/index_test.rs b/module/core/impls_index/tests/inc/index_test.rs index de1ed0d9be..561e1ba8ac 100644 --- a/module/core/impls_index/tests/inc/index_test.rs +++ b/module/core/impls_index/tests/inc/index_test.rs @@ -1,155 +1,151 @@ // use test_tools::exposed::*; use super::*; -use the_module::prelude::impls1; +use the_module::exposed::impls1; +use the_module::exposed::{ index }; // -tests_impls! +#[ test ] +fn empty_with_comma() { - - fn empty_with_comma() + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); - { - - impls1!(); - index!(); - - } + impls1!(); + index!(); } +} + +#[ test ] +fn empty_without_comma() +{ - fn empty_without_comma() + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); + impls1! { + }; - impls1! - { - }; - - index! - { - } - + index! + { } } +} + +#[ test ] +fn with_comma() +{ - fn with_comma() + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); + impls1! { - - impls1! + fn f1() -> i32 { - fn f1() -> i32 - { - println!( "f1" ); - 13 - } - }; - - index! - { - f1, + println!( "f1" ); + 13 } + }; - a_id!( f1(), 13 ); + index! + { + f1, } + a_id!( f1(), 13 ); } +} + +#[ test ] +fn without_comma() +{ - fn without_comma() + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); + impls1! { - - impls1! - { - fn f1() -> i32 - { - println!( "f1" ); - 13 - } - }; - - index! + fn f1() -> i32 { - f1 + println!( "f1" ); + 13 } + }; - a_id!( f1(), 13 ); + index! + { + f1 } + a_id!( f1(), 13 ); } +} + +#[ test ] +fn parentheses_with_comma() +{ - fn parentheses_with_comma() + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); + impls1! { - - impls1! + fn f1() -> i32 { - fn f1() -> i32 - { - println!( "f1" ); - 13 - } - }; - - index!( f1, ); + println!( "f1" ); + 13 + } + }; - a_id!( f1(), 13 ); - } + index!( f1, ); + a_id!( f1(), 13 ); } +} - fn parentheses_without_comma() +#[ test ] +fn parentheses_without_comma() +{ + + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); + impls1! { - - impls1! + fn f1() -> i32 { - fn f1() -> i32 - { - println!( "f1" ); - 13 - } - }; - - index!( f1 ); + println!( "f1" ); + 13 + } + }; - a_id!( f1(), 13 ); - } + index!( f1 ); + a_id!( f1(), 13 ); } } // -tests_index! -{ - - empty_with_comma, - empty_without_comma, - with_comma, - without_comma, - parentheses_with_comma, - parentheses_without_comma, - -} +// tests_index! +// { +// +// empty_with_comma, +// empty_without_comma, +// with_comma, +// without_comma, +// parentheses_with_comma, +// parentheses_without_comma, +// +// } diff --git a/module/core/impls_index/tests/inc/mod.rs b/module/core/impls_index/tests/inc/mod.rs index d7b9687e2f..105f2928cd 100644 --- a/module/core/impls_index/tests/inc/mod.rs +++ b/module/core/impls_index/tests/inc/mod.rs @@ -1,5 +1,10 @@ -use super::*; +use super:: +{ + the_module, + only_for_terminal_module, + a_id, +}; mod func_test; mod impls_basic_test; diff --git a/module/core/impls_index/tests/inc/tests_index_test.rs b/module/core/impls_index/tests/inc/tests_index_test.rs index 9c684d5a68..d6cbf4e3c6 100644 --- a/module/core/impls_index/tests/inc/tests_index_test.rs +++ b/module/core/impls_index/tests/inc/tests_index_test.rs @@ -1,155 +1,151 @@ // use test_tools::exposed::*; use super::*; -use the_module::prelude::impls1; +use the_module::exposed::impls1; +use the_module::exposed::{ tests_index }; // -tests_impls! +#[ test ] +fn empty_with_comma() { - - fn empty_with_comma() + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); - { - - impls1!(); - tests_index!(); - - } + impls1!(); + tests_index!(); } +} + +#[ test ] +fn empty_without_comma() +{ - fn empty_without_comma() + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); + impls1! { + }; - impls1! - { - }; - - tests_index! - { - } - + tests_index! + { } } +} + +#[ test ] +fn with_comma() +{ - fn with_comma() + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); + impls1! { - - impls1! + fn f1() -> i32 { - fn f1() -> i32 - { - println!( "f1" ); - 13 - } - }; - - tests_index! - { - f1, + println!( "f1" ); + 13 } + }; - a_id!( f1(), 13 ); + tests_index! + { + f1, } + a_id!( f1(), 13 ); } +} + +#[ test ] +fn without_comma() +{ - fn without_comma() + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); + impls1! { - - impls1! - { - fn f1() -> i32 - { - println!( "f1" ); - 13 - } - }; - - tests_index! + fn f1() -> i32 { - f1 + println!( "f1" ); + 13 } + }; - a_id!( f1(), 13 ); + tests_index! + { + f1 } + a_id!( f1(), 13 ); } +} + +#[ test ] +fn parentheses_with_comma() +{ - fn parentheses_with_comma() + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); + impls1! { - - impls1! + fn f1() -> i32 { - fn f1() -> i32 - { - println!( "f1" ); - 13 - } - }; - - tests_index!( f1, ); + println!( "f1" ); + 13 + } + }; - a_id!( f1(), 13 ); - } + tests_index!( f1, ); + a_id!( f1(), 13 ); } +} - fn parentheses_without_comma() +#[ test ] +fn parentheses_without_comma() +{ + + // test.case( "impls1 basic" ); { - // test.case( "impls1 basic" ); + impls1! { - - impls1! + fn f1() -> i32 { - fn f1() -> i32 - { - println!( "f1" ); - 13 - } - }; - - tests_index!( f1 ); + println!( "f1" ); + 13 + } + }; - a_id!( f1(), 13 ); - } + tests_index!( f1 ); + a_id!( f1(), 13 ); } } // -tests_index! -{ - - empty_with_comma, - empty_without_comma, - with_comma, - without_comma, - parentheses_with_comma, - parentheses_without_comma, - -} +// tests_index! +// { +// +// empty_with_comma, +// empty_without_comma, +// with_comma, +// without_comma, +// parentheses_with_comma, +// parentheses_without_comma, +// +// } diff --git a/module/core/impls_index/tests/tests.rs b/module/core/impls_index/tests/tests.rs index 7d4038e715..b96684ac4a 100644 --- a/module/core/impls_index/tests/tests.rs +++ b/module/core/impls_index/tests/tests.rs @@ -1,3 +1,4 @@ +#![ allow( unused_imports ) ] include!( "../../../../module/step/meta/src/module/terminal.rs" ); diff --git a/module/core/interval_adapter/Readme.md b/module/core/interval_adapter/Readme.md index 19cfc05f9e..f1d171804d 100644 --- a/module/core/interval_adapter/Readme.md +++ b/module/core/interval_adapter/Readme.md @@ -1,11 +1,11 @@ -# Module :: interval_adapter +# Module :: `interval_adapter` [![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_interval_adapter_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_interval_adapter_push.yml) [![docs.rs](https://img.shields.io/docsrs/interval_adapter?color=e3e8f0&logo=docs.rs)](https://docs.rs/interval_adapter) [![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%2Finterval_adapter%2Fexamples%2Finterval_adapter_trivial.rs,RUN_POSTFIX=--example%20interval_adapter_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) -Integer interval adapter for both Range and RangeInclusive. +Integer interval adapter for both Range and `RangeInclusive`. Let's assume you have a function which should accept Interval. But you don't want to limit caller of the function to either half-open interval `core::ops::Range` or closed one `core::ops::RangeInclusive` you want allow to use anyone of iterable interval. To make that work smoothly use `IterableInterval`. Both `core::ops::Range` and `core::ops::RangeInclusive` implement the trait, also it's possible to work with non-iterable intervals, like ( -Infinity .. +Infinity ). diff --git a/module/core/interval_adapter/src/lib.rs b/module/core/interval_adapter/src/lib.rs index 4684d69850..19fb7c2537 100644 --- a/module/core/interval_adapter/src/lib.rs +++ b/module/core/interval_adapter/src/lib.rs @@ -4,16 +4,18 @@ #![ doc( html_root_url = "https://docs.rs/winterval/latest/winterval/" ) ] #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( feature = "enabled" ) ] mod private { #[ doc( inline ) ] #[ allow( unused_imports ) ] + #[ allow( clippy::pub_use ) ] pub use core::ops::Bound; #[ doc( inline ) ] #[ allow( unused_imports ) ] + #[ allow( clippy::pub_use ) ] pub use core::ops::RangeBounds; use core::cmp::{ PartialEq, Eq }; @@ -21,6 +23,7 @@ mod private // xxx : seal it + #[ allow( clippy::wrong_self_convention ) ] /// Extend bound adding few methods. pub trait BoundExt< T > where @@ -39,23 +42,25 @@ mod private isize : Into< T >, { #[ inline( always ) ] + #[ allow( clippy::arithmetic_side_effects, clippy::implicit_return, clippy::pattern_type_mismatch ) ] fn into_left_closed( &self ) -> T { match self { - Bound::Included( v ) => *v, - Bound::Excluded( v ) => *v + 1.into(), + Bound::Included( value ) => *value, + Bound::Excluded( value ) => *value + 1.into(), Bound::Unbounded => 0.into(), // Bound::Unbounded => isize::MIN.into(), } } #[ inline( always ) ] + #[ allow( clippy::arithmetic_side_effects, clippy::implicit_return, clippy::pattern_type_mismatch ) ] fn into_right_closed( &self ) -> T { match self { - Bound::Included( v ) => *v, - Bound::Excluded( v ) => *v - 1.into(), + Bound::Included( value ) => *value, + Bound::Excluded( value ) => *value - 1.into(), Bound::Unbounded => isize::MAX.into(), } } @@ -97,6 +102,7 @@ mod private fn right( &self ) -> Bound< T >; /// Interval in closed format as pair of numbers. /// To convert open endpoint to closed add or subtract one. + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn bounds( &self ) -> ( Bound< T >, Bound< T > ) { @@ -104,18 +110,21 @@ mod private } /// The left endpoint of the interval, converting interval into closed one. + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn closed_left( &self ) -> T { self.left().into_left_closed() } /// The right endpoint of the interval, converting interval into closed one. + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn closed_right( &self ) -> T { self.right().into_right_closed() } /// Length of the interval, converting interval into closed one. + #[ allow( clippy::implicit_return, clippy::arithmetic_side_effects ) ] #[ inline( always ) ] fn closed_len( &self ) -> T { @@ -123,6 +132,7 @@ mod private self.closed_right() - self.closed_left() + one } /// Interval in closed format as pair of numbers, converting interval into closed one. + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn closed( &self ) -> ( T, T ) { @@ -130,6 +140,7 @@ mod private } /// Convert to interval in canonical format. + #[ allow( unknown_lints, clippy::implicit_return ) ] #[ inline( always ) ] fn canonical( &self ) -> Interval< T > { @@ -166,16 +177,19 @@ mod private /// /// Canonical implementation of interval. Other implementations of interval is convertible to it. /// - /// Both [core::ops::Range], [core::ops::RangeInclusive] are convertable to [crate::Interval] + /// Both [`core::ops::Range`], [`core::ops::RangeInclusive`] are convertable to [`crate::Interval`] /// + #[ allow( clippy::used_underscore_binding ) ] #[ derive( PartialEq, Eq, Debug, Clone, Copy ) ] pub struct Interval< T = isize > where T : EndPointTrait< T >, isize : Into< T >, { + /// Left _left : Bound< T >, + /// Right _right : Bound< T >, } @@ -185,15 +199,18 @@ mod private isize : Into< T >, { /// Constructor of an interval. Expects closed interval in arguments. + #[ allow( unknown_lints, clippy::implicit_return ) ] + #[ inline ] pub fn new( left : Bound< T >, right : Bound< T > ) -> Self { Self { _left : left, _right : right } } /// Convert to interval in canonical format. + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] pub fn iter< It >( &self ) -> impl Iterator< Item = T > { - ( &self ).into_iter() + self.into_iter() } } @@ -208,6 +225,7 @@ mod private { type Item = T; type IntoIter = IntervalIterator< T >; + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn into_iter( self ) -> Self::IntoIter { @@ -222,6 +240,7 @@ mod private { type Item = T; type IntoIter = IntervalIterator< T >; + #[ allow( unknown_lints, clippy::implicit_return ) ] #[ inline( always ) ] fn into_iter( self ) -> Self::IntoIter { @@ -229,13 +248,16 @@ mod private } } + /// qqq: Documentation #[ derive( Debug ) ] pub struct IntervalIterator< T > where T : EndPointTrait< T >, isize : Into< T >, { + /// current current : T, + /// right right : T, } @@ -245,6 +267,7 @@ mod private isize : Into< T >, { /// Constructor. + #[ allow( clippy::used_underscore_binding, clippy::implicit_return ) ] pub fn new( ins : Interval< T > ) -> Self { let current = ins._left.into_left_closed(); @@ -253,12 +276,14 @@ mod private } } + #[ allow( clippy::missing_trait_methods ) ] impl< T > Iterator for IntervalIterator< T > where T : EndPointTrait< T >, isize : Into< T >, { type Item = T; + #[ allow( clippy::implicit_return, clippy::arithmetic_side_effects ) ] #[ inline( always ) ] fn next( &mut self ) -> Option< Self::Item > { @@ -298,17 +323,20 @@ mod private // } // } + #[ allow( clippy::used_underscore_binding, clippy::missing_trait_methods ) ] impl< T > NonIterableInterval< T > for Interval< T > where T : EndPointTrait< T >, isize : Into< T >, { + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn left( &self ) -> Bound< T > { self._left } + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn right( &self ) -> Bound< T > { @@ -316,17 +344,20 @@ mod private } } + #[ allow( clippy::missing_trait_methods ) ] impl< T > NonIterableInterval< T > for core::ops::Range< T > where T : EndPointTrait< T >, isize : Into< T >, { + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn left( &self ) -> Bound< T > { Bound::Included( self.start ) } + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn right( &self ) -> Bound< T > { @@ -334,17 +365,20 @@ mod private } } + #[ allow( clippy::missing_trait_methods ) ] impl< T > NonIterableInterval< T > for core::ops::RangeInclusive< T > where T : EndPointTrait< T >, isize : Into< T >, { + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn left( &self ) -> Bound< T > { Bound::Included( *self.start() ) } + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn right( &self ) -> Bound< T > { @@ -352,17 +386,20 @@ mod private } } + #[ allow( clippy::missing_trait_methods ) ] impl< T > NonIterableInterval< T > for core::ops::RangeTo< T > where T : EndPointTrait< T >, isize : Into< T >, { + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn left( &self ) -> Bound< T > { Bound::Unbounded } + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn right( &self ) -> Bound< T > { @@ -370,17 +407,20 @@ mod private } } + #[ allow( clippy::missing_trait_methods ) ] impl< T > NonIterableInterval< T > for core::ops::RangeToInclusive< T > where T : EndPointTrait< T >, isize : Into< T >, { + #[ allow( clippy::implicit_return ) ] #[ inline( always ) ] fn left( &self ) -> Bound< T > { Bound::Unbounded } + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn right( &self ) -> Bound< T > { @@ -388,17 +428,20 @@ mod private } } + #[allow( clippy::missing_trait_methods ) ] impl< T > NonIterableInterval< T > for core::ops::RangeFrom< T > where T : EndPointTrait< T >, isize : Into< T >, { + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn left( &self ) -> Bound< T > { Bound::Included( self.start ) } + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn right( &self ) -> Bound< T > { @@ -406,17 +449,20 @@ mod private } } + #[ allow( clippy::missing_trait_methods ) ] impl< T > NonIterableInterval< T > for core::ops::RangeFull where T : EndPointTrait< T >, isize : Into< T >, { + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn left( &self ) -> Bound< T > { Bound::Unbounded } + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn right( &self ) -> Bound< T > { @@ -424,17 +470,20 @@ mod private } } + #[ allow( clippy::missing_trait_methods ) ] impl< T > NonIterableInterval< T > for ( T, T ) where T : EndPointTrait< T >, isize : Into< T >, { + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn left( &self ) -> Bound< T > { Bound::Included( self.0 ) } + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn right( &self ) -> Bound< T > { @@ -442,17 +491,22 @@ mod private } } + #[ allow( clippy::missing_trait_methods ) ] impl< T > NonIterableInterval< T > for ( Bound< T >, Bound< T > ) where T : EndPointTrait< T >, isize : Into< T >, { + #[ allow( unknown_lints )] + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn left( &self ) -> Bound< T > { self.0 } + #[ allow( unknown_lints )] + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn right( &self ) -> Bound< T > { @@ -460,17 +514,21 @@ mod private } } + #[ allow( clippy::missing_trait_methods ) ] impl< T > NonIterableInterval< T > for [ T ; 2 ] where T : EndPointTrait< T >, isize : Into< T >, { + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn left( &self ) -> Bound< T > { Bound::Included( self[ 0 ] ) } + #[ allow( unknown_lints )] + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn right( &self ) -> Bound< T > { @@ -478,17 +536,20 @@ mod private } } + #[ allow( clippy::missing_trait_methods ) ] impl< T > NonIterableInterval< T > for [ Bound< T > ; 2 ] where T : EndPointTrait< T >, isize : Into< T >, { + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn left( &self ) -> Bound< T > { self[ 0 ] } + #[ allow( clippy::implicit_return )] #[ inline( always ) ] fn right( &self ) -> Bound< T > { @@ -499,7 +560,7 @@ mod private // = // from for std // = - + /// qqq: documentation macro_rules! impl_interval_from { {} => {}; @@ -519,7 +580,7 @@ mod private { let _left = NonIterableInterval::left( &src ); let _right = NonIterableInterval::right( &src ); - Self { _left, _right } + return Self { _left, _right } } } }; @@ -564,6 +625,9 @@ mod private isize : Into< T >, Interval< T > : From< Self >, { + #[ allow( unknown_lints )] + #[ allow( clippy::implicit_return )] + #[ inline ] fn into_interval( self ) -> Interval< T > { From::from( self ) @@ -576,6 +640,7 @@ mod private #[ allow( unused_imports ) ] #[ cfg( feature = "enabled" ) ] // #[ allow( unused_imports ) ] +#[ allow( clippy::pub_use ) ] pub use own::*; /// Own namespace of the module. @@ -583,7 +648,8 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { - use super::*; + use super::orphan; + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] #[ doc( inline ) ] pub use orphan::*; } @@ -593,8 +659,9 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { - use super::*; + use super::exposed; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use exposed::*; } @@ -603,10 +670,12 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { - use super::*; + use super::{ prelude, private }; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use prelude::*; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use private:: { Bound, @@ -620,7 +689,7 @@ pub mod exposed } // #[ doc( inline ) ] -#[ allow( unused_imports ) ] +// #[ allow( unused_imports ) ] // #[ cfg( feature = "enabled" ) ] // #[ allow( unused_imports ) ] // pub use exposed::*; @@ -630,8 +699,9 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { - use super::*; + use super::private; #[ doc( inline ) ] + #[ allow( clippy::useless_attribute, clippy::pub_use ) ] pub use private:: { IterableInterval, diff --git a/module/core/iter_tools/Readme.md b/module/core/iter_tools/Readme.md index 4aaebd7c0f..cafefb8cc7 100644 --- a/module/core/iter_tools/Readme.md +++ b/module/core/iter_tools/Readme.md @@ -1,6 +1,6 @@ -# Module :: iter_tools +# Module :: `iter_tools` [![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_iter_tools_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_iter_tools_push.yml) [![docs.rs](https://img.shields.io/docsrs/iter_tools?color=e3e8f0&logo=docs.rs)](https://docs.rs/iter_tools) [![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%2Fiter_tools%2Fexamples%2Fiter_tools_trivial.rs,RUN_POSTFIX=--example%20iter_tools_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) @@ -50,7 +50,7 @@ cd wTools cd examples/iter_tools_trivial cargo run ``` -` + ### Try out from the repository diff --git a/module/core/iter_tools/src/iter.rs b/module/core/iter_tools/src/iter.rs index 727e18409f..62b0294989 100644 --- a/module/core/iter_tools/src/iter.rs +++ b/module/core/iter_tools/src/iter.rs @@ -173,6 +173,8 @@ mod private Self : core::iter::Iterator, { /// Iterate each element and return `core::Result::Err` if any element is error. + /// # Errors + /// qqq: errors fn map_result< F, RE, El >( self, f : F ) -> core::result::Result< Vec< El >, RE > where Self : Sized + Clone, @@ -209,6 +211,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -219,6 +222,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -269,7 +273,7 @@ pub mod orphan #[ cfg( not( feature = "no_std" ) ) ] #[ doc( inline ) ] - pub use std::iter::zip; + pub use core::iter::zip; } @@ -277,6 +281,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -306,6 +311,7 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] diff --git a/module/core/iter_tools/src/lib.rs b/module/core/iter_tools/src/lib.rs index caa22f5593..e4b744172f 100644 --- a/module/core/iter_tools/src/lib.rs +++ b/module/core/iter_tools/src/lib.rs @@ -32,6 +32,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -48,6 +49,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -58,6 +60,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use prelude::*; diff --git a/module/core/macro_tools/Readme.md b/module/core/macro_tools/Readme.md index 6d148200b3..8cb337367c 100644 --- a/module/core/macro_tools/Readme.md +++ b/module/core/macro_tools/Readme.md @@ -1,6 +1,6 @@ -# Module :: proc_macro_tools +# Module :: `proc_macro_tools` [![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_macro_tools_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_macro_tools_push.yml) [![docs.rs](https://img.shields.io/docsrs/macro_tools?color=e3e8f0&logo=docs.rs)](https://docs.rs/macro_tools) [![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%2Fmacro_tools%2Fexamples%2Fmacro_tools_trivial.rs,RUN_POSTFIX=--example%20macro_tools_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) @@ -67,10 +67,10 @@ using reusable components like `AttributePropertyBoolean`. - `AttributeComponent`: A trait that defines how an attribute should be parsed from a `syn::Attribute`. - `AttributePropertyComponent`: A trait that defines a marker for attribute properties. - `Assign`: A trait that simplifies the logic of assigning fields to a struct. Using a -component-based approach requires each field to have a unique type, which aligns with the -strengths of strongly-typed languages. This method ensures that the logic of -assigning values to fields is encapsulated within the fields themselves, promoting modularity -and reusability. + component-based approach requires each field to have a unique type, which aligns with the + strengths of strongly-typed languages. This method ensures that the logic of + assigning values to fields is encapsulated within the fields themselves, promoting modularity + and reusability. The reusable property components from the library come with parameters that distinguish different properties of the same type. This is useful when an attribute has multiple boolean diff --git a/module/core/macro_tools/src/attr.rs b/module/core/macro_tools/src/attr.rs index d87c7865b2..e2edde225f 100644 --- a/module/core/macro_tools/src/attr.rs +++ b/module/core/macro_tools/src/attr.rs @@ -2,9 +2,10 @@ //! Attributes analyzys and manipulation. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// Checks if the given iterator of attributes contains an attribute named `debug`. @@ -48,7 +49,8 @@ mod private /// /// assert!( contains_debug, "Expected to find 'debug' attribute" ); /// ``` - /// + /// # Errors + /// qqq: doc pub fn has_debug< 'a >( attrs : impl Iterator< Item = &'a syn::Attribute > ) -> syn::Result< bool > { @@ -56,7 +58,7 @@ mod private { if let Some( ident ) = attr.path().get_ident() { - let ident_string = format!( "{}", ident ); + let ident_string = format!( "{ident}" ); if ident_string == "debug" { return Ok( true ) @@ -67,7 +69,7 @@ mod private return_syn_err!( "Unknown structure attribute:\n{}", qt!{ attr } ); } } - return Ok( false ) + Ok( false ) } /// Checks if the given attribute name is a standard Rust attribute. @@ -110,8 +112,9 @@ mod private /// assert_eq!( macro_tools::attr::is_standard( "my_attribute" ), false ); /// ``` /// - - pub fn is_standard<'a>( attr_name : &'a str ) -> bool + #[ must_use ] + #[ allow( clippy::match_same_arms ) ] + pub fn is_standard( attr_name : &str ) -> bool { match attr_name { @@ -199,6 +202,7 @@ mod private } } + #[ allow( clippy::iter_without_into_iter ) ] impl AttributesInner { /// Iterator @@ -208,6 +212,7 @@ mod private } } + #[ allow( clippy::default_trait_access ) ] impl syn::parse::Parse for AttributesInner { @@ -274,6 +279,7 @@ mod private } } + #[ allow( clippy::iter_without_into_iter ) ] impl AttributesOuter { /// Iterator @@ -283,6 +289,7 @@ mod private } } + #[ allow( clippy::default_trait_access ) ] impl syn::parse::Parse for AttributesOuter { @@ -425,6 +432,9 @@ mod private /// # Returns /// /// A `syn::Result` containing the constructed component if successful, or an error if the parsing fails. + /// + /// # Errors + /// qqq: doc fn from_meta( attr : &syn::Attribute ) -> syn::Result< Self >; // zzz : redo maybe @@ -440,6 +450,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -456,6 +467,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -465,6 +477,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::attr; diff --git a/module/core/macro_tools/src/attr_prop.rs b/module/core/macro_tools/src/attr_prop.rs index a5e3aeaecd..e981e9803a 100644 --- a/module/core/macro_tools/src/attr_prop.rs +++ b/module/core/macro_tools/src/attr_prop.rs @@ -102,7 +102,7 @@ mod boolean_optional; mod syn; mod syn_optional; -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::*; @@ -151,6 +151,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -164,6 +165,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -173,6 +175,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::attr_prop; diff --git a/module/core/macro_tools/src/attr_prop/boolean.rs b/module/core/macro_tools/src/attr_prop/boolean.rs index fa786b990d..d57917b576 100644 --- a/module/core/macro_tools/src/attr_prop/boolean.rs +++ b/module/core/macro_tools/src/attr_prop/boolean.rs @@ -3,6 +3,8 @@ //! Defaults to `false`. //! +use core::marker::PhantomData; +#[ allow( clippy::wildcard_imports ) ] use crate::*; // use former_types::Assign; @@ -114,6 +116,7 @@ pub struct AttributePropertyBoolean< Marker = AttributePropertyBooleanMarker >( impl< Marker > AttributePropertyBoolean< Marker > { /// Just unwraps and returns the internal data. + #[ must_use ] #[ inline( always ) ] pub fn internal( self ) -> bool { @@ -122,6 +125,7 @@ impl< Marker > AttributePropertyBoolean< Marker > /// Returns a reference to the internal boolean value. #[ inline( always ) ] + #[ must_use ] pub fn ref_internal( &self ) -> &bool { &self.0 @@ -160,9 +164,10 @@ impl< Marker > syn::parse::Parse for AttributePropertyBoolean< Marker > impl< Marker > From< bool > for AttributePropertyBoolean< Marker > { #[ inline( always ) ] + #[ allow( clippy::default_constructed_unit_structs ) ] fn from( src : bool ) -> Self { - Self( src, Default::default() ) + Self( src, PhantomData::default() ) } } diff --git a/module/core/macro_tools/src/attr_prop/boolean_optional.rs b/module/core/macro_tools/src/attr_prop/boolean_optional.rs index e695db40dd..bbc953c63a 100644 --- a/module/core/macro_tools/src/attr_prop/boolean_optional.rs +++ b/module/core/macro_tools/src/attr_prop/boolean_optional.rs @@ -2,7 +2,8 @@ //! A generic optional boolean attribute property: `Option< bool >`. //! Defaults to `false`. //! - +use core::marker::PhantomData; +#[ allow( clippy::wildcard_imports ) ] use crate::*; use components::Assign; @@ -19,6 +20,7 @@ pub struct AttributePropertyOptionalBoolean< Marker = AttributePropertyOptionalB impl< Marker > AttributePropertyOptionalBoolean< Marker > { /// Just unwraps and returns the internal data. + #[ must_use ] #[ inline( always ) ] pub fn internal( self ) -> Option< bool > { @@ -26,6 +28,7 @@ impl< Marker > AttributePropertyOptionalBoolean< Marker > } /// Returns a reference to the internal optional boolean value. + #[ must_use ] #[ inline( always ) ] pub fn ref_internal( &self ) -> Option< &bool > { @@ -42,6 +45,7 @@ where /// Inserts value of another instance into the option if it is None, then returns a mutable reference to the contained value. /// If another instance does is None then do nothing. #[ inline( always ) ] + #[ allow( clippy::single_match ) ] fn assign( &mut self, component : IntoT ) { let component = component.into(); @@ -73,18 +77,20 @@ impl< Marker > syn::parse::Parse for AttributePropertyOptionalBoolean< Marker > impl< Marker > From< bool > for AttributePropertyOptionalBoolean< Marker > { #[ inline( always ) ] + #[ allow( clippy::default_constructed_unit_structs ) ] fn from( src : bool ) -> Self { - Self( Some( src ), Default::default() ) + Self( Some( src ), PhantomData::default() ) } } impl< Marker > From< Option< bool > > for AttributePropertyOptionalBoolean< Marker > { #[ inline( always ) ] + #[ allow( clippy::default_constructed_unit_structs ) ] fn from( src : Option< bool > ) -> Self { - Self( src, Default::default() ) + Self( src, PhantomData::default() ) } } diff --git a/module/core/macro_tools/src/attr_prop/singletone.rs b/module/core/macro_tools/src/attr_prop/singletone.rs index 0e6970bdd0..1ee3d86266 100644 --- a/module/core/macro_tools/src/attr_prop/singletone.rs +++ b/module/core/macro_tools/src/attr_prop/singletone.rs @@ -11,6 +11,8 @@ //! //! This is useful for attributes that need to enable or disable features or flags. +use core::marker::PhantomData; +#[ allow( clippy::wildcard_imports ) ] use crate::*; // use former_types::Assign; @@ -35,6 +37,7 @@ impl< Marker > AttributePropertySingletone< Marker > { /// Unwraps and returns the internal optional boolean value. + #[ must_use ] #[ inline( always ) ] pub fn internal( self ) -> bool { @@ -42,6 +45,7 @@ impl< Marker > AttributePropertySingletone< Marker > } /// Returns a reference to the internal optional boolean value. + #[ must_use ] #[ inline( always ) ] pub fn ref_internal( &self ) -> &bool { @@ -72,9 +76,10 @@ where impl< Marker > From< bool > for AttributePropertySingletone< Marker > { #[ inline( always ) ] + #[ allow( clippy::default_constructed_unit_structs ) ] fn from( src : bool ) -> Self { - Self( src, Default::default() ) + Self( src, PhantomData::default() ) } } diff --git a/module/core/macro_tools/src/attr_prop/singletone_optional.rs b/module/core/macro_tools/src/attr_prop/singletone_optional.rs index 7d500cc94f..0761d65233 100644 --- a/module/core/macro_tools/src/attr_prop/singletone_optional.rs +++ b/module/core/macro_tools/src/attr_prop/singletone_optional.rs @@ -12,7 +12,8 @@ //! ``` //! //! This is useful for attributes that need to enable or disable features or flags. - +use core::marker::PhantomData; +#[ allow( clippy::wildcard_imports ) ] use crate::*; // use former_types::Assign; @@ -39,7 +40,10 @@ impl< Marker > AttributePropertyOptionalSingletone< Marker > { /// Return bool value: on/off, use argument as default if it's `None`. + /// # Panics + /// qqq: doc #[ inline ] + #[ must_use ] pub fn value( self, default : bool ) -> bool { if self.0.is_none() @@ -51,12 +55,14 @@ impl< Marker > AttributePropertyOptionalSingletone< Marker > /// Unwraps and returns the internal optional boolean value. #[ inline( always ) ] + #[ must_use ] pub fn internal( self ) -> Option< bool > { self.0 } /// Returns a reference to the internal optional boolean value. + #[ must_use ] #[ inline( always ) ] pub fn ref_internal( &self ) -> Option< &bool > { @@ -73,6 +79,7 @@ where /// Inserts value of another instance into the option if it is None, then returns a mutable reference to the contained value. /// If another instance does is None then do nothing. #[ inline( always ) ] + #[ allow( clippy::single_match ) ] fn assign( &mut self, component : IntoT ) { let component = component.into(); @@ -94,18 +101,20 @@ where impl< Marker > From< bool > for AttributePropertyOptionalSingletone< Marker > { #[ inline( always ) ] + #[ allow( clippy::default_constructed_unit_structs ) ] fn from( src : bool ) -> Self { - Self( Some( src ), Default::default() ) + Self( Some( src ), PhantomData::default() ) } } impl< Marker > From< Option< bool > > for AttributePropertyOptionalSingletone< Marker > { #[ inline( always ) ] + #[ allow( clippy::default_constructed_unit_structs ) ] fn from( src : Option< bool > ) -> Self { - Self( src, Default::default() ) + Self( src, PhantomData::default() ) } } diff --git a/module/core/macro_tools/src/attr_prop/syn.rs b/module/core/macro_tools/src/attr_prop/syn.rs index 183ead1a3a..4427a83f22 100644 --- a/module/core/macro_tools/src/attr_prop/syn.rs +++ b/module/core/macro_tools/src/attr_prop/syn.rs @@ -2,6 +2,8 @@ //! Property of an attribute which simply wraps one of the standard `syn` types. //! +use core::marker::PhantomData; +#[ allow( clippy::wildcard_imports ) ] use crate::*; // use former_types::Assign; @@ -108,8 +110,9 @@ impl< T, Marker > From< T > for AttributePropertySyn< T, Marker > where T : syn::parse::Parse + quote::ToTokens { #[ inline( always ) ] + #[ allow( clippy::default_constructed_unit_structs ) ] fn from( src : T ) -> Self { - Self( src, Default::default() ) + Self( src, PhantomData::default() ) } } diff --git a/module/core/macro_tools/src/attr_prop/syn_optional.rs b/module/core/macro_tools/src/attr_prop/syn_optional.rs index 4e5bba2783..e95e46b779 100644 --- a/module/core/macro_tools/src/attr_prop/syn_optional.rs +++ b/module/core/macro_tools/src/attr_prop/syn_optional.rs @@ -1,7 +1,8 @@ //! //! Property of an attribute which simply wraps one of the standard `syn` types and keeps it optional. //! - +use core::marker::PhantomData; +#[ allow( clippy::wildcard_imports ) ] use crate::*; // use former_types::Assign; @@ -46,6 +47,7 @@ where { /// Inserts value of another instance into the option if it is None, then returns a mutable reference to the contained value. /// If another instance does is None then do nothing. + #[ allow( clippy::single_match ) ] #[ inline( always ) ] fn assign( &mut self, component : IntoT ) { @@ -70,9 +72,10 @@ impl< T, Marker > Default for AttributePropertyOptionalSyn< T, Marker > where T : syn::parse::Parse + quote::ToTokens, { + #[ allow( clippy::default_constructed_unit_structs ) ] fn default() -> Self { - Self( None, Default::default() ) + Self( None, PhantomData::default() ) } } @@ -123,9 +126,10 @@ impl< T, Marker > From< T > for AttributePropertyOptionalSyn< T, Marker > where T : syn::parse::Parse + quote::ToTokens { #[ inline( always ) ] + #[ allow( clippy::default_constructed_unit_structs ) ] fn from( src : T ) -> Self { - Self( Some( src ), Default::default() ) + Self( Some( src ), PhantomData::default() ) } } @@ -133,9 +137,10 @@ impl< T, Marker > From< Option< T > > for AttributePropertyOptionalSyn< T, Marke where T : syn::parse::Parse + quote::ToTokens { #[ inline( always ) ] + #[ allow( clippy::default_constructed_unit_structs ) ] fn from( src : Option< T > ) -> Self { - Self( src, Default::default() ) + Self( src, PhantomData::default() ) } } diff --git a/module/core/macro_tools/src/components.rs b/module/core/macro_tools/src/components.rs index 5ff8c6fbe5..7d744f57c1 100644 --- a/module/core/macro_tools/src/components.rs +++ b/module/core/macro_tools/src/components.rs @@ -2,7 +2,7 @@ //! Type-based assigning. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } @@ -15,6 +15,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -31,6 +32,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -40,6 +42,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::components; diff --git a/module/core/macro_tools/src/container_kind.rs b/module/core/macro_tools/src/container_kind.rs index b7cedc6149..a2e1de1297 100644 --- a/module/core/macro_tools/src/container_kind.rs +++ b/module/core/macro_tools/src/container_kind.rs @@ -2,9 +2,10 @@ //! Determine kind of a container. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; // use crate::type_rightmost; @@ -39,7 +40,9 @@ mod private /// let kind = container_kind::of_type( &tree_type ); /// assert_eq!( kind, container_kind::ContainerKind::HashMap ); /// ``` - + /// # Panics + /// qqq: doc + #[ must_use ] pub fn of_type( ty : &syn::Type ) -> ContainerKind { @@ -61,7 +64,7 @@ mod private ContainerKind::No } - /// Return kind of container specified by type. Unlike [of_type] it also understand optional types. + /// Return kind of container specified by type. Unlike [`of_type`] it also understand optional types. /// /// Good to verify `Option< alloc::vec::Vec< i32 > >` is optional vector. /// @@ -75,13 +78,16 @@ mod private /// assert_eq!( kind, container_kind::ContainerKind::HashMap ); /// assert_eq!( optional, true ); /// ``` + /// # Panics + /// qqq: doc + #[ must_use ] pub fn of_optional( ty : &syn::Type ) -> ( ContainerKind, bool ) { if typ::type_rightmost( ty ) == Some( "Option".to_string() ) { - let ty2 = typ::type_parameters( ty, 0 ..= 0 ).first().copied(); + let ty2 = typ::type_parameters( ty, &( 0 ..= 0 ) ).first().copied(); // inspect_type::inspect_type_of!( ty2 ); if ty2.is_none() { @@ -104,6 +110,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -122,6 +129,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -131,6 +139,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::container_kind; diff --git a/module/core/macro_tools/src/ct.rs b/module/core/macro_tools/src/ct.rs index dd3778e29b..4083f7321c 100644 --- a/module/core/macro_tools/src/ct.rs +++ b/module/core/macro_tools/src/ct.rs @@ -2,7 +2,7 @@ //! Compile-time tools. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } @@ -19,6 +19,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -35,6 +36,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -44,6 +46,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::ct; diff --git a/module/core/macro_tools/src/derive.rs b/module/core/macro_tools/src/derive.rs index 84ab933fb4..7dd8888d61 100644 --- a/module/core/macro_tools/src/derive.rs +++ b/module/core/macro_tools/src/derive.rs @@ -2,9 +2,10 @@ //! Macro helpers around derive macro and structure [`syn::DeriveInput`]. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use syn::punctuated::Punctuated; @@ -24,8 +25,10 @@ mod private /// }; /// let fields = derive.named_fields( &ast ); /// ``` + /// # Errors + /// qqq: doc - pub fn named_fields< 'a >( ast : &'a syn::DeriveInput ) -> crate::Result< &'a Punctuated< syn::Field, syn::token::Comma > > + pub fn named_fields( ast : &syn::DeriveInput ) -> crate::Result< &Punctuated< syn::Field, syn::token::Comma > > { let fields = match ast.data @@ -54,6 +57,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -70,6 +74,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -79,6 +84,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::derive; @@ -96,6 +102,7 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] diff --git a/module/core/macro_tools/src/diag.rs b/module/core/macro_tools/src/diag.rs index 0f8fa6f6e8..40a3afb1bf 100644 --- a/module/core/macro_tools/src/diag.rs +++ b/module/core/macro_tools/src/diag.rs @@ -2,9 +2,10 @@ //! Macro helpers. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// Adds indentation and optional prefix/postfix to each line of the given string. @@ -62,17 +63,17 @@ mod private { if b.0 > 0 { - a.push_str( "\n" ); + a.push( '\n' ); } a.push_str( prefix ); - a.push_str( &b.1 ); + a.push_str( b.1 ); a.push_str( postfix ); a }); - if src.ends_with( "\n" ) || src.ends_with( "\n\r" ) || src.ends_with( "\r\n" ) + if src.ends_with( '\n' ) || src.ends_with( "\n\r" ) || src.ends_with( "\r\n" ) { - result.push_str( "\n" ); + result.push( '\n' ); result.push_str( prefix ); result.push_str( postfix ); } @@ -128,11 +129,12 @@ mod private /// }; /// /// // Format the debug report for printing or logging - /// let formatted_report = report_format( "Code Transformation for MyStruct", original_input, generated_code ); + /// let formatted_report = report_format( &"Code Transformation for MyStruct", &original_input, generated_code ); /// println!( "{}", formatted_report ); /// ``` /// + #[ allow( clippy::needless_pass_by_value ) ] pub fn report_format< IntoAbout, IntoInput, IntoOutput > ( about : IntoAbout, input : IntoInput, output : IntoOutput @@ -142,7 +144,7 @@ mod private IntoInput : ToString, IntoOutput : ToString, { - format!( "\n" ) + + "\n".to_string() + &format!( " = context\n\n{}\n\n", indentation( " ", about.to_string(), "" ) ) + &format!( " = original\n\n{}\n\n", indentation( " ", input.to_string(), "" ) ) + &format!( " = generated\n\n{}\n", indentation( " ", output.to_string(), "" ) ) @@ -384,6 +386,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -395,6 +398,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -412,6 +416,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::diag; @@ -432,6 +437,7 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] diff --git a/module/core/macro_tools/src/equation.rs b/module/core/macro_tools/src/equation.rs index 6a419dfe07..ae7080efdb 100644 --- a/module/core/macro_tools/src/equation.rs +++ b/module/core/macro_tools/src/equation.rs @@ -2,9 +2,10 @@ //! Attributes analyzys and manipulation. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// Represents an equation parsed from a procedural macro input. @@ -85,7 +86,7 @@ mod private /// /// For attribute like `#[former( default = 31 ) ]` return key `default` and value `31`, - /// as well as syn::Meta as the last element of result tuple. + /// as well as `syn::Meta` as the last element of result tuple. /// /// ### Basic use-case. /// @@ -96,19 +97,20 @@ mod private /// let got = equation::from_meta( &attr ).unwrap(); /// assert_eq!( macro_tools::code_to_str!( got ), "default = 31".to_string() ); /// ``` - + /// # Errors + /// qqq: doc pub fn from_meta( attr : &syn::Attribute ) -> Result< Equation > { let meta = &attr.meta; - return match meta + match meta { syn::Meta::List( ref meta_list ) => { let eq : Equation = syn::parse2( meta_list.tokens.clone() )?; Ok( eq ) } - _ => return Err( syn::Error::new( attr.span(), "Unknown format of attribute, expected syn::Meta::List( meta_list )" ) ), - }; + _ => Err( syn::Error::new( attr.span(), "Unknown format of attribute, expected syn::Meta::List( meta_list )" ) ), + } } } @@ -121,6 +123,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -135,6 +138,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -144,6 +148,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::equation; diff --git a/module/core/macro_tools/src/generic_args.rs b/module/core/macro_tools/src/generic_args.rs index 16636e8ac0..b07b22c5d3 100644 --- a/module/core/macro_tools/src/generic_args.rs +++ b/module/core/macro_tools/src/generic_args.rs @@ -2,7 +2,7 @@ //! This module provides utilities to handle and manipulate generic arguments using the `syn` crate. It includes traits and functions for transforming, merging, and managing generic parameters within procedural macros, enabling seamless syntactic analysis and code generation. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -24,6 +24,7 @@ mod private /// # Returns /// A new instance of `syn::AngleBracketedGenericArguments` representing the generic parameters /// of the original type. + #[ allow( clippy::wrong_self_convention ) ] fn into_generic_args( &self ) -> syn::AngleBracketedGenericArguments; } @@ -98,6 +99,7 @@ mod private /// /// This example demonstrates how lifetimes `'a` and `'b` are placed before other generic parameters /// like `T`, `U`, and `V` in the merged result, adhering to the expected syntax order in Rust generics. + #[ must_use ] pub fn merge ( a : &syn::AngleBracketedGenericArguments, @@ -110,7 +112,7 @@ mod private // Function to categorize and collect arguments into lifetimes and others let mut categorize_and_collect = |args : &syn::punctuated::Punctuated| { - for arg in args.iter() + for arg in args { match arg { @@ -148,6 +150,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -163,6 +166,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; diff --git a/module/core/macro_tools/src/generic_params.rs b/module/core/macro_tools/src/generic_params.rs index 599b5ca7cb..401fd0d326 100644 --- a/module/core/macro_tools/src/generic_params.rs +++ b/module/core/macro_tools/src/generic_params.rs @@ -2,9 +2,10 @@ //! Functions and structures to handle and manipulate generic parameters using the `syn` crate. It's designed to support macro-driven code generation by simplifying, merging, extracting, and decomposing `syn::Generics`. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use crate::IterTrait; // use iter_tools::IterTrait; @@ -36,12 +37,15 @@ mod private impl GenericsWithWhere { /// Unwraps the `GenericsWithWhere` to retrieve the inner `syn::Generics`. + #[ must_use ] pub fn unwrap( self ) -> syn::Generics { self.generics } /// Parses a string to a `GenericsWithWhere`, specifically designed to handle generics syntax with where clauses effectively. + /// # Errors + /// qqq: doc pub fn parse_from_str( s : &str ) -> syn::Result< GenericsWithWhere > { syn::parse_str::< GenericsWithWhere >( s ) @@ -109,27 +113,29 @@ mod private /// # Examples /// /// - /// # use syn::{Generics, parse_quote}; + /// # use `syn::{Generics`, `parse_quote`}; /// - /// let mut generics_a : syn::Generics = parse_quote!{ < T : Clone, U : Default > }; - /// generics_a.where_clause = parse_quote!{ where T : Default }; - /// let mut generics_b : syn::Generics = parse_quote!{ < V : core::fmt::Debug > }; - /// generics_b.where_clause = parse_quote!{ where V : Sized }; - /// let got = generic_params::merge( &generics_a, &generics_b ); + /// let mut `generics_a` : `syn::Generics` = `parse_quote`!{ < T : Clone, U : Default > }; + /// `generics_a.where_clause` = `parse_quote`!{ where T : Default }; + /// let mut `generics_b` : `syn::Generics` = `parse_quote`!{ < V : `core::fmt::Debug` > }; + /// `generics_b.where_clause` = `parse_quote`!{ where V : Sized }; + /// let got = `generic_params::merge`( &`generics_a`, &`generics_b` ); /// - /// let mut exp : syn::Generics = parse_quote! + /// let mut exp : `syn::Generics` = `parse_quote`! /// { - /// < T : Clone, U : Default, V : core::fmt::Debug > + /// < T : Clone, U : Default, V : `core::fmt::Debug` > /// }; - /// exp.where_clause = parse_quote! + /// `exp.where_clause` = `parse_quote`! /// { /// where /// T : Default, /// V : Sized /// }; /// - /// assert_eq!( got, exp ); + /// `assert_eq`!( got, exp ); + #[ must_use ] + #[ allow( clippy::default_trait_access ) ] pub fn merge( a : &syn::Generics, b : &syn::Generics ) -> syn::Generics { @@ -205,6 +211,8 @@ mod private /// assert!( simplified_generics.where_clause.is_none() ); // Where clause is removed /// ``` + #[ allow( clippy::default_trait_access ) ] + #[ must_use ] pub fn only_names( generics : &syn::Generics ) -> syn::Generics { // use syn::{ Generics, GenericParam, LifetimeDef, TypeParam, ConstParam }; @@ -282,9 +290,9 @@ mod private /// &syn::Ident::new( "N", proc_macro2::Span::call_site() ) /// ]); /// ``` - - pub fn names< 'a >( generics : &'a syn::Generics ) - -> impl IterTrait< 'a, &'a syn::Ident > + #[ must_use ] + pub fn names( generics : &syn::Generics ) + -> impl IterTrait< '_, &syn::Ident > // -> std::iter::Map // < // syn::punctuated::Iter< 'a, syn::GenericParam >, @@ -388,6 +396,8 @@ mod private /// ``` /// + #[ allow( clippy::type_complexity ) ] + #[ must_use ] pub fn decompose ( generics : &syn::Generics, @@ -512,6 +522,7 @@ pub use own::*; /// Own namespace of the module. pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -530,6 +541,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; diff --git a/module/core/macro_tools/src/item.rs b/module/core/macro_tools/src/item.rs index 605124e8a5..45138346e9 100644 --- a/module/core/macro_tools/src/item.rs +++ b/module/core/macro_tools/src/item.rs @@ -3,9 +3,10 @@ //! to manipulate the structure of items, handle different kinds of fields, and provide a structured approach to //! organizing the codebase into different access levels. -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// Ensures the last field in a struct has a trailing comma. @@ -56,7 +57,7 @@ mod private /// } /// }.to_string() ); /// ``` - + #[ must_use ] pub fn ensure_comma( input : &syn::ItemStruct ) -> syn::ItemStruct { let mut new_input = input.clone(); // Clone the input to modify it @@ -66,16 +67,16 @@ mod private // Handle named fields syn::Fields::Named( syn::FieldsNamed { named, .. } ) => { - punctuated::ensure_trailing_comma( named ) + punctuated::ensure_trailing_comma( named ); }, // Handle unnamed fields (tuples) syn::Fields::Unnamed( syn::FieldsUnnamed { unnamed, .. } ) => { - punctuated::ensure_trailing_comma( unnamed ) + punctuated::ensure_trailing_comma( unnamed ); }, // Do nothing for unit structs syn::Fields::Unit => {} - } + }; new_input } @@ -90,6 +91,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -104,6 +106,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; diff --git a/module/core/macro_tools/src/item_struct.rs b/module/core/macro_tools/src/item_struct.rs index 1855fa67b3..09f8f2c7a5 100644 --- a/module/core/macro_tools/src/item_struct.rs +++ b/module/core/macro_tools/src/item_struct.rs @@ -2,16 +2,18 @@ //! Parse structures, like `struct { a : i32 }`. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; // use iter_tools::{ IterTrait, BoxedIter }; /// Extracts the types of each field into a vector. - pub fn field_types< 'a >( t : &'a syn::ItemStruct ) + #[ must_use ] + pub fn field_types( t : &syn::ItemStruct ) -> - impl IterTrait< 'a, &'a syn::Type > + impl IterTrait< '_, &syn::Type > // -> std::iter::Map // < // syn::punctuated::Iter< 'a, syn::Field >, @@ -22,7 +24,13 @@ mod private } /// Retrieves the names of each field, if they exist. - pub fn field_names< 'a >( t : &'a syn::ItemStruct ) -> Option< BoxedIter< 'a, &'a syn::Ident > > + /// # Errors + /// qqq: doc + /// # Panics + /// qqq: error + #[ allow( clippy::match_wildcard_for_single_variants ) ] + #[ must_use ] + pub fn field_names( t : &syn::ItemStruct ) -> Option< BoxedIter< '_, &syn::Ident > > { match &t.fields { @@ -35,6 +43,9 @@ mod private /// Retrieves the type of the first field of the struct. /// /// Returns the type if the struct has at least one field, otherwise returns an error. + /// # Errors + /// qqq + #[ allow( clippy::match_wildcard_for_single_variants ) ] pub fn first_field_type( t : &syn::ItemStruct ) -> Result< syn::Type > { let maybe_field = match t.fields @@ -49,13 +60,16 @@ mod private return Ok( field.ty.clone() ) } - return Err( syn_err!( t.span(), "Expects at least one field" ) ); + Err( syn_err!( t.span(), "Expects at least one field" ) ) } /// Retrieves the name of the first field of the struct, if available. /// /// Returns `Some` with the field identifier for named fields, or `None` for unnamed fields. /// Returns an error if the struct has no fields + /// # Errors + /// qqq: doc + #[ allow( clippy::match_wildcard_for_single_variants ) ] pub fn first_field_name( t : &syn::ItemStruct ) -> Result< Option< syn::Ident > > { let maybe_field = match t.fields @@ -70,7 +84,7 @@ mod private return Ok( field.ident.clone() ) } - return Err( syn_err!( t.span(), "Expects type for fields" ) ); + Err( syn_err!( t.span(), "Expects type for fields" ) ) } @@ -84,6 +98,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -101,6 +116,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -110,6 +126,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::item_struct; diff --git a/module/core/macro_tools/src/iter.rs b/module/core/macro_tools/src/iter.rs index 6ad9773801..587750de8a 100644 --- a/module/core/macro_tools/src/iter.rs +++ b/module/core/macro_tools/src/iter.rs @@ -2,7 +2,7 @@ //! Tailored iterator. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } @@ -15,6 +15,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -27,6 +28,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -36,6 +38,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; // pub use super::super::iter; diff --git a/module/core/macro_tools/src/kw.rs b/module/core/macro_tools/src/kw.rs index c7910e7571..9ae3e2abf2 100644 --- a/module/core/macro_tools/src/kw.rs +++ b/module/core/macro_tools/src/kw.rs @@ -2,7 +2,7 @@ //! Keywords //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::*; @@ -17,6 +17,7 @@ mod private // qqq : cover by test /// Check is string a keyword. + #[ must_use ] pub fn is( src : &str ) -> bool { KEYWORDS.contains( &src ) @@ -32,6 +33,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -41,6 +43,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -50,6 +53,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::kw; diff --git a/module/core/macro_tools/src/lib.rs b/module/core/macro_tools/src/lib.rs index a11fdf7f69..c3a663cf22 100644 --- a/module/core/macro_tools/src/lib.rs +++ b/module/core/macro_tools/src/lib.rs @@ -4,17 +4,18 @@ #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( feature = "enabled" ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// - /// Result with syn::Error. + /// Result with `syn::Error`. /// - pub type Result< T > = std::result::Result< T, syn::Error >; + pub type Result< T > = core::result::Result< T, syn::Error >; } @@ -63,7 +64,7 @@ pub mod typ; #[ cfg( all( feature = "enabled", feature = "typed" ) ) ] pub mod typed; -#[ cfg( all( feature = "enabled" ) ) ] +#[ cfg( feature = "enabled" ) ] pub mod iter; /// @@ -98,6 +99,7 @@ pub mod own mod _all { + #[ allow( clippy::wildcard_imports ) ] use super::super::*; pub use orphan::*; @@ -167,6 +169,7 @@ pub mod orphan mod _all { + #[ allow( clippy::wildcard_imports ) ] use super::super::*; pub use exposed::*; } @@ -185,6 +188,7 @@ pub mod exposed mod _all { + #[ allow( clippy::wildcard_imports ) ] use super::super::*; pub use prelude::*; @@ -249,6 +253,7 @@ pub mod prelude mod _all { + #[ allow( clippy::wildcard_imports ) ] use super::super::*; // pub use prelude::*; diff --git a/module/core/macro_tools/src/name.rs b/module/core/macro_tools/src/name.rs index a9f53887b0..ae70cba3f8 100644 --- a/module/core/macro_tools/src/name.rs +++ b/module/core/macro_tools/src/name.rs @@ -2,7 +2,7 @@ //! Tait to getn name of an Item. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -39,7 +39,7 @@ mod private syn::Item::Union( item ) => item.name(), // syn::Item::Use( item ) => item.name(), // syn::Item::Verbatim( item ) => item.name(), - _ => "".into(), + _ => String::new(), } } } @@ -51,7 +51,7 @@ mod private let first = self.segments.first(); if first.is_none() { - return "".into() + return String::new() } let first = first.unwrap(); first.ident.to_string() @@ -104,7 +104,7 @@ mod private { if self.trait_.is_none() { - return "".into() + return String::new() } let t = self.trait_.as_ref().unwrap(); t.1.name() @@ -117,7 +117,7 @@ mod private { if self.ident.is_none() { - return "".to_string() + return String::new() } let ident = self.ident.as_ref().unwrap(); ident.to_string() @@ -232,6 +232,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -241,6 +242,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -250,6 +252,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::name; @@ -263,6 +266,7 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] #[ allow( unused_imports ) ] diff --git a/module/core/macro_tools/src/phantom.rs b/module/core/macro_tools/src/phantom.rs index f4bc1ec350..4f52f3d5fa 100644 --- a/module/core/macro_tools/src/phantom.rs +++ b/module/core/macro_tools/src/phantom.rs @@ -4,9 +4,10 @@ //! Functions and structures to handle and manipulate `PhantomData` fields in structs using the `syn` crate. These utilities ensure that generic parameters are correctly accounted for in type checking, even if they are not directly used in the struct's fields. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// Adds a `PhantomData` field to a struct to manage generic parameter usage. @@ -42,7 +43,8 @@ mod private /// // Output will include a _phantom field of type `PhantomData< ( T, U ) >` /// ``` /// - + #[ allow( clippy::default_trait_access, clippy::semicolon_if_nothing_returned ) ] + #[ must_use ] pub fn add_to_item( input : &syn::ItemStruct ) -> syn::ItemStruct { @@ -136,6 +138,8 @@ mod private /// // Output : ::core::marker::PhantomData< ( &'a (), *const T, N ) > /// ``` /// + #[ must_use ] + #[ allow( clippy::default_trait_access ) ] pub fn tuple( input : &syn::punctuated::Punctuated< syn::GenericParam, syn::token::Comma > ) -> syn::Type { use proc_macro2::Span; @@ -198,6 +202,7 @@ pub use own::*; /// Own namespace of the module. pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -214,6 +219,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; diff --git a/module/core/macro_tools/src/punctuated.rs b/module/core/macro_tools/src/punctuated.rs index 2257904a81..a2c3fa0c8a 100644 --- a/module/core/macro_tools/src/punctuated.rs +++ b/module/core/macro_tools/src/punctuated.rs @@ -4,7 +4,7 @@ //! This module provides functionality to manipulate and ensure correct punctuation in `syn::punctuated::Punctuated` collections, commonly used in procedural macros to represent sequences of elements separated by punctuation marks, such as commas. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -28,6 +28,7 @@ pub use own::*; /// Own namespace of the module. pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -43,6 +44,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; diff --git a/module/core/macro_tools/src/quantifier.rs b/module/core/macro_tools/src/quantifier.rs index 379c38e9a4..030074314a 100644 --- a/module/core/macro_tools/src/quantifier.rs +++ b/module/core/macro_tools/src/quantifier.rs @@ -2,9 +2,10 @@ //! Quantifiers like Pair and Many. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// @@ -105,11 +106,13 @@ mod private T : Element, { /// Constructor. + #[ must_use ] pub fn new() -> Self { Self( Vec::new() ) } /// Constructor. + #[ must_use ] pub fn new_with( src : Vec< T > ) -> Self { Self( src ) @@ -148,6 +151,7 @@ mod private T : quote::ToTokens, { type Item = T; + #[ allow( clippy::std_instead_of_alloc ) ] type IntoIter = std::vec::IntoIter< Self::Item >; fn into_iter( self ) -> Self::IntoIter { @@ -253,6 +257,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -262,6 +267,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -271,6 +277,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::quantifier; @@ -291,6 +298,7 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use private:: diff --git a/module/core/macro_tools/src/struct_like.rs b/module/core/macro_tools/src/struct_like.rs index 1ec494be89..321fbffee3 100644 --- a/module/core/macro_tools/src/struct_like.rs +++ b/module/core/macro_tools/src/struct_like.rs @@ -2,9 +2,10 @@ //! Parse structures, like `struct { a : i32 }`. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// Enum to encapsulate either a field from a struct or a variant from an enum. @@ -59,6 +60,7 @@ mod private { /// Returns a reference to the attributes of the item. + #[ must_use ] pub fn attrs( &self ) -> &Vec< syn::Attribute > { match self @@ -69,6 +71,7 @@ mod private } /// Returns a reference to the visibility of the item. + #[ must_use ] pub fn vis( &self ) -> Option< &syn::Visibility > { match self @@ -79,6 +82,7 @@ mod private } /// Returns a reference to the mutability of the item. + #[ must_use ] pub fn mutability( &self ) -> Option< &syn::FieldMutability > { match self @@ -89,6 +93,7 @@ mod private } /// Returns a reference to the identifier of the item. + #[ must_use] pub fn ident( &self ) -> Option< &syn::Ident > { match self @@ -99,6 +104,7 @@ mod private } /// Returns an iterator over elements of the item. + #[ must_use ] pub fn typ( &self ) -> Option< &syn::Type > { match self @@ -115,6 +121,7 @@ mod private } /// Returns a reference to the fields of the item. + #[ must_use ] pub fn fields( &self ) -> Option< &syn::Fields > { match self @@ -125,6 +132,7 @@ mod private } /// Returns a reference to the discriminant of the item. + #[ must_use ] pub fn discriminant( &self ) -> Option< &( syn::token::Eq, syn::Expr ) > { match self @@ -202,7 +210,7 @@ mod private // Parse ItemStruct let mut item_struct : ItemStruct = input.parse()?; item_struct.vis = visibility; - item_struct.attrs = attributes.into(); + item_struct.attrs = attributes; if item_struct.fields.is_empty() { Ok( StructLike::Unit( item_struct ) ) @@ -217,7 +225,7 @@ mod private // Parse ItemEnum let mut item_enum : ItemEnum = input.parse()?; item_enum.vis = visibility; - item_enum.attrs = attributes.into(); + item_enum.attrs = attributes; Ok( StructLike::Enum( item_enum ) ) } else @@ -274,14 +282,12 @@ mod private } /// Returns an iterator over elements of the item. + #[ must_use ] pub fn attrs( &self ) -> &Vec< syn::Attribute > { match self { - StructLike::Unit( item ) => - { - &item.attrs - }, + StructLike::Unit( item ) | StructLike::Struct( item ) => { &item.attrs @@ -294,14 +300,12 @@ mod private } /// Returns an iterator over elements of the item. + #[ must_use ] pub fn vis( &self ) -> &syn::Visibility { match self { - StructLike::Unit( item ) => - { - &item.vis - }, + StructLike::Unit( item ) | StructLike::Struct( item ) => { &item.vis @@ -314,14 +318,12 @@ mod private } /// Returns an iterator over elements of the item. + #[ must_use ] pub fn ident( &self ) -> &syn::Ident { match self { - StructLike::Unit( item ) => - { - &item.ident - }, + StructLike::Unit( item ) | StructLike::Struct( item ) => { &item.ident @@ -334,14 +336,12 @@ mod private } /// Returns an iterator over elements of the item. + #[ must_use ] pub fn generics( &self ) -> &syn::Generics { match self { - StructLike::Unit( item ) => - { - &item.generics - }, + StructLike::Unit( item ) | StructLike::Struct( item ) => { &item.generics @@ -355,13 +355,14 @@ mod private /// Returns an iterator over fields of the item. // pub fn fields< 'a >( &'a self ) -> impl IterTrait< 'a, &'a syn::Field > + #[ must_use ] pub fn fields< 'a >( &'a self ) -> BoxedIter< 'a, &'a syn::Field > { let result : BoxedIter< 'a, &'a syn::Field > = match self { StructLike::Unit( _item ) => { - Box::new( std::iter::empty() ) + Box::new( core::iter::empty() ) }, StructLike::Struct( item ) => { @@ -369,22 +370,22 @@ mod private }, StructLike::Enum( _item ) => { - Box::new( std::iter::empty() ) + Box::new( core::iter::empty() ) }, }; result } /// Extracts the name of each field. + /// # Panics + /// qqq: docs // pub fn field_names< 'a >( &'a self ) -> Option< impl IterTrait< 'a, &'a syn::Ident > + '_ > - pub fn field_names< 'a >( &'a self ) -> Option< BoxedIter< 'a, &'a syn::Ident >> + #[ must_use ] + pub fn field_names( &self ) -> Option< BoxedIter< '_, &syn::Ident >> { match self { - StructLike::Unit( item ) => - { - item_struct::field_names( item ) - }, + StructLike::Unit( item ) | StructLike::Struct( item ) => { item_struct::field_names( item ) @@ -398,8 +399,9 @@ mod private } /// Extracts the type of each field. - pub fn field_types<'a>( &'a self ) - -> BoxedIter< 'a, &'a syn::Type > + #[ must_use ] + pub fn field_types( & self ) + -> BoxedIter< '_, & syn::Type > // -> std::iter::Map // < // std::boxed::Box< dyn _IterTrait< '_, &syn::Field > + 'a >, @@ -411,8 +413,9 @@ mod private /// Extracts the name of each field. // 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 > > + #[ must_use ] + pub fn field_attrs( & self ) + -> BoxedIter< '_, &Vec< syn::Attribute > > // -> std::iter::Map // < // std::boxed::Box< dyn _IterTrait< '_, &syn::Field > + 'a >, @@ -423,6 +426,7 @@ mod private } /// Extract the first field. + #[ must_use ] pub fn first_field( &self ) -> Option< &syn::Field > { self.fields().next() @@ -443,6 +447,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -458,6 +463,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -467,6 +473,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::struct_like; diff --git a/module/core/macro_tools/src/tokens.rs b/module/core/macro_tools/src/tokens.rs index 0d7fd568e8..cfb52da63f 100644 --- a/module/core/macro_tools/src/tokens.rs +++ b/module/core/macro_tools/src/tokens.rs @@ -2,9 +2,10 @@ //! Attributes analyzys and manipulation. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use core::fmt; @@ -32,6 +33,7 @@ mod private impl Tokens { /// Constructor from `proc_macro2::TokenStream`. + #[ must_use ] pub fn new( inner : proc_macro2::TokenStream ) -> Self { Tokens { inner } @@ -59,7 +61,7 @@ mod private { fn fmt( &self, f : &mut fmt::Formatter< '_ > ) -> fmt::Result { - write!( f, "{}", self.inner.to_string() ) + write!( f, "{}", self.inner ) } } @@ -67,7 +69,7 @@ mod private { fn fmt( &self, f : &mut core::fmt::Formatter< '_ > ) -> core::fmt::Result { - write!( f, "{}", self.inner.to_string() ) + write!( f, "{}", self.inner ) } } @@ -81,6 +83,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -90,6 +93,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -99,6 +103,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::tokens; diff --git a/module/core/macro_tools/src/typ.rs b/module/core/macro_tools/src/typ.rs index 03b535081e..3a2e710808 100644 --- a/module/core/macro_tools/src/typ.rs +++ b/module/core/macro_tools/src/typ.rs @@ -2,9 +2,10 @@ //! Advanced syntax elements. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use interval_adapter::BoundExt; @@ -22,7 +23,9 @@ mod private /// let got = typ::type_rightmost( &tree_type ); /// assert_eq!( got, Some( "Option".to_string() ) ); /// ``` - + /// # Panics + /// qqq: doc + #[ must_use ] pub fn type_rightmost( ty : &syn::Type ) -> Option< String > { if let syn::Type::Path( path ) = ty @@ -53,8 +56,10 @@ mod private /// // < i16 /// // < i32 /// ``` - - pub fn type_parameters( ty : &syn::Type, range : impl NonIterableInterval ) -> Vec< &syn::Type > + /// # Panics + /// qqq: doc + #[ allow( clippy::cast_possible_wrap ) ] + pub fn type_parameters< 'a >( ty : &'a syn::Type, range : &'a impl NonIterableInterval ) -> Vec< &'a syn::Type > { if let syn::Type::Path( syn::TypePath{ path : syn::Path { ref segments, .. }, .. } ) = ty { @@ -104,7 +109,7 @@ mod private /// assert!( macro_tools::typ::is_optional( &parsed_type ) ); /// ``` /// - + #[ must_use ] pub fn is_optional( ty : &syn::Type ) -> bool { typ::type_rightmost( ty ) == Some( "Option".to_string() ) @@ -124,10 +129,11 @@ mod private /// let first_param = macro_tools::typ::parameter_first( &parsed_type ).expect( "Should have at least one parameter" ); /// // Option< i32 > /// ``` - + /// # Errors + /// qqq: docs pub fn parameter_first( ty : &syn::Type ) -> Result< &syn::Type > { - typ::type_parameters( ty, 0 ..= 0 ) + typ::type_parameters( ty, &( 0 ..= 0 ) ) .first() .copied() .ok_or_else( || syn_err!( ty, "Expects at least one parameter here:\n {}", qt!{ #ty } ) ) @@ -143,6 +149,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -160,6 +167,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -169,6 +177,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::typ; diff --git a/module/core/macro_tools/src/typed.rs b/module/core/macro_tools/src/typed.rs index 3eeeba271f..c5d2d05c3c 100644 --- a/module/core/macro_tools/src/typed.rs +++ b/module/core/macro_tools/src/typed.rs @@ -2,7 +2,7 @@ //! Typed parsing. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::*; @@ -17,6 +17,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] @@ -35,6 +36,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -44,6 +46,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::super::typed; diff --git a/module/core/mem_tools/Cargo.toml b/module/core/mem_tools/Cargo.toml index cec41724d4..ba71b5759a 100644 --- a/module/core/mem_tools/Cargo.toml +++ b/module/core/mem_tools/Cargo.toml @@ -24,7 +24,6 @@ workspace = true features = [ "full" ] all-features = false - include = [ "/rust/impl/mem", "/Cargo.toml", diff --git a/module/core/mem_tools/src/lib.rs b/module/core/mem_tools/src/lib.rs index 03270e0a05..141da61a9d 100644 --- a/module/core/mem_tools/src/lib.rs +++ b/module/core/mem_tools/src/lib.rs @@ -37,7 +37,6 @@ pub mod own #[ doc( inline ) ] pub use orphan::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super::mem::orphan::*; } @@ -60,7 +59,6 @@ pub mod exposed #[ doc( inline ) ] pub use prelude::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super::mem::exposed::*; } @@ -71,6 +69,5 @@ pub mod prelude { use super::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super::mem::prelude::*; } diff --git a/module/core/mem_tools/src/mem.rs b/module/core/mem_tools/src/mem.rs index e35cb611cd..3a48ddad8b 100644 --- a/module/core/mem_tools/src/mem.rs +++ b/module/core/mem_tools/src/mem.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; @@ -64,30 +64,28 @@ mod private } +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +pub use own::*; + /// Own namespace of the module. #[ allow( unused_imports ) ] pub mod own { use super::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super:: { orphan::*, }; } -#[ doc( inline ) ] -#[ allow( unused_imports ) ] -pub use own::*; - /// Orphan namespace of the module. #[ allow( unused_imports ) ] pub mod orphan { use super::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super:: { exposed::*, @@ -103,6 +101,9 @@ pub mod orphan pub mod exposed { use super::*; + // Expose itself. + pub use super::super::mem; + #[ doc( inline ) ] pub use prelude::*; } diff --git a/module/core/meta_tools/Cargo.toml b/module/core/meta_tools/Cargo.toml index 0fc0b3c61d..ec2054076a 100644 --- a/module/core/meta_tools/Cargo.toml +++ b/module/core/meta_tools/Cargo.toml @@ -24,47 +24,45 @@ workspace = true features = [ "full" ] all-features = false - - [features] default = [ "enabled", "meta_for_each", "meta_impls_index", - # "meta_mod_interface", - "meta_constructors", + "mod_interface", "meta_idents_concat", ] full = [ "enabled", "meta_for_each", "meta_impls_index", - # "meta_mod_interface", - "meta_constructors", + "mod_interface", "meta_idents_concat", ] no_std = [] use_alloc = [ "no_std" ] -enabled = [] +enabled = [ + "for_each/enabled", + "impls_index/enabled", + "mod_interface/enabled", +] -meta_for_each = [ "for_each/enabled" ] -meta_impls_index = [ "impls_index/enabled" ] -meta_mod_interface = [ "mod_interface/enabled" ] -# xxx : qqq : make mod_interface optional maybe +meta_for_each = [ "for_each/enabled", "dep:for_each" ] +meta_impls_index = [ "impls_index/enabled", "dep:impls_index" ] +mod_interface = [ "mod_interface/enabled", "dep:mod_interface" ] -meta_constructors = [ "literally" ] -meta_idents_concat = [ "paste" ] +# meta_constructors = [ "literally" ] +meta_idents_concat = [ "dep:paste" ] [dependencies] -## external -literally = { version = "~0.1.3", optional = true, default-features = false } -paste = { version = "~1.0.14", optional = true, default-features = false } +# ## external +paste = { workspace = true, optional = true, default-features = false } ## internal -impls_index = { workspace = true } -for_each = { workspace = true } -mod_interface = { workspace = true, features = [ "default" ] } +for_each = { workspace = true, optional = true } +impls_index = { workspace = true, optional = true } +mod_interface = { workspace = true, optional = true } [dev-dependencies] test_tools = { workspace = true } diff --git a/module/core/meta_tools/Readme.md b/module/core/meta_tools/Readme.md index 0d472b069f..c43c980e94 100644 --- a/module/core/meta_tools/Readme.md +++ b/module/core/meta_tools/Readme.md @@ -7,21 +7,6 @@ Collection of general purpose meta tools. -### Basic use-case :: variadic constructor of collections - -Among other useful meta tools the module aggregates variadic constructors of collections. For example macro `hmap!` for constructing a hash map. - - - -```rust -use meta_tools::*; - -let meta_map = hmap! { 3 => 13 }; -let mut std_map = std::collections::HashMap::new(); -std_map.insert( 3, 13 ); -assert_eq!( meta_map, std_map ); -``` - ### Basic Use Case :: function-style call Apply a macro for each element of a list. diff --git a/module/core/meta_tools/examples/meta_tools_trivial.rs b/module/core/meta_tools/examples/meta_tools_trivial.rs index 75d17ddace..983e55c9d6 100644 --- a/module/core/meta_tools/examples/meta_tools_trivial.rs +++ b/module/core/meta_tools/examples/meta_tools_trivial.rs @@ -3,8 +3,10 @@ use meta_tools::*; fn main() { - let meta_map = hmap! { 3 => 13 }; - let mut std_map = std::collections::HashMap::new(); - std_map.insert( 3, 13 ); - assert_eq!( meta_map, std_map ); + for_each!( dbg, "a", "b", "c" ); + + // generates + dbg!( "a" ); + dbg!( "b" ); + dbg!( "c" ); } diff --git a/module/core/meta_tools/src/lib.rs b/module/core/meta_tools/src/lib.rs index 352f7e0f3b..e31d911ffe 100644 --- a/module/core/meta_tools/src/lib.rs +++ b/module/core/meta_tools/src/lib.rs @@ -10,35 +10,69 @@ pub mod dependency { - // #[ cfg( feature = "meta_mod_interface" ) ] pub use ::mod_interface; #[ cfg( feature = "meta_for_each" ) ] pub use ::for_each; #[ cfg( feature = "meta_impls_index" ) ] pub use ::impls_index; - - #[ cfg( feature = "meta_constructors" ) ] - pub use ::literally; #[ cfg( feature = "meta_idents_concat" ) ] pub use ::paste; - // #[ cfg( feature = "former" ) ] - // pub use ::former; - // #[ cfg( feature = "options" ) ] - // pub use ::woptions; - } mod private {} // -// qqq : meta interface should be optional dependancy. please fix writing equivalent code manually +// // qqq : meta interface should be optional dependancy. please fix writing equivalent code manually +// #[ cfg( feature = "enabled" ) ] +// mod_interface::mod_interface! +// { +// // #![ debug ] +// +// layer meta; +// +// } + +pub mod meta; + +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub use own::*; + +/// Own namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod own +{ + use super::*; + pub use meta::orphan::*; +} + +/// Orphan namespace of the module. #[ cfg( feature = "enabled" ) ] -mod_interface::mod_interface! +#[ allow( unused_imports ) ] +pub mod orphan { - // #![ debug ] + use super::*; + pub use exposed::*; +} - layer meta; +/// Exposed namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod exposed +{ + use super::*; + pub use prelude::*; + pub use meta::exposed::*; +} +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; + pub use meta::prelude::*; } diff --git a/module/core/meta_tools/src/meta.rs b/module/core/meta_tools/src/meta.rs index e05ad7deec..1047857beb 100644 --- a/module/core/meta_tools/src/meta.rs +++ b/module/core/meta_tools/src/meta.rs @@ -2,39 +2,82 @@ //! Collection of general purpose meta tools. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } // +// #[ cfg( feature = "enabled" ) ] +// mod_interface::mod_interface! +// { +// #![ debug ] +// +// #[ cfg( feature = "meta_impls_index" ) ] +// use ::impls_index; +// #[ cfg( feature = "meta_for_each" ) ] +// use ::for_each; +// // #[ cfg( feature = "meta_mod_interface" ) ] +// use ::mod_interface; +// // #[ cfg( feature = "meta_mod_interface" ) ] +// prelude use ::mod_interface::mod_interface; +// +// #[ cfg( feature = "meta_idents_concat" ) ] +// prelude use ::paste::paste as meta_idents_concat; +// +// } + +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub use own::*; + +/// Own namespace of the module. +#[ cfg( feature = "enabled" ) ] +pub mod own +{ + use super::*; + pub use ::impls_index::orphan::*; + pub use ::for_each::orphan::*; + pub use ::mod_interface::orphan::*; + pub use orphan::*; +} + +/// Orphan namespace of the module. #[ cfg( feature = "enabled" ) ] -mod_interface::mod_interface! +#[ allow( unused_imports ) ] +pub mod orphan { + use super::*; + + // pub use ::impls_index; + // pub use ::for_each; + // pub use ::mod_interface; - #[ cfg( feature = "meta_impls_index" ) ] - use ::impls_index; - #[ cfg( feature = "meta_for_each" ) ] - use ::for_each; - // #[ cfg( feature = "meta_mod_interface" ) ] - use ::mod_interface; - // #[ cfg( feature = "meta_mod_interface" ) ] - prelude use ::mod_interface::mod_interface; - - #[ cfg( feature = "meta_constructors" ) ] - prelude use ::literally::*; - #[ cfg( feature = "meta_idents_concat" ) ] - prelude use ::paste::paste as meta_idents_concat; - - // #[ cfg( feature = "options" ) ] - // use ::woptions; - // #[ cfg( feature = "options" ) ] - // prelude use ::woptions as options; - - // #[ cfg( feature = "former" ) ] - // use ::former; - // #[ cfg( feature = "former" ) ] - // prelude use ::former as former; + pub use exposed::*; +} +/// Exposed namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod exposed +{ + use super::*; + pub use prelude::*; + pub use super::super::meta; + pub use ::impls_index::exposed::*; + pub use ::for_each::exposed::*; + pub use ::mod_interface::exposed::*; + pub use ::paste::paste as meta_idents_concat; +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; + pub use ::impls_index::prelude::*; + pub use ::for_each::prelude::*; + pub use ::mod_interface::prelude::*; } diff --git a/module/core/meta_tools/tests/inc/meta_constructor_test.rs b/module/core/meta_tools/tests/inc/meta_constructor_test.rs index acee680259..d4cffdf307 100644 --- a/module/core/meta_tools/tests/inc/meta_constructor_test.rs +++ b/module/core/meta_tools/tests/inc/meta_constructor_test.rs @@ -1,50 +1,50 @@ -use super::*; - -// - -tests_impls! -{ - - fn hash_map() - { - - // test.case( "empty" ); - let got : std::collections::HashMap< i32, i32 > = the_module::hmap!{}; - let exp = std::collections::HashMap::new(); - a_id!( got, exp ); - - // test.case( "single entry" ); - let got = the_module::hmap!{ 3 => 13 }; - let mut exp = std::collections::HashMap::new(); - exp.insert( 3, 13 ); - a_id!( got, exp ); - - } - - // - - - fn hash_set() - { - - // test.case( "empty" ); - let got : std::collections::HashSet< i32 > = the_module::hset!{}; - let exp = std::collections::HashSet::new(); - a_id!( got, exp ); - - // test.case( "single entry" ); - let got = the_module::hset!{ 13 }; - let mut exp = std::collections::HashSet::new(); - exp.insert( 13 ); - a_id!( got, exp ); - - } -} - -// - -tests_index! -{ - hash_map, - hash_set, -} +// use super::*; +// +// // +// +// tests_impls! +// { +// +// fn hash_map() +// { +// +// // test.case( "empty" ); +// let got : std::collections::HashMap< i32, i32 > = the_module::hmap!{}; +// let exp = std::collections::HashMap::new(); +// a_id!( got, exp ); +// +// // test.case( "single entry" ); +// let got = the_module::hmap!{ 3 => 13 }; +// let mut exp = std::collections::HashMap::new(); +// exp.insert( 3, 13 ); +// a_id!( got, exp ); +// +// } +// +// // +// +// +// fn hash_set() +// { +// +// // test.case( "empty" ); +// let got : std::collections::HashSet< i32 > = the_module::hset!{}; +// let exp = std::collections::HashSet::new(); +// a_id!( got, exp ); +// +// // test.case( "single entry" ); +// let got = the_module::hset!{ 13 }; +// let mut exp = std::collections::HashSet::new(); +// exp.insert( 13 ); +// a_id!( got, exp ); +// +// } +// } +// +// // +// +// tests_index! +// { +// hash_map, +// hash_set, +// } diff --git a/module/core/meta_tools/tests/inc/mod.rs b/module/core/meta_tools/tests/inc/mod.rs index 9fc942d2c2..98e402d4c3 100644 --- a/module/core/meta_tools/tests/inc/mod.rs +++ b/module/core/meta_tools/tests/inc/mod.rs @@ -1,17 +1,17 @@ #[ allow( unused_imports ) ] use super::*; -#[ cfg( any( feature = "meta_constructors", feature = "meta_constructors" ) ) ] -mod meta_constructor_test; +// #[ cfg( any( feature = "meta_constructors", feature = "meta_constructors" ) ) ] +// mod meta_constructor_test; #[ cfg( any( feature = "meta_idents_concat", feature = "meta_idents_concat" ) ) ] mod indents_concat_test; -#[ cfg( any( feature = "for_each", feature = "meta_for_each" ) ) ] +#[ cfg( any( feature = "meta_for_each" ) ) ] #[ path = "../../../for_each/tests/inc/mod.rs" ] mod for_each_test; -#[ cfg( any( feature = "impls_index", feature = "meta_impls_index" ) ) ] +#[ cfg( any( feature = "meta_impls_index" ) ) ] #[ path = "../../../impls_index/tests/inc/mod.rs" ] mod impls_index; diff --git a/module/core/mod_interface/Readme.md b/module/core/mod_interface/Readme.md index 47115efb68..53e887fdd3 100644 --- a/module/core/mod_interface/Readme.md +++ b/module/core/mod_interface/Readme.md @@ -1,6 +1,6 @@ -# Module :: mod_interface +# Module :: `mod_interface` [![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_mod_interface_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_mod_interface_push.yml) [![docs.rs](https://img.shields.io/docsrs/mod_interface?color=e3e8f0&logo=docs.rs)](https://docs.rs/mod_interface) [![discord](https://img.shields.io/discord/872391416519737405?color=eee&logo=discord&logoColor=eee&label=ask)](https://discord.gg/m3YfbXpUUY) @@ -11,21 +11,51 @@ Protocol of modularity unifying interface. The `mod_interface` crate provides a structured approach to modularity, addressing two key challenges in software development: -1. **Meaningful Namespace Structuring**: The crate enables developers to organize program entities into meaningful namespaces ( read modules ) without additional development overhead. This is achieved through a set of auto-importing rules and a flexible inversion of control mechanism, allowing parent namespaces to delegate control over its items to child namespaces. This approach ensures that each namespace is self-contained and meaningful, promoting better organization and modularity. +1. **Meaningful Namespace Structuring**: The crate enables developers to organize program entities into meaningful namespaces ( read modules ) without additional development overhead. This is achieved through a set of auto-importing rules and a flexible inversion of control mechanism, allowing parent layers ( namespaces or modules ) to delegate control over its items to child layers. This approach ensures that each namespace is self-contained and meaningful, promoting better organization and modularity. 2. **Enhanced Readability and Tooling Independence**: By requiring a `mod private` section that lists all items ( read functions, structures, traits, types ) the `mod_interface` macro encourages developers to create a concise list of items at the beginning or end of a file. This improves readability, encourages refactoring, and reduces cognitive load by providing a clear, high-level grouping of items. Code tooling is not always reliable and can sometimes be counterproductive by automating tasks that should be done manually to achieve more concise code. While code tooling like `rust_analyzer` are useful, this approach minimizes reliance on them, making the program's structure easier to understand and manage. While some may argue that inversion of control over namespaces may not always achieve the desired outcome, and code tooling can be sufficient, the `mod_interface` crate offers a cathartic solution for designing complex systems where tooling and triditional structuring often fall short. By promoting a clear and organized structure, it helps developers grasp the semantics of their programs more holistically. -### Example : Trivial +### Basic Concepts -This example demonstrates how to use the `mod_interface` crate to organize a Rust program into structured namespaces. The code is divided into a library file (`child.rs`) and a main function. The library file defines a module with private functions and uses the `mod_interface` macro to specify which functions should be exposed in different namespaces. The main function then tests the visibility and accessibility of these functions. +In the `mod_interface` crate, the concepts of layers and namespaces are central to its modularity approach. Here's a refined explanation: + +- **Namespaces**: These are standard Rust modules that help organize code into logical groups. +- **Layers**: A layer is a specialized module that contains a set of predefined submodules, referred to as chapters. These chapters dictate how the contents of the module are propagated to parent layers. + +The chapters within a layer are: + +- **Private Chapter (`private`)**: This is where all the code and entities are initially defined. It is not accessible outside the module. +- **Public Chapter (`own`)**: Contains items that are not propagated to any parent layers. They remain within the module. +- **Public Chapter (`orphan`)**: Shares its contents with the immediate parent layer only. +- **Public Chapter (`exposed`)**: Propagates its contents to all parent layers, making them accessible throughout the hierarchy. +- **Public Chapter (`prelude`)**: Similar to `exposed`, but also serves as a recommendation for other crates to implicitly import its contents, akin to the prelude in the [Rust standard library](https://doc.rust-lang.org/std/prelude/index.html). + +Developers should define all entities within the `private` chapter and then re-export them through the other four chapters based on the desired propagation strategy. + +### Syntax of `mod_interface` Macro + +The `mod_interface` macro provides several directives to manage the relationships between layers and entities: + +- **`layer `**: Establishes a relationship where the current layer uses a child layer. +- **`use `**: Allows the current layer to use another layer defined elsewhere. +- **`reuse `**: Enables the current layer to reuse a layer defined anywhere, promoting code reuse. +- **` use `**: Allows the current layer to use an entity defined anywhere, with the specified promotion stategy (``). + +These directives provide flexibility in organizing and managing the modular structure of a Rust program, enhancing both readability and maintainability. + +### Example: Using Layers and Entities + +In this example, we demonstrate the basic use case of one layer utilizing another layer. For a module to be used as a layer, it must contain all the necessary chapters: `orphan`, `exposed`, and `prelude`. Generally, a layer should also have the `own` and `private` chapters, but these are typically not modified directly by the user unless explicitly defined, with the `private` chapter remaining inaccessible from outside the module. + +Below is a simple example where a parent layer imports a `child` layer. The `child` layer defines several functions, each with a different propagation strategy, resulting in each function being placed in a different chapter of the parent layer, while some functions do not reach the parent layer at all. ```rust use mod_interface::mod_interface; // Define a module named `child`. -mod child +pub mod child { // Define a private namespace for all its items. @@ -63,7 +93,7 @@ crate::mod_interface! } -fn main() +// fn main() { assert!( child::prelude_thing(), "prelude thing of child is there" ); @@ -125,29 +155,34 @@ pub mod child /// Own namespace of the module. pub mod own { - pub use super::orphan::*; - pub use super::private::my_thing; + use super::*; + pub use orphan::*; + pub use private::my_thing; } /// Orphan namespace of the module. pub mod orphan { - pub use super::exposed::*; - pub use super::private::orphan_thing; + use super::*; + pub use exposed::*; + pub use private::orphan_thing; } /// Exposed namespace of the module. pub mod exposed { - pub use super::prelude::*; - pub use super::private::exposed_thing; + use super::*; + pub use prelude::*; + pub use private::exposed_thing; } /// Prelude to use essentials: `use my_module::prelude::*`. pub mod prelude { - pub use super::private::prelude_thing; + use super::*; + pub use private::prelude_thing; } + } // Priave namespaces is necessary. @@ -162,6 +197,7 @@ pub mod own use super::*; pub use orphan::*; pub use super::child::orphan::*; + pub use super::child; } /// Orphan namespace of the module. @@ -178,7 +214,7 @@ pub mod exposed { use super::*; pub use prelude::*; - pub use super::child::exposed::*; + pub use child::exposed::*; } /// Prelude to use essentials: `use my_module::prelude::*`. @@ -186,12 +222,12 @@ pub mod exposed pub mod prelude { use super::*; - pub use super::child::prelude::*; + pub use child::prelude::*; } // -fn main() +// fn main() { assert!( child::prelude_thing(), "prelude thing of child is there" ); diff --git a/module/core/mod_interface/examples/mod_interface_trivial/Readme.md b/module/core/mod_interface/examples/mod_interface_trivial/Readme.md index 343322a31c..e7b67c25d1 100644 --- a/module/core/mod_interface/examples/mod_interface_trivial/Readme.md +++ b/module/core/mod_interface/examples/mod_interface_trivial/Readme.md @@ -1,11 +1,9 @@ -# Sample +### Example: Using Layers and Entities [![discord](https://img.shields.io/discord/872391416519737405?color=eee&logo=discord&logoColor=eee&label=ask)](https://discord.gg/m3YfbXpUUY) [![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%2Frust%2Fmod_interface_trivial,SAMPLE_FILE=.%2Fsrc%2Fmain.rs/https://github.com/Wandalen/wTools) [![docs.rs](https://raster.shields.io/static/v1?label=docs&message=online&color=eee&logo=docsdotrs&logoColor=eee)](https://docs.rs/mod_interface) -A sample demonstrates basic usage of macro `mod_interface`. +In this example, we demonstrate the basic use case of one layer utilizing another layer. For a module to be used as a layer, it must contain all the necessary chapters: `orphan`, `exposed`, and `prelude`. Generally, a layer should also have the `own` and `private` chapters, but these are typically not modified directly by the user unless explicitly defined, with the `private` chapter remaining inaccessible from outside the module. -In file `inner.rs` demonstrated how to generate module interface from namespace `private` and its public routine. - -In file `main.rs` demonstrated how to generate module interface from layer ( file with full module interface ). +Below is a simple example where a parent layer imports a `child` layer. The `child` layer defines several functions, each with a different propagation strategy, resulting in each function being placed in a different chapter of the parent layer, while some functions do not reach the parent layer at all. diff --git a/module/core/mod_interface/examples/mod_interface_trivial/src/main.rs b/module/core/mod_interface/examples/mod_interface_trivial/src/main.rs index 420a6c9fb4..f834f8b12f 100644 --- a/module/core/mod_interface/examples/mod_interface_trivial/src/main.rs +++ b/module/core/mod_interface/examples/mod_interface_trivial/src/main.rs @@ -3,7 +3,7 @@ use mod_interface::mod_interface; /// Children. -mod child; +pub mod child; // Priave namespaces is necessary. mod private {} diff --git a/module/core/mod_interface/src/lib.rs b/module/core/mod_interface/src/lib.rs index 726b166188..07820b8983 100644 --- a/module/core/mod_interface/src/lib.rs +++ b/module/core/mod_interface/src/lib.rs @@ -22,6 +22,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use orphan::*; @@ -37,6 +38,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use exposed::*; @@ -47,6 +49,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; #[ doc( inline ) ] pub use prelude::*; diff --git a/module/core/mod_interface/tests/inc/derive/attr_debug/mod.rs b/module/core/mod_interface/tests/inc/derive/attr_debug/mod.rs index 57b54aff39..7b425682cc 100644 --- a/module/core/mod_interface/tests/inc/derive/attr_debug/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/attr_debug/mod.rs @@ -3,7 +3,7 @@ use super::*; mod private {} -mod_interface! +the_module::mod_interface! { // #![ debug ] diff --git a/module/core/mod_interface/tests/inc/derive/layer/mod.rs b/module/core/mod_interface/tests/inc/derive/layer/mod.rs index d8e79fb20b..8a567560f7 100644 --- a/module/core/mod_interface/tests/inc/derive/layer/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/layer/mod.rs @@ -6,7 +6,7 @@ mod private { } -mod_interface! +the_module::mod_interface! { /// layer_a diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer/layer_a.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer/layer_a.rs index dfffa8d8a8..082005e6be 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer/layer_a.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer/layer_a.rs @@ -33,7 +33,7 @@ mod private // -mod_interface! +the_module::mod_interface! { // orphan use super::private:: diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer/layer_b.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer/layer_b.rs index 9f17f61637..1d265d3c4f 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer/layer_b.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer/layer_b.rs @@ -39,7 +39,7 @@ pub struct SubStruct2 // -mod_interface! +the_module::mod_interface! { own use layer_b_own; diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer/mod.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer/mod.rs index 6cf3f6db29..219360f435 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer/mod.rs @@ -11,7 +11,7 @@ mod private { } -mod_interface! +the_module::mod_interface! { /// layer_a diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/layer_a.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/layer_a.rs index dfffa8d8a8..082005e6be 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/layer_a.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/layer_a.rs @@ -33,7 +33,7 @@ mod private // -mod_interface! +the_module::mod_interface! { // orphan use super::private:: diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/layer_b.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/layer_b.rs index 9f17f61637..1d265d3c4f 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/layer_b.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/layer_b.rs @@ -39,7 +39,7 @@ pub struct SubStruct2 // -mod_interface! +the_module::mod_interface! { own use layer_b_own; diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/mod.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/mod.rs index 09c564f64b..b0fc4d5d70 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer_cfg/mod.rs @@ -11,7 +11,7 @@ mod private { } -mod_interface! +the_module::mod_interface! { /// layer_a diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/layer_a.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/layer_a.rs index 8d8d6b1faf..c71e0af7d2 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/layer_a.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/layer_a.rs @@ -33,7 +33,7 @@ mod private // -mod_interface! +the_module::mod_interface! { own use { layer_a_own }; diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/layer_b.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/layer_b.rs index 9f17f61637..1d265d3c4f 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/layer_b.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/layer_b.rs @@ -39,7 +39,7 @@ pub struct SubStruct2 // -mod_interface! +the_module::mod_interface! { own use layer_b_own; diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/mod.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/mod.rs index c34df1c831..0d2ec22d26 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use/mod.rs @@ -12,11 +12,11 @@ mod private } /// layer_a -mod layer_a; +pub mod layer_a; /// layer_b -mod layer_b; +pub mod layer_b; -mod_interface! +the_module::mod_interface! { /// layer_a diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/layer_a.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/layer_a.rs index 8d8d6b1faf..c71e0af7d2 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/layer_a.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/layer_a.rs @@ -33,7 +33,7 @@ mod private // -mod_interface! +the_module::mod_interface! { own use { layer_a_own }; diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/layer_b.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/layer_b.rs index 9f17f61637..1d265d3c4f 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/layer_b.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/layer_b.rs @@ -39,7 +39,7 @@ pub struct SubStruct2 // -mod_interface! +the_module::mod_interface! { own use layer_b_own; diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/mod.rs b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/mod.rs index 4774b23347..c20f8d770a 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_layer_separate_use_two/mod.rs @@ -12,11 +12,11 @@ mod private } /// layer_a -mod layer_a; +pub mod layer_a; /// layer_b -mod layer_b; +pub mod layer_b; -mod_interface! +the_module::mod_interface! { // zzz : test with `layer { layer_a, layer_a };` diff --git a/module/core/mod_interface/tests/inc/derive/layer_have_mod_cfg/mod.rs b/module/core/mod_interface/tests/inc/derive/layer_have_mod_cfg/mod.rs index 2188f4a6b3..38ff58d0eb 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_have_mod_cfg/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_have_mod_cfg/mod.rs @@ -11,7 +11,7 @@ mod private { } -mod_interface! +the_module::mod_interface! { /// mod_a diff --git a/module/core/mod_interface/tests/inc/derive/layer_unknown_vis/trybuild.stderr b/module/core/mod_interface/tests/inc/derive/layer_unknown_vis/trybuild.stderr index 2d2aa78ea8..125e29bbdb 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_unknown_vis/trybuild.stderr +++ b/module/core/mod_interface/tests/inc/derive/layer_unknown_vis/trybuild.stderr @@ -1,4 +1,4 @@ -error: expected one of: `mod`, `use`, `layer` +error: expected one of: `mod`, `use`, `layer`, `reuse` --> tests/inc/derive/layer_unknown_vis/mod.rs | | xyz layer layer_a; diff --git a/module/core/mod_interface/tests/inc/derive/layer_use_cfg/layer_a.rs b/module/core/mod_interface/tests/inc/derive/layer_use_cfg/layer_a.rs index dfffa8d8a8..082005e6be 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_use_cfg/layer_a.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_use_cfg/layer_a.rs @@ -33,7 +33,7 @@ mod private // -mod_interface! +the_module::mod_interface! { // orphan use super::private:: diff --git a/module/core/mod_interface/tests/inc/derive/layer_use_cfg/layer_b.rs b/module/core/mod_interface/tests/inc/derive/layer_use_cfg/layer_b.rs index 9f17f61637..1d265d3c4f 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_use_cfg/layer_b.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_use_cfg/layer_b.rs @@ -39,7 +39,7 @@ pub struct SubStruct2 // -mod_interface! +the_module::mod_interface! { own use layer_b_own; diff --git a/module/core/mod_interface/tests/inc/derive/layer_use_cfg/mod.rs b/module/core/mod_interface/tests/inc/derive/layer_use_cfg/mod.rs index 0c730db3a7..d9eedf0a3e 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_use_cfg/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_use_cfg/mod.rs @@ -12,12 +12,13 @@ mod private } /// layer_a -mod layer_a; +pub mod layer_a; /// layer_b -mod layer_b; +pub mod layer_b; -mod_interface! +the_module::mod_interface! { + // #![ debug ] /// layer_a use super::layer_a; @@ -33,4 +34,3 @@ mod_interface! // include!( "../../only_test/layer_simple_only_test.rs" ); - diff --git a/module/core/mod_interface/tests/inc/derive/layer_use_macro/layer_a.rs b/module/core/mod_interface/tests/inc/derive/layer_use_macro/layer_a.rs index 12db22ecfc..b37c839cd0 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_use_macro/layer_a.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_use_macro/layer_a.rs @@ -35,7 +35,7 @@ mod private // -mod_interface! +the_module::mod_interface! { // exposed( crate ) use macro1; diff --git a/module/core/mod_interface/tests/inc/derive/layer_use_macro/mod.rs b/module/core/mod_interface/tests/inc/derive/layer_use_macro/mod.rs index 1bb9569c90..67a972b145 100644 --- a/module/core/mod_interface/tests/inc/derive/layer_use_macro/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/layer_use_macro/mod.rs @@ -11,7 +11,7 @@ mod private { } -mod_interface! +the_module::mod_interface! { /// layer_a diff --git a/module/core/mod_interface/tests/inc/derive/micro_modules/mod.rs b/module/core/mod_interface/tests/inc/derive/micro_modules/mod.rs index 80d4c7218a..57adff6ff2 100644 --- a/module/core/mod_interface/tests/inc/derive/micro_modules/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/micro_modules/mod.rs @@ -6,7 +6,7 @@ mod private { } -mod_interface! +the_module::mod_interface! { // #![ debug ] diff --git a/module/core/mod_interface/tests/inc/derive/micro_modules_bad_vis/trybuild.stderr b/module/core/mod_interface/tests/inc/derive/micro_modules_bad_vis/trybuild.stderr index b84160eec0..d73c3c374c 100644 --- a/module/core/mod_interface/tests/inc/derive/micro_modules_bad_vis/trybuild.stderr +++ b/module/core/mod_interface/tests/inc/derive/micro_modules_bad_vis/trybuild.stderr @@ -1,4 +1,4 @@ -error: To include a non-standard module use either [ private, protected, orphan, exposed, prelude ] visibility: +error: To include a non-standard module use either [ private, own, orphan, exposed, prelude ] visibility: #[doc = " mod_exposed"] pub mod mod_exposed; --> tests/inc/derive/micro_modules_bad_vis/mod.rs | diff --git a/module/core/mod_interface/tests/inc/derive/micro_modules_glob/mod.rs b/module/core/mod_interface/tests/inc/derive/micro_modules_glob/mod.rs index 40ccb61f64..f567778739 100644 --- a/module/core/mod_interface/tests/inc/derive/micro_modules_glob/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/micro_modules_glob/mod.rs @@ -1,7 +1,7 @@ // use super::*; -/// Internal namespace. +/// Define a private namespace for all its items. mod private { pub struct Struct1; @@ -10,7 +10,7 @@ mod private // -crate::mod_interface! +crate::the_module::mod_interface! { own use { diff --git a/module/core/mod_interface/tests/inc/derive/micro_modules_two/mod.rs b/module/core/mod_interface/tests/inc/derive/micro_modules_two/mod.rs index 9071caf2d1..c62e6f7e18 100644 --- a/module/core/mod_interface/tests/inc/derive/micro_modules_two/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/micro_modules_two/mod.rs @@ -6,7 +6,7 @@ mod private { } -mod_interface! +the_module::mod_interface! { /// mod_own1 diff --git a/module/core/mod_interface/tests/inc/derive/micro_modules_two_joined/mod.rs b/module/core/mod_interface/tests/inc/derive/micro_modules_two_joined/mod.rs index ced5712479..de2d1c2e88 100644 --- a/module/core/mod_interface/tests/inc/derive/micro_modules_two_joined/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/micro_modules_two_joined/mod.rs @@ -6,7 +6,7 @@ mod private { } -mod_interface! +the_module::mod_interface! { own mod diff --git a/module/core/mod_interface/tests/inc/derive/micro_modules_unknown_vis/trybuild.stderr b/module/core/mod_interface/tests/inc/derive/micro_modules_unknown_vis/trybuild.stderr index 8df4ef8899..0fd927c7e0 100644 --- a/module/core/mod_interface/tests/inc/derive/micro_modules_unknown_vis/trybuild.stderr +++ b/module/core/mod_interface/tests/inc/derive/micro_modules_unknown_vis/trybuild.stderr @@ -1,4 +1,4 @@ -error: expected one of: `mod`, `use`, `layer` +error: expected one of: `mod`, `use`, `layer`, `reuse` --> tests/inc/derive/micro_modules_unknown_vis/mod.rs | | not_vis mod mod_exposed; diff --git a/module/core/mod_interface/tests/inc/derive/reuse_basic/child.rs b/module/core/mod_interface/tests/inc/derive/reuse_basic/child.rs index d94a40b5bd..19fcd7abde 100644 --- a/module/core/mod_interface/tests/inc/derive/reuse_basic/child.rs +++ b/module/core/mod_interface/tests/inc/derive/reuse_basic/child.rs @@ -6,7 +6,7 @@ mod private pub struct Prelude; } -crate::mod_interface! +crate::the_module::mod_interface! { own use Own; orphan use Orphan; diff --git a/module/core/mod_interface/tests/inc/derive/reuse_basic/mod.rs b/module/core/mod_interface/tests/inc/derive/reuse_basic/mod.rs index 55daeb2a1c..8ee5259142 100644 --- a/module/core/mod_interface/tests/inc/derive/reuse_basic/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/reuse_basic/mod.rs @@ -1,7 +1,7 @@ // use super::*; -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } @@ -10,7 +10,7 @@ mod child; // -crate::mod_interface! +crate::the_module::mod_interface! { reuse child; } diff --git a/module/core/mod_interface/tests/inc/derive/use_as/derive.rs b/module/core/mod_interface/tests/inc/derive/use_as/derive.rs index a70260fc3c..1d0b464591 100644 --- a/module/core/mod_interface/tests/inc/derive/use_as/derive.rs +++ b/module/core/mod_interface/tests/inc/derive/use_as/derive.rs @@ -6,7 +6,7 @@ pub mod layer_x; mod private {} -mod_interface! +the_module::mod_interface! { // #![ debug ] diff --git a/module/core/mod_interface/tests/inc/derive/use_bad_vis/trybuild.stderr b/module/core/mod_interface/tests/inc/derive/use_bad_vis/trybuild.stderr index b63d146f04..cb5d08876c 100644 --- a/module/core/mod_interface/tests/inc/derive/use_bad_vis/trybuild.stderr +++ b/module/core/mod_interface/tests/inc/derive/use_bad_vis/trybuild.stderr @@ -1,4 +1,4 @@ -error: Use either [ private, protected, orphan, exposed, prelude ] visibility: +error: Use either [ private, own, orphan, exposed, prelude ] visibility: #[doc = " layer_a"] pub use; --> tests/inc/derive/use_bad_vis/mod.rs | diff --git a/module/core/mod_interface/tests/inc/derive/use_basic/mod.rs b/module/core/mod_interface/tests/inc/derive/use_basic/mod.rs index fe3862d5b3..4afc8262c6 100644 --- a/module/core/mod_interface/tests/inc/derive/use_basic/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/use_basic/mod.rs @@ -1,12 +1,14 @@ use super::*; -mod layer_a; -mod layer_b; +// private layer +pub mod layer_a; +// private layer +pub mod layer_b; mod private {} -mod_interface! +the_module::mod_interface! { /// layer_a diff --git a/module/core/mod_interface/tests/inc/derive/use_layer/layer_a.rs b/module/core/mod_interface/tests/inc/derive/use_layer/layer_a.rs index 14ecb25b3e..1b892a03b1 100644 --- a/module/core/mod_interface/tests/inc/derive/use_layer/layer_a.rs +++ b/module/core/mod_interface/tests/inc/derive/use_layer/layer_a.rs @@ -34,7 +34,7 @@ pub struct SubStruct4 // -mod_interface! +the_module::mod_interface! { orphan use ::std::vec::Vec; diff --git a/module/core/mod_interface/tests/inc/derive/use_layer/mod.rs b/module/core/mod_interface/tests/inc/derive/use_layer/mod.rs index a7f1790c60..4b4bfaa581 100644 --- a/module/core/mod_interface/tests/inc/derive/use_layer/mod.rs +++ b/module/core/mod_interface/tests/inc/derive/use_layer/mod.rs @@ -6,7 +6,7 @@ mod tools pub use super::super::*; } -mod layer_a; +pub mod layer_a; /// SuperStruct1. #[ derive( Debug, PartialEq ) ] @@ -16,7 +16,7 @@ pub struct SuperStruct1 mod private {} -mod_interface! +the_module::mod_interface! { /// layer_a diff --git a/module/core/error_tools/src/untyped.rs b/module/core/mod_interface/tests/inc/derive/use_private_layers/layer_a.rs similarity index 63% rename from module/core/error_tools/src/untyped.rs rename to module/core/mod_interface/tests/inc/derive/use_private_layers/layer_a.rs index df16162bab..8c49982711 100644 --- a/module/core/error_tools/src/untyped.rs +++ b/module/core/mod_interface/tests/inc/derive/use_private_layers/layer_a.rs @@ -1,13 +1,9 @@ -/// Internal namespace. + +/// Private namespace of the module. mod private { - } -#[ doc( inline ) ] -#[ allow( unused_imports ) ] -pub use own::*; - /// Own namespace of the module. #[ allow( unused_imports ) ] pub mod own @@ -15,38 +11,29 @@ pub mod own use super::*; #[ doc( inline ) ] pub use orphan::*; - - #[ doc( inline ) ] - pub use ::anyhow:: + /// layer_a_own + pub fn layer_a_own() -> bool { - Chain, - Context, - Error, - Ok, - Result, - }; - + true + } } -/// Shared with parent namespace of the module +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +pub use own::*; + +/// Orphan namespace of the module. #[ allow( unused_imports ) ] pub mod orphan { use super::*; - pub use super::super::untyped; - pub use super::super::untyped as for_app; - #[ doc( inline ) ] pub use exposed::*; - - #[ doc( inline ) ] - pub use ::anyhow:: + /// layer_a_orphan + pub fn layer_a_orphan() -> bool { - format_err, - ensure, - bail, - }; - + true + } } /// Exposed namespace of the module. @@ -54,10 +41,13 @@ pub mod orphan pub mod exposed { use super::*; - #[ doc( inline ) ] pub use prelude::*; - + /// layer_a_exposed + pub fn layer_a_exposed() -> bool + { + true + } } /// Prelude to use essentials: `use my_module::prelude::*`. @@ -65,4 +55,9 @@ pub mod exposed pub mod prelude { use super::*; -} \ No newline at end of file + /// layer_a_prelude + pub fn layer_a_prelude() -> bool + { + true + } +} diff --git a/module/core/error_tools/src/typed.rs b/module/core/mod_interface/tests/inc/derive/use_private_layers/layer_b.rs similarity index 62% rename from module/core/error_tools/src/typed.rs rename to module/core/mod_interface/tests/inc/derive/use_private_layers/layer_b.rs index e4e341a586..1e15689f05 100644 --- a/module/core/error_tools/src/typed.rs +++ b/module/core/mod_interface/tests/inc/derive/use_private_layers/layer_b.rs @@ -1,13 +1,9 @@ -/// Internal namespace. + +/// Private namespace of the module. mod private { - } -#[ doc( inline ) ] -#[ allow( unused_imports ) ] -pub use own::*; - /// Own namespace of the module. #[ allow( unused_imports ) ] pub mod own @@ -15,26 +11,29 @@ pub mod own use super::*; #[ doc( inline ) ] pub use orphan::*; + /// layer_b_own + pub fn layer_b_own() -> bool + { + true + } } -/// Shared with parent namespace of the module +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +pub use own::*; + +/// Orphan namespace of the module. #[ allow( unused_imports ) ] pub mod orphan { use super::*; - pub use super::super::typed; - pub use super::super::typed as for_lib; - #[ doc( inline ) ] pub use exposed::*; - - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use ::thiserror:: + /// layer_b_orphan + pub fn layer_b_orphan() -> bool { - Error, - }; - + true + } } /// Exposed namespace of the module. @@ -42,10 +41,13 @@ pub mod orphan pub mod exposed { use super::*; - #[ doc( inline ) ] pub use prelude::*; - + /// layer_b_exposed + pub fn layer_b_exposed() -> bool + { + true + } } /// Prelude to use essentials: `use my_module::prelude::*`. @@ -53,9 +55,9 @@ pub mod exposed pub mod prelude { use super::*; - - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use thiserror; - -} \ No newline at end of file + /// layer_b_prelude + pub fn layer_b_prelude() -> bool + { + true + } +} diff --git a/module/core/mod_interface/tests/inc/derive/use_private_layers/mod.rs b/module/core/mod_interface/tests/inc/derive/use_private_layers/mod.rs new file mode 100644 index 0000000000..531513253f --- /dev/null +++ b/module/core/mod_interface/tests/inc/derive/use_private_layers/mod.rs @@ -0,0 +1,28 @@ +#![ allow( dead_code ) ] +#![ allow( unused_imports ) ] + +use super::*; + +// private layer +mod layer_a; +// private layer +mod layer_b; + +mod private {} + +// xxx : qqq : make it working + +// the_module::mod_interface! +// { +// +// /// layer_a +// priv use super::layer_a; +// +// /// layer_b +// priv use super::layer_b; +// +// } +// +// // +// +// include!( "../../only_test/layer_simple_only_test.rs" ); diff --git a/module/core/mod_interface/tests/inc/derive/use_unknown_vis/trybuild.stderr b/module/core/mod_interface/tests/inc/derive/use_unknown_vis/trybuild.stderr index 530570d39a..0dc9fb08bc 100644 --- a/module/core/mod_interface/tests/inc/derive/use_unknown_vis/trybuild.stderr +++ b/module/core/mod_interface/tests/inc/derive/use_unknown_vis/trybuild.stderr @@ -1,4 +1,4 @@ -error: expected one of: `mod`, `use`, `layer` +error: expected one of: `mod`, `use`, `layer`, `reuse` --> tests/inc/derive/use_unknown_vis/mod.rs | | xyz use f1; diff --git a/module/core/mod_interface/tests/inc/manual/layer/mod.rs b/module/core/mod_interface/tests/inc/manual/layer/mod.rs index 044ff08dbf..adb8be65df 100644 --- a/module/core/mod_interface/tests/inc/manual/layer/mod.rs +++ b/module/core/mod_interface/tests/inc/manual/layer/mod.rs @@ -19,11 +19,13 @@ pub mod own #[ doc( inline ) ] pub use orphan::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super::layer_a::orphan::*; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use super::layer_b::orphan::*; + #[ doc( inline ) ] + pub use super::layer_a; + #[ doc( inline ) ] + pub use super::layer_b; } #[ doc( inline ) ] diff --git a/module/core/mod_interface/tests/inc/manual/micro_modules/mod.rs b/module/core/mod_interface/tests/inc/manual/micro_modules/mod.rs index 65ba341ba1..5aa53251a1 100644 --- a/module/core/mod_interface/tests/inc/manual/micro_modules/mod.rs +++ b/module/core/mod_interface/tests/inc/manual/micro_modules/mod.rs @@ -1,3 +1,4 @@ +#![ allow( dead_code ) ] use super::*; diff --git a/module/core/mod_interface/tests/inc/manual/layer_use/layer_a.rs b/module/core/mod_interface/tests/inc/manual/use_layer/layer_a.rs similarity index 100% rename from module/core/mod_interface/tests/inc/manual/layer_use/layer_a.rs rename to module/core/mod_interface/tests/inc/manual/use_layer/layer_a.rs diff --git a/module/core/mod_interface/tests/inc/manual/layer_use/layer_b.rs b/module/core/mod_interface/tests/inc/manual/use_layer/layer_b.rs similarity index 100% rename from module/core/mod_interface/tests/inc/manual/layer_use/layer_b.rs rename to module/core/mod_interface/tests/inc/manual/use_layer/layer_b.rs diff --git a/module/core/mod_interface/tests/inc/manual/layer_use/mod.rs b/module/core/mod_interface/tests/inc/manual/use_layer/mod.rs similarity index 93% rename from module/core/mod_interface/tests/inc/manual/layer_use/mod.rs rename to module/core/mod_interface/tests/inc/manual/use_layer/mod.rs index 044ff08dbf..43622260c8 100644 --- a/module/core/mod_interface/tests/inc/manual/layer_use/mod.rs +++ b/module/core/mod_interface/tests/inc/manual/use_layer/mod.rs @@ -24,6 +24,10 @@ pub mod own #[ doc( inline ) ] #[ allow( unused_imports ) ] pub use super::layer_b::orphan::*; + #[ doc( inline ) ] + pub use super::layer_a; + #[ doc( inline ) ] + pub use super::layer_b; } #[ doc( inline ) ] diff --git a/module/core/mod_interface/tests/inc/mod.rs b/module/core/mod_interface/tests/inc/mod.rs index f838c57b50..1809e2f2e8 100644 --- a/module/core/mod_interface/tests/inc/mod.rs +++ b/module/core/mod_interface/tests/inc/mod.rs @@ -9,7 +9,7 @@ mod manual mod micro_modules; mod micro_modules_two; mod layer; - mod layer_use; + mod use_layer; } @@ -37,6 +37,7 @@ mod derive // use mod use_layer; mod use_basic; + mod use_private_layers; #[ path = "./use_as/derive.rs" ] mod use_as_derive; #[ path = "./use_as/manual.rs" ] @@ -50,6 +51,6 @@ mod derive } -// mod trybuild_test; +mod trybuild_test; // xxx : enable \ No newline at end of file diff --git a/module/core/mod_interface/tests/inc/only_test/layer_simple_only_test.rs b/module/core/mod_interface/tests/inc/only_test/layer_simple_only_test.rs index 93b1190705..f62756f61a 100644 --- a/module/core/mod_interface/tests/inc/only_test/layer_simple_only_test.rs +++ b/module/core/mod_interface/tests/inc/only_test/layer_simple_only_test.rs @@ -7,6 +7,12 @@ tests_impls! fn basic() { + /* test.case( "layers themself" ); */ + { + a_id!( own::layer_a::layer_a_own(), true ); + a_id!( own::layer_b::layer_b_own(), true ); + } + /* test.case( "root" ); */ { a_id!( layer_a::layer_a_own(), true ); diff --git a/module/core/mod_interface/tests/inc/trybuild_test.rs b/module/core/mod_interface/tests/inc/trybuild_test.rs index 5acc2a4f29..f5dbbbaece 100644 --- a/module/core/mod_interface/tests/inc/trybuild_test.rs +++ b/module/core/mod_interface/tests/inc/trybuild_test.rs @@ -5,6 +5,8 @@ use super::*; // #[ cfg_attr( feature = "enabled", module_mod_interface ) ] +// xxx : qqq : enable it + // #[ cfg( module_mod_interface ) ] // #[ cfg( module_is_terminal ) ] #[ test_tools::nightly ] @@ -12,50 +14,49 @@ use super::*; fn trybuild_tests() { // qqq : fix test : if run its test with --target-dir flag it's fall (for example : cargo test --target-dir C:\foo\bar ) - // // use test_tools::dependency::trybuild; - // println!( "current_dir : {:?}", std::env::current_dir().unwrap() ); - // // let t = trybuild::TestCases::new(); - // let t = test_tools::compiletime::TestCases::new(); - // - // let current_exe_path = std::env::current_exe().expect( "No such file or directory" ); - // - // let exe_directory = dbg!(current_exe_path.parent().expect("No such file or directory")); - // fn find_workspace_root( start_path : &std::path::Path ) -> Option< &std::path::Path > - // { - // start_path - // .ancestors() - // .find( |path| path.join( "Cargo.toml" ).exists() ) - // } - // - // let workspace_root = find_workspace_root( exe_directory ).expect( "No such file or directory" ); - // let current_dir = workspace_root.join( "module/core/mod_interface" ); - // - // // micro module - // - // t.pass( current_dir.join( "tests/inc/derive/micro_modules/trybuild.rs" ) ); - // t.pass( current_dir.join( "tests/inc/derive/micro_modules_two/trybuild.rs" ) ); - // t.pass( current_dir.join( "tests/inc/derive/micro_modules_two_joined/trybuild.rs" ) ); - // - // // layer - // - // t.pass( current_dir.join( "tests/inc/derive/layer/trybuild.rs" ) ); - // t.pass( current_dir.join( "tests/inc/derive/layer_have_layer/trybuild.rs" ) ); - // t.pass( current_dir.join( "tests/inc/derive/layer_have_layer_separate_use/trybuild.rs" ) ); - // t.pass( current_dir.join( "tests/inc/derive/layer_have_layer_separate_use_two/trybuild.rs" ) ); - // t.pass( current_dir.join( "tests/inc/derive/layer_have_layer_cfg/trybuild.rs" ) ); - // t.pass( current_dir.join( "tests/inc/derive/layer_use_cfg/trybuild.rs" ) ); - // t.pass( current_dir.join( "tests/inc/derive/layer_have_mod_cfg/trybuild.rs" ) ); - // t.pass( current_dir.join( "tests/inc/derive/layer_use_macro/trybuild.rs" ) ); - // - // // use - // - // t.pass( current_dir.join( "tests/inc/derive/use_basic/trybuild.rs" ) ); - // t.pass( current_dir.join( "tests/inc/derive/use_layer/trybuild.rs" ) ); - // t.pass( current_dir.join( "tests/inc/derive/use_as/trybuild.rs" ) ); - // - // // attr - // - // t.pass( current_dir.join( "tests/inc/derive/attr_debug/trybuild.rs" ) ); + // use test_tools::dependency::trybuild; + println!( "current_dir : {:?}", std::env::current_dir().unwrap() ); + let t = test_tools::compiletime::TestCases::new(); + + let current_exe_path = std::env::current_exe().expect( "No such file or directory" ); + + let exe_directory = dbg!(current_exe_path.parent().expect("No such file or directory")); + fn find_workspace_root( start_path : &std::path::Path ) -> Option< &std::path::Path > + { + start_path + .ancestors() + .find( |path| path.join( "Cargo.toml" ).exists() ) + } + + let workspace_root = find_workspace_root( exe_directory ).expect( "No such file or directory" ); + let current_dir = workspace_root.join( "module/core/mod_interface" ); + + // micro module + + t.pass( current_dir.join( "tests/inc/derive/micro_modules/trybuild.rs" ) ); + t.pass( current_dir.join( "tests/inc/derive/micro_modules_two/trybuild.rs" ) ); + t.pass( current_dir.join( "tests/inc/derive/micro_modules_two_joined/trybuild.rs" ) ); + + // layer + + t.pass( current_dir.join( "tests/inc/derive/layer/trybuild.rs" ) ); + t.pass( current_dir.join( "tests/inc/derive/layer_have_layer/trybuild.rs" ) ); + t.pass( current_dir.join( "tests/inc/derive/layer_have_layer_separate_use/trybuild.rs" ) ); + t.pass( current_dir.join( "tests/inc/derive/layer_have_layer_separate_use_two/trybuild.rs" ) ); + t.pass( current_dir.join( "tests/inc/derive/layer_have_layer_cfg/trybuild.rs" ) ); + t.pass( current_dir.join( "tests/inc/derive/layer_use_cfg/trybuild.rs" ) ); + t.pass( current_dir.join( "tests/inc/derive/layer_have_mod_cfg/trybuild.rs" ) ); + t.pass( current_dir.join( "tests/inc/derive/layer_use_macro/trybuild.rs" ) ); + + // use + + t.pass( current_dir.join( "tests/inc/derive/use_basic/trybuild.rs" ) ); + t.pass( current_dir.join( "tests/inc/derive/use_layer/trybuild.rs" ) ); + t.pass( current_dir.join( "tests/inc/derive/use_as/trybuild.rs" ) ); + + // attr + + t.pass( current_dir.join( "tests/inc/derive/attr_debug/trybuild.rs" ) ); // } @@ -69,29 +70,28 @@ only_for_terminal_module! fn cta_trybuild_tests() { // qqq : fix test : if run its test with --target-dir flag it's fall (for example : cargo test --target-dir C:\foo\bar ) - // use test_tools::dependency::trybuild; - // println!( "current_dir : {:?}", std::env::current_dir().unwrap() ); - // // let t = trybuild::TestCases::new(); - // let t = test_tools::compiletime::TestCases::new(); - // - // let current_exe_path = std::env::current_exe().expect( "No such file or directory" ); - // - // let exe_directory = current_exe_path.parent().expect( "No such file or directory" ); - // fn find_workspace_root( start_path : &std::path::Path ) -> Option< &std::path::Path > - // { - // start_path - // .ancestors() - // .find( |path| path.join( "Cargo.toml" ).exists() ) - // } - // - // let workspace_root = find_workspace_root( exe_directory ).expect( "No such file or directory" ); - // let current_dir = workspace_root.join( "module/core/mod_interface" ); - // - // t.compile_fail( current_dir.join( "tests/inc/derive/micro_modules_bad_vis/trybuild.rs" ) ); - // t.compile_fail( current_dir.join( "tests/inc/derive/micro_modules_unknown_vis/trybuild.rs" ) ); - // t.compile_fail( current_dir.join( "tests/inc/derive/layer_bad_vis/trybuild.rs" ) ); - // t.compile_fail( current_dir.join( "tests/inc/derive/layer_unknown_vis/trybuild.rs" ) ); - // t.compile_fail( current_dir.join( "tests/inc/derive/use_bad_vis/trybuild.rs" ) ); - // t.compile_fail( current_dir.join( "tests/inc/derive/use_unknown_vis/trybuild.rs" ) ); + use test_tools::dependency::trybuild; + println!( "current_dir : {:?}", std::env::current_dir().unwrap() ); + let t = test_tools::compiletime::TestCases::new(); + + let current_exe_path = std::env::current_exe().expect( "No such file or directory" ); + + let exe_directory = current_exe_path.parent().expect( "No such file or directory" ); + fn find_workspace_root( start_path : &std::path::Path ) -> Option< &std::path::Path > + { + start_path + .ancestors() + .find( |path| path.join( "Cargo.toml" ).exists() ) + } + + let workspace_root = find_workspace_root( exe_directory ).expect( "No such file or directory" ); + let current_dir = workspace_root.join( "module/core/mod_interface" ); + + t.compile_fail( current_dir.join( "tests/inc/derive/micro_modules_bad_vis/trybuild.rs" ) ); + t.compile_fail( current_dir.join( "tests/inc/derive/micro_modules_unknown_vis/trybuild.rs" ) ); + t.compile_fail( current_dir.join( "tests/inc/derive/layer_bad_vis/trybuild.rs" ) ); + t.compile_fail( current_dir.join( "tests/inc/derive/layer_unknown_vis/trybuild.rs" ) ); + t.compile_fail( current_dir.join( "tests/inc/derive/use_bad_vis/trybuild.rs" ) ); + t.compile_fail( current_dir.join( "tests/inc/derive/use_unknown_vis/trybuild.rs" ) ); } } diff --git a/module/core/mod_interface/tests/smoke_test.rs b/module/core/mod_interface/tests/smoke_test.rs index 828e9b016b..d826b0e72a 100644 --- a/module/core/mod_interface/tests/smoke_test.rs +++ b/module/core/mod_interface/tests/smoke_test.rs @@ -1,4 +1,4 @@ - +//! Smoke tests #[ test ] fn local_smoke_test() @@ -6,7 +6,6 @@ fn local_smoke_test() ::test_tools::smoke_test_for_local_run(); } - #[ test ] fn published_smoke_test() { diff --git a/module/core/mod_interface/tests/tests.rs b/module/core/mod_interface/tests/tests.rs index 33120affda..7736531699 100644 --- a/module/core/mod_interface/tests/tests.rs +++ b/module/core/mod_interface/tests/tests.rs @@ -1,3 +1,5 @@ +//! Main tests +#![ allow( unused_imports ) ] /// A struct for testing purpose. #[ derive( Debug, PartialEq ) ] @@ -5,9 +7,7 @@ pub struct CrateStructForTesting1 { } -#[ allow( unused_imports ) ] use ::mod_interface as the_module; -#[ allow( unused_imports ) ] use test_tools::exposed::*; #[ path="../../../../module/step/meta/src/module/terminal.rs" ] mod terminal; diff --git a/module/core/mod_interface_meta/Readme.md b/module/core/mod_interface_meta/Readme.md index d9b2a9bd8b..d953c21eca 100644 --- a/module/core/mod_interface_meta/Readme.md +++ b/module/core/mod_interface_meta/Readme.md @@ -1,11 +1,11 @@ -# Module :: mod_interface_meta +# Module :: `mod_interface_meta` [![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_mod_interface_meta_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_mod_interface_meta_push.yml) [![docs.rs](https://img.shields.io/docsrs/mod_interface_meta?color=e3e8f0&logo=docs.rs)](https://docs.rs/mod_interface_meta) [![discord](https://img.shields.io/discord/872391416519737405?color=eee&logo=discord&logoColor=eee&label=ask)](https://discord.gg/m3YfbXpUUY) Protocol of modularity unifying interface of a module and introducing layers. -Not intended to be used without runtime. This module and runtime is aggregate in module::mod_interface is [here](https://github.com/Wandalen/wTools/tree/master/module/core/mod_interface). -module and runtime is aggregate in module::mod_interface is [here](https://github.com/Wandalen/wTools/tree/master/module/core/mod_interface). +Not intended to be used without runtime. This module and runtime is aggregate in `module::mod_interface` is [here](https://github.com/Wandalen/wTools/tree/master/module/core/mod_interface). +module and runtime is aggregate in `module::mod_interface` is [here](https://github.com/Wandalen/wTools/tree/master/module/core/mod_interface). diff --git a/module/core/mod_interface_meta/src/impls.rs b/module/core/mod_interface_meta/src/impls.rs index 58fec18e93..cdac53e906 100644 --- a/module/core/mod_interface_meta/src/impls.rs +++ b/module/core/mod_interface_meta/src/impls.rs @@ -1,7 +1,9 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; + #[ allow( clippy::wildcard_imports ) ] use macro_tools::exposed::*; use std::collections::HashMap; @@ -204,6 +206,16 @@ mod private pub use #adjsuted_path::orphan::*; }); + // export layer as own field of current layer + let prefixed_with_super_maybe = path.prefixed_with_super_maybe(); + c.clauses_map.get_mut( &VisOwn::Kind() ).unwrap().push( qt! + { + #[ doc( inline ) ] + #[ allow( unused_imports ) ] + #attrs1 + pub use #prefixed_with_super_maybe; + }); + c.clauses_map.get_mut( &VisExposed::Kind() ).unwrap().push( qt! { #[ doc( inline ) ] @@ -365,6 +377,16 @@ mod private pub use __all__::#path::orphan::*; }); + // export layer as own field of current layer + // let prefixed_with_super_maybe = path.prefixed_with_super_maybe(); + c.clauses_map.get_mut( &VisOwn::Kind() ).unwrap().push( qt! + { + #[ doc( inline ) ] + #[ allow( unused_imports ) ] + #attrs1 + pub use super::#path; + }); + c.clauses_map.get_mut( &VisExposed::Kind() ).unwrap().push( qt! { #[ doc( inline ) ] @@ -389,9 +411,10 @@ mod private /// /// Protocol of modularity unifying interface of a module and introducing layers. /// - #[ allow ( dead_code ) ] + #[ allow ( dead_code, clippy::too_many_lines ) ] pub fn mod_interface( input : proc_macro::TokenStream ) -> syn::Result< proc_macro2::TokenStream > { + #[ allow( clippy::enum_glob_use ) ] use ElementType::*; let original_input = input.clone(); @@ -563,7 +586,7 @@ mod private if has_debug { - let about = format!( "derive : mod_interface" ); + let about = "derive : mod_interface"; diag::report_print( about, &original_input, &result ); } @@ -581,6 +604,7 @@ mod private #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use orphan::*; } @@ -591,6 +615,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use exposed::*; } @@ -599,6 +624,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use prelude::*; pub use private:: @@ -610,6 +636,7 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use private:: { diff --git a/module/core/mod_interface_meta/src/lib.rs b/module/core/mod_interface_meta/src/lib.rs index 70dc68878e..f077e63508 100644 --- a/module/core/mod_interface_meta/src/lib.rs +++ b/module/core/mod_interface_meta/src/lib.rs @@ -93,10 +93,13 @@ mod impls; #[ allow( unused_imports ) ] use impls::exposed::*; mod record; +#[ allow( clippy::wildcard_imports ) ] use record::exposed::*; mod visibility; +#[ allow( clippy::wildcard_imports ) ] use visibility::exposed::*; mod use_tree; +#[ allow( clippy::wildcard_imports ) ] use use_tree::exposed::*; /// diff --git a/module/core/mod_interface_meta/src/record.rs b/module/core/mod_interface_meta/src/record.rs index 70e8f289ec..24b773be10 100644 --- a/module/core/mod_interface_meta/src/record.rs +++ b/module/core/mod_interface_meta/src/record.rs @@ -1,7 +1,9 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; + #[ allow( clippy::wildcard_imports ) ] use macro_tools::exposed::*; /// @@ -69,6 +71,7 @@ mod private { fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream ) { + #[ allow( clippy::enum_glob_use ) ] use ElementType::*; match self { @@ -128,7 +131,7 @@ mod private { let ident = input.parse()?; elements = syn::punctuated::Punctuated::new(); - elements.push( Pair::new( Default::default(), ident ) ); + elements.push( Pair::new( AttributesOuter::default(), ident ) ); } }, } @@ -201,8 +204,7 @@ mod private // code_print!( attr.path() ); // code_print!( attr.meta ); - let good = true - && code_to_str!( attr.path() ) == "debug" + let good = code_to_str!( attr.path() ) == "debug" // && code_to_str!( attr.meta ).is_empty() ; @@ -268,6 +270,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use orphan::*; } @@ -276,6 +279,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use exposed::*; } @@ -284,6 +288,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use prelude::*; pub use private:: @@ -299,6 +304,7 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use private:: { diff --git a/module/core/mod_interface_meta/src/use_tree.rs b/module/core/mod_interface_meta/src/use_tree.rs index de6805dd90..48e1e5bb81 100644 --- a/module/core/mod_interface_meta/src/use_tree.rs +++ b/module/core/mod_interface_meta/src/use_tree.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use macro_tools::prelude::*; @@ -24,12 +24,13 @@ mod private /// Is adding prefix to the tree path required? /// Add `super::private::` to path unless it starts from `::` or `super` or `crate`. - pub fn prefix_is_needed( &self ) -> bool + pub fn private_prefix_is_needed( &self ) -> bool { + #[ allow( clippy::wildcard_imports, clippy::enum_glob_use ) ] use syn::UseTree::*; - // println!( "prefix_is_needed : {:?}", self ); - // println!( "prefix_is_needed : self.leading_colon : {:?}", self.leading_colon ); + // println!( "private_prefix_is_needed : {:?}", self ); + // println!( "private_prefix_is_needed : self.leading_colon : {:?}", self.leading_colon ); if self.leading_colon.is_some() { @@ -46,6 +47,7 @@ mod private /// Get pure path, cutting off `as module2` from `use module1 as module2`. pub fn pure_path( &self ) -> syn::Result< syn::punctuated::Punctuated< syn::Ident, Token![::] > > { + #[ allow( clippy::wildcard_imports, clippy::enum_glob_use ) ] use syn::UseTree::*; // let leading_colon = None; @@ -92,11 +94,11 @@ mod private pub fn pure_without_super_path( &self ) -> syn::Result< syn::punctuated::Punctuated< syn::Ident, Token![::] > > { let path = self.pure_path()?; - if path.len() < 1 + if path.is_empty() { return Ok( path ); } - if path[ 0 ].to_string() == "super" + if path[ 0 ] == "super" { // let mut path2 = syn::punctuated::Punctuated::< syn::Ident, Token![::] >::new(); let path2 : syn::punctuated::Punctuated< syn::Ident, Token![::] > = path.into_iter().skip(1).collect(); @@ -105,47 +107,12 @@ mod private Ok( path ) } -// /// Adjusted path. -// /// Add `super::private::` to path unless it starts from `::` or `super` or `crate`. -// pub fn adjsuted_implicit_path( &self ) -> syn::Result< syn::punctuated::Punctuated< syn::Ident, Token![::] > > -// { -// // use syn::UseTree::*; -// let pure_path = self.pure_path()?; -// if self.prefix_is_needed() -// { -// Ok( parse_qt!{ super::private::#pure_path } ) -// } -// else -// { -// Ok( pure_path ) -// } -// } -// -// /// Adjusted path. -// /// Add `super::private::` to path unless it starts from `::` or `super` or `crate`. -// // pub fn adjsuted_explicit_path( &self ) -> syn::UseTree -// pub fn adjsuted_explicit_path( &self ) -> Self -// { -// // use syn::UseTree::*; -// if self.prefix_is_needed() -// { -// let mut clone = self.clone(); -// let tree = parse_qt!{ super::private::#self }; -// clone.tree = tree; -// clone -// } -// else -// { -// self.clone() -// } -// } - /// Prefix path with __all__ if it's appropriate. pub fn prefixed_with_all( &self ) -> Self { // use syn::UseTree::*; - if self.prefix_is_needed() + if self.private_prefix_is_needed() { let mut clone = self.clone(); let tree = parse_qt!{ __all__::#self }; @@ -159,12 +126,32 @@ mod private } + /// Prefix path with `super::` if it's appropriate to avoid "re-export of crate public `child`" problem. + pub fn prefixed_with_super_maybe( &self ) -> Self + { + + // use syn::UseTree::*; + if self.private_prefix_is_needed() + { + let mut clone = self.clone(); + let tree = parse_qt!{ super::#self }; + clone.tree = tree; + clone + } + else + { + self.clone() + } + + } + } impl syn::parse::Parse for UseTree { fn parse( input : ParseStream< '_ > ) -> syn::Result< Self > { + #[ allow( clippy::wildcard_imports, clippy::enum_glob_use ) ] use syn::UseTree::*; let leading_colon = input.parse()?; let tree = input.parse()?; @@ -232,6 +219,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use orphan::*; } @@ -240,6 +228,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use exposed::*; } @@ -248,6 +237,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use prelude::*; diff --git a/module/core/mod_interface_meta/src/visibility.rs b/module/core/mod_interface_meta/src/visibility.rs index acece0cb4f..747b2a2da5 100644 --- a/module/core/mod_interface_meta/src/visibility.rs +++ b/module/core/mod_interface_meta/src/visibility.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use macro_tools::prelude::*; @@ -13,6 +13,7 @@ mod private pub mod kw { + #[ allow( clippy::wildcard_imports ) ] use super::*; // syn::custom_keyword!( private ); syn::custom_keyword!( own ); @@ -425,7 +426,7 @@ mod private Visibility::Orphan( e ) => e.restriction(), Visibility::Exposed( e ) => e.restriction(), Visibility::Prelude( e ) => e.restriction(), - Visibility::Public( _ ) => None, + Visibility::Public( _ ) | // Visibility::Restricted( e ) => e.restriction(), Visibility::Inherited => None, } @@ -485,12 +486,12 @@ mod private } } - #[ allow( clippy::derive_hash_xor_eq ) ] + #[ allow( clippy::derived_hash_with_manual_eq ) ] impl Hash for Visibility { fn hash< H : Hasher >( &self, state : &mut H ) { - self.kind().hash( state ) + self.kind().hash( state ); } } @@ -520,6 +521,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use orphan::*; } @@ -528,6 +530,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use exposed::*; } @@ -536,6 +539,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use prelude::*; diff --git a/module/core/process_tools/Readme.md b/module/core/process_tools/Readme.md index 97f7c673ea..86fb5c3d6d 100644 --- a/module/core/process_tools/Readme.md +++ b/module/core/process_tools/Readme.md @@ -1,6 +1,6 @@ -# Module :: process_tools +# Module :: `process_tools` [![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_process_tools_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_process_tools_push.yml) [![docs.rs](https://img.shields.io/docsrs/process_tools?color=e3e8f0&logo=docs.rs)](https://docs.rs/process_tools) [![discord](https://img.shields.io/discord/872391416519737405?color=eee&logo=discord&logoColor=eee&label=ask)](https://discord.gg/m3YfbXpUUY) diff --git a/module/core/process_tools/src/environment.rs b/module/core/process_tools/src/environment.rs index 6ba4ba20fd..485b2b6092 100644 --- a/module/core/process_tools/src/environment.rs +++ b/module/core/process_tools/src/environment.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -6,7 +6,7 @@ mod private /// /// This function looks for environment variables that are commonly set by CI/CD systems to determine if it's running /// within such an environment. It supports detection for a variety of popular CI/CD platforms including GitHub Actions, - /// GitLab CI, Travis CI, CircleCI, and Jenkins. + /// GitLab CI, Travis CI, `CircleCI`, and Jenkins. /// /// # Returns /// - `true` if an environment variable indicating a CI/CD environment is found. @@ -29,10 +29,11 @@ mod private /// ``` #[ cfg( feature = "process_environment_is_cicd" ) ] + #[ must_use ] pub fn is_cicd() -> bool { use std::env; - let ci_vars = vec! + let ci_vars = [ "CI", // Common in many CI systems "GITHUB_ACTIONS", // GitHub Actions diff --git a/module/core/process_tools/src/process.rs b/module/core/process_tools/src/process.rs index 8636c628b5..d0637d805a 100644 --- a/module/core/process_tools/src/process.rs +++ b/module/core/process_tools/src/process.rs @@ -1,4 +1,5 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { // use crate::*; @@ -73,17 +74,20 @@ mod private /// Executes an external process in a specified directory without using a shell. /// /// # Arguments: - /// - `bin_path`: Path to the executable bin_path. - /// - `args`: Command-line arguments for the bin_path. - /// - `current_path`: Directory current_path to run the bin_path in. + /// - `bin_path`: Path to the executable `bin_path`. + /// - `args`: Command-line arguments for the `bin_path`. + /// - `current_path`: Directory `current_path` to run the `bin_path` in. /// /// # Returns: /// A `Result` containing `Report` on success, detailing execution output, /// or an error message on failure. /// - /// # Errors: + /// # Errors /// Returns an error if the process fails to spawn, complete, or if output /// cannot be decoded as UTF-8. + /// + /// # Panics + /// qqq: doc // // qqq : for Petro : use typed error // qqq : for Petro : write example @@ -131,7 +135,7 @@ mod private .context( "failed to spawn process" ) .map_err( | e | { - report.error = Err( e.into() ); + report.error = Err( e ); Err::< (), () >( () ) }); @@ -141,16 +145,14 @@ mod private } let child = child.unwrap(); - let output = child + child .wait_with_output() .context( "failed to wait on child" ) .map_err( | e | { - report.error = Err( e.into() ); + report.error = Err( e ); Err::< (), () >( () ) - }); - - output + }) }; if report.error.is_err() @@ -163,7 +165,7 @@ mod private .context( "Found invalid UTF-8" ) .map_err( | e | { - report.error = Err( e.into() ); + report.error = Err( e ); Err::< (), () >( () ) }); @@ -179,7 +181,7 @@ mod private .context( "Found invalid UTF-8" ) .map_err( | e | { - report.error = Err( e.into() ); + report.error = Err( e ); Err::< (), () >( () ) }); @@ -290,10 +292,10 @@ mod private { Report { - command : Default::default(), + command : String::default(), current_path : PathBuf::new(), - out : Default::default(), - err : Default::default(), + out : String::default(), + err : String::default(), error : Ok( () ), } } diff --git a/module/core/program_tools/src/program.rs b/module/core/program_tools/src/program.rs index 70d66a7ead..90737df823 100644 --- a/module/core/program_tools/src/program.rs +++ b/module/core/program_tools/src/program.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/core/pth/Readme.md b/module/core/pth/Readme.md index a6f4c2f04d..9479a502d6 100644 --- a/module/core/pth/Readme.md +++ b/module/core/pth/Readme.md @@ -11,7 +11,7 @@ All functions in the crate don't touch file system, but only process paths. ### Type `AbsolutePath` -The AbsolutePath type ensures that paths are absolute, which helps reduce issues and maintenance costs associated with relative paths. Relative paths can be problematic as they introduce additional variables and complexities, making code analysis, integration, refactoring, and testing more difficult. By using absolute paths, software architecture can be improved, similar to how avoiding global variables can enhance code quality. It is recommended to use relative paths only at the outskirts of an application. +The `AbsolutePath` type ensures that paths are absolute, which helps reduce issues and maintenance costs associated with relative paths. Relative paths can be problematic as they introduce additional variables and complexities, making code analysis, integration, refactoring, and testing more difficult. By using absolute paths, software architecture can be improved, similar to how avoiding global variables can enhance code quality. It is recommended to use relative paths only at the outskirts of an application. ### Trait `AsPath` @@ -19,11 +19,11 @@ This trait is used to avoid redundant allocation of memory by providing a refere ### Trait `TryIntoPath` -This trait is used to convert any path-like type into an owned PathBuf. Unlike `TryIntoCowPath`, it always returns an owned PathBuf, so there is no need to differentiate between borrowed and owned paths at runtime. Unlike `AsPath`, it is implemented for a wider range of path-like types, similar to `TryIntoCowPath`. +This trait is used to convert any path-like type into an owned `PathBuf`. Unlike `TryIntoCowPath`, it always returns an owned `PathBuf`, so there is no need to differentiate between borrowed and owned paths at runtime. Unlike `AsPath`, it is implemented for a wider range of path-like types, similar to `TryIntoCowPath`. ### Trait `TryIntoCowPath` -This trait is designed to avoid redundant memory allocation. Unlike TryIntoPath, it does not allocate memory on the heap if it’s not necessary. Unlike `AsPath`, it is implemented for a wider number of path-like types, similar to TryIntoPath. The drawback is the necessity to differentiate borrowed and owned paths at runtime. +This trait is designed to avoid redundant memory allocation. Unlike `TryIntoPath`, it does not allocate memory on the heap if it’s not necessary. Unlike `AsPath`, it is implemented for a wider number of path-like types, similar to `TryIntoPath`. The drawback is the necessity to differentiate borrowed and owned paths at runtime. -# Module :: strs_tools +# Module :: `strs_tools` [![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_strs_tools_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_strs_tools_push.yml) [![docs.rs](https://img.shields.io/docsrs/strs_tools?color=e3e8f0&logo=docs.rs)](https://docs.rs/strs_tools) [![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%2Fstrs_tools%2Fexamples%2Fstrs_tools_trivial.rs,RUN_POSTFIX=--example%20strs_tools_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) diff --git a/module/core/strs_tools/src/lib.rs b/module/core/strs_tools/src/lib.rs index 72ff01c34c..b3858c911f 100644 --- a/module/core/strs_tools/src/lib.rs +++ b/module/core/strs_tools/src/lib.rs @@ -18,6 +18,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use orphan::*; pub use super::string::orphan::*; @@ -28,6 +29,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use exposed::*; } diff --git a/module/core/strs_tools/src/string/indentation.rs b/module/core/strs_tools/src/string/indentation.rs index b4574f3fbc..8e71ccbcfb 100644 --- a/module/core/strs_tools/src/string/indentation.rs +++ b/module/core/strs_tools/src/string/indentation.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -57,17 +57,17 @@ mod private { if b.0 > 0 { - a.push_str( "\n" ); + a.push( '\n' ); } a.push_str( prefix ); - a.push_str( &b.1 ); + a.push_str( b.1 ); a.push_str( postfix ); a }); - if src.ends_with( "\n" ) || src.ends_with( "\n\r" ) || src.ends_with( "\r\n" ) + if src.ends_with( '\n' ) || src.ends_with( "\n\r" ) || src.ends_with( "\r\n" ) { - result.push_str( "\n" ); + result.push( '\n' ); result.push_str( prefix ); result.push_str( postfix ); } @@ -85,6 +85,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use orphan::*; pub use private:: @@ -96,6 +97,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use exposed::*; pub use private:: @@ -107,6 +109,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::own as indentation; diff --git a/module/core/strs_tools/src/string/isolate.rs b/module/core/strs_tools/src/string/isolate.rs index 50ba7fe294..34e9af9449 100644 --- a/module/core/strs_tools/src/string/isolate.rs +++ b/module/core/strs_tools/src/string/isolate.rs @@ -26,7 +26,7 @@ mod private } /// - /// Adapter for IsolateOptions. + /// Adapter for `IsolateOptions`. /// pub trait IsolateOptionsAdapter< 'a > @@ -144,6 +144,7 @@ mod private /// It produces former. To convert former into options and run algorithm of splitting call `perform()`. /// + #[ must_use ] pub fn isolate<'a>() -> IsolateOptionsFormer<'a> { IsolateOptions::former() @@ -155,6 +156,7 @@ mod private /// It produces former. To convert former into options and run algorithm of splitting call `perform()`. /// + #[ must_use ] pub fn isolate_left<'a>() -> IsolateOptionsFormer<'a> { IsolateOptions::former() @@ -167,6 +169,7 @@ mod private /// It produces former. To convert former into options and run algorithm of splitting call `perform()`. /// + #[ must_use ] pub fn isolate_right<'a>() -> IsolateOptionsFormer<'a> { IsolateOptions::former() @@ -194,6 +197,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use exposed::*; } diff --git a/module/core/strs_tools/src/string/mod.rs b/module/core/strs_tools/src/string/mod.rs index 46552b8124..d473f9eeef 100644 --- a/module/core/strs_tools/src/string/mod.rs +++ b/module/core/strs_tools/src/string/mod.rs @@ -33,7 +33,9 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; + #[ allow( clippy::wildcard_imports ) ] pub use orphan::*; #[ cfg( all( feature = "string_indentation", not( feature = "no_std" ) ) ) ] pub use super::indentation::orphan::*; @@ -52,6 +54,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use exposed::*; } diff --git a/module/core/strs_tools/src/string/number.rs b/module/core/strs_tools/src/string/number.rs index 69f8b2c0d1..fac6b4664d 100644 --- a/module/core/strs_tools/src/string/number.rs +++ b/module/core/strs_tools/src/string/number.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } @@ -11,14 +11,15 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use orphan::*; pub use private:: { }; - #[ cfg( all( feature = "string_parse_number" ) ) ] + #[ cfg( feature = "string_parse_number" ) ] #[ doc( inline ) ] - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::wildcard_imports ) ] pub use lexical::*; } @@ -26,6 +27,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use exposed::*; pub use private:: @@ -37,6 +39,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::own as number; diff --git a/module/core/strs_tools/src/string/parse_request.rs b/module/core/strs_tools/src/string/parse_request.rs index 432b2098b6..e926b4a4cf 100644 --- a/module/core/strs_tools/src/string/parse_request.rs +++ b/module/core/strs_tools/src/string/parse_request.rs @@ -1,7 +1,9 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; + #[ allow( clippy::wildcard_imports ) ] use string:: { split::*, @@ -48,6 +50,7 @@ mod private } } + #[ allow( clippy::from_over_into ) ] impl< T > Into > for OpType< T > { fn into( self ) -> Vec< T > @@ -62,8 +65,11 @@ mod private impl OpType< T > { - /// Append item of OpType to current value. If current type is `Primitive`, then it will be converted to + /// Append item of `OpType` to current value. If current type is `Primitive`, then it will be converted to /// `Vector`. + /// # Panics + /// qqq: doc + #[ must_use ] pub fn append( mut self, item : OpType< T > ) -> OpType< T > { let mut mut_item = item; @@ -156,6 +162,7 @@ mod private /// Options for parser. /// + #[ allow( clippy::struct_excessive_bools ) ] #[ derive( Debug, former::Former ) ] #[ perform( fn parse( mut self ) -> Request< 'a > ) ] pub struct ParseOptions< 'a > @@ -179,7 +186,7 @@ mod private } /// - /// Adapter for ParseOptions. + /// Adapter for `ParseOptions`. /// pub trait ParseOptionsAdapter< 'a > @@ -245,6 +252,7 @@ mod private self.subject_win_paths_maybe } + #[ allow( clippy::assigning_clones, clippy::too_many_lines, clippy::collapsible_if ) ] fn parse( mut self ) -> Request< 'a > where Self : Sized, @@ -474,6 +482,7 @@ mod private /// It produces former. To convert former into options and run algorithm of splitting call `perform()`. /// + #[ must_use ] pub fn request_parse<'a>() -> ParseOptionsFormer<'a> { ParseOptions::former() @@ -488,6 +497,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use orphan::*; pub use private:: @@ -504,6 +514,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use exposed::*; } @@ -512,6 +523,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::own as parse_request; @@ -526,6 +538,7 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use private::ParseOptionsAdapter; } diff --git a/module/core/strs_tools/src/string/split.rs b/module/core/strs_tools/src/string/split.rs index 5c9eac10cd..6744e6a020 100644 --- a/module/core/strs_tools/src/string/split.rs +++ b/module/core/strs_tools/src/string/split.rs @@ -72,7 +72,7 @@ mod private { if let Some( x ) = src.find( pat ) { - r.push( ( x, x + pat.len() ) ) + r.push( ( x, x + pat.len() ) ); } } @@ -116,7 +116,7 @@ mod private impl< 'a, D : Searcher + Clone > SplitFastIterator< 'a, D > { - #[ allow( dead_code ) ] + #[ allow( dead_code, clippy::needless_pass_by_value ) ] fn new( o : impl SplitOptionsAdapter< 'a, D > ) -> Self { Self @@ -154,12 +154,10 @@ mod private { return None; } - else - { - self.counter -= 1; - self.stop_empty = true; - return Some( Split { string : "", typ : SplitType::Delimeted } ); - } + + self.counter -= 1; + self.stop_empty = true; + return Some( Split { string : "", typ : SplitType::Delimeted } ); } if start == 0 && end != 0 @@ -170,7 +168,7 @@ mod private let mut next = &self.iterable[ ..start ]; if start == end && self.counter >= 3 { - next = &self.iterable[ ..start + 1 ]; + next = &self.iterable[ ..=start ]; start += 1; } @@ -229,6 +227,7 @@ mod private /// #[ derive( Debug ) ] + #[ allow( clippy::struct_excessive_bools ) ] pub struct SplitIterator< 'a > { iterator : SplitFastIterator< 'a, Vec< &'a str > >, @@ -247,6 +246,7 @@ mod private impl< 'a > SplitIterator< 'a > { + #[ allow( clippy::needless_pass_by_value ) ] fn new( o : impl SplitOptionsAdapter< 'a, Vec< &'a str > > ) -> Self { let iterator; @@ -338,10 +338,7 @@ mod private { return self.next(); } - else - { - return Some( split ); - } + return Some( split ); }, None => { @@ -405,6 +402,7 @@ mod private /// #[ derive( Debug ) ] + #[ allow( clippy::struct_excessive_bools ) ] pub struct SplitOptions< 'a, D > where D : Searcher + Default + Clone, @@ -422,7 +420,8 @@ mod private impl< 'a > SplitOptions< 'a, Vec< &'a str > > { - /// Produces SplitIterator. + /// Produces `SplitIterator`. + #[ must_use ] pub fn split( self ) -> SplitIterator< 'a > where Self : Sized, @@ -435,7 +434,7 @@ mod private where D : Searcher + Default + Clone { - /// Produces SplitFastIterator. + /// Produces `SplitFastIterator`. pub fn split_fast( self ) -> SplitFastIterator< 'a, D > where Self : Sized, @@ -561,9 +560,10 @@ mod private } /// - /// Former for SplitOptions. + /// Former for `SplitOptions`. /// + #[ allow( clippy::struct_excessive_bools ) ] #[ derive( Debug ) ] pub struct SplitOptionsFormer< 'a > { @@ -637,6 +637,7 @@ mod private /// .perform(); /// ``` + #[ must_use ] pub fn split< 'a >() -> SplitOptionsFormer< 'a > { SplitOptionsFormer::new( < &str >::default() ) @@ -651,6 +652,7 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use orphan::*; pub use private:: @@ -668,6 +670,7 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use exposed::*; } @@ -676,6 +679,7 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use super::own as split; @@ -690,6 +694,7 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { + #[ allow( clippy::wildcard_imports ) ] use super::*; pub use private::SplitOptionsAdapter; } diff --git a/module/core/test_tools/Cargo.toml b/module/core/test_tools/Cargo.toml index 6d30222997..4f17161640 100644 --- a/module/core/test_tools/Cargo.toml +++ b/module/core/test_tools/Cargo.toml @@ -24,13 +24,15 @@ workspace = true features = [ "full" ] all-features = false - - # = features [features] -default = [ "enabled" ] -full = [ "enabled" ] +default = [ + "enabled", + # "standalone", + "normal", +] +full = [ "default" ] no_std = [ # "error_tools/no_std", # "meta_tools/no_std", @@ -53,39 +55,80 @@ use_alloc = [ # "former_stable/use_alloc", ] enabled = [ - "error_tools/enabled", - "meta_tools/enabled", - "mem_tools/enabled", - "typing_tools/enabled", - "data_type/enabled", - "diagnostics_tools/enabled", - "process_tools/enabled", - "collection_tools/enabled", + # "error_tools/enabled", + # "meta_tools/enabled", + # "mem_tools/enabled", + # "typing_tools/enabled", + # "data_type/enabled", + # "diagnostics_tools/enabled", + # "process_tools/enabled", + # "collection_tools/enabled", ] # nightly = [ "typing_tools/nightly" ] +normal = [ + "dep:error_tools", + "dep:collection_tools", + "dep:impls_index", + "dep:mem_tools", + "dep:typing_tools", + "dep:diagnostics_tools", + "dep:process_tools", +] +standalone = [ + "standalone_error_tools", + "standalone_collection_tools", + "standalone_impls_index", + "standalone_mem_tools", + # "dep:mem_tools", + "dep:typing_tools", + "dep:diagnostics_tools", + "dep:process_tools", +] +standalone_error_tools = [ "dep:anyhow", "dep:thiserror", "error_typed", "error_untyped" ] +standalone_collection_tools = [ "dep:hashbrown", "collection_constructors", "collection_into_constructors" ] +standalone_impls_index = [ "dep:impls_index_meta" ] +standalone_mem_tools = [] + +# error_tools +error_typed = [] +error_untyped = [] +# collection_tools +collection_constructors = [] +collection_into_constructors = [] + [dependencies] ## external -paste = "~1.0" # zzz : remove laster -rustversion = "~1.0" -# anyhow = "~1.0" -num-traits = "~0.2" trybuild = { version = "1.0.85", features = [ "diff" ] } -rand = "0.8.5" +rustversion = { workspace = true } +num-traits = { workspace = true } +rand = { workspace = true } +# tempdir = { workspace = true } ## internal -error_tools = { workspace = true, features = [ "full" ] } -meta_tools = { workspace = true, features = [ "full" ] } -mem_tools = { workspace = true, features = [ "full" ] } -typing_tools = { workspace = true, features = [ "full" ] } -data_type = { workspace = true, features = [ "full" ] } -diagnostics_tools = { workspace = true, features = [ "full" ] } -process_tools = { workspace = true, features = [ "full" ] } -collection_tools = { workspace = true, features = [ "full" ] } +error_tools = { workspace = true, features = [ "full" ], optional = true } +collection_tools = { workspace = true, features = [ "full" ], optional = true } +impls_index = { workspace = true, features = [ "full" ], optional = true } +mem_tools = { workspace = true, features = [ "full" ], optional = true } + +typing_tools = { workspace = true, features = [ "full" ], optional = true } +diagnostics_tools = { workspace = true, features = [ "full" ], optional = true } +process_tools = { workspace = true, features = [ "full" ], optional = true } + # former_stable = { workspace = true, features = [ "full" ] } +## transient + +# error_tools +anyhow = { workspace = true, optional = true } +thiserror = { workspace = true, optional = true } +# collection_tools +hashbrown = { workspace = true, optional = true } +# impls_index +impls_index_meta = { workspace = true, optional = true } + [build-dependencies] rustc_version = "0.4" diff --git a/module/core/test_tools/src/lib.rs b/module/core/test_tools/src/lib.rs index f9870e775e..4d1b25124e 100644 --- a/module/core/test_tools/src/lib.rs +++ b/module/core/test_tools/src/lib.rs @@ -6,47 +6,32 @@ /// Namespace with dependencies. +#[ allow( unused_imports ) ] #[ cfg( feature = "enabled" ) ] pub mod dependency { - // zzz : exclude later - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use ::paste; + // // zzz : exclude later + // #[ doc( inline ) ] + // pub use ::paste; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use ::trybuild; #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use ::rustversion; - - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use ::error_tools; - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use ::meta_tools; - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use ::mem_tools; #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use ::typing_tools; - #[ doc( inline ) ] - #[ allow( unused_imports ) ] pub use ::num_traits; - #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use ::diagnostics_tools; #[ doc( inline ) ] - #[ allow( unused_imports ) ] - pub use ::process_tools; - - // #[ doc( inline ) ] - // #[ allow( unused_imports ) ] - // pub use ::process_tools as process_tools; + pub use super:: + { + error_tools, + collection_tools, + impls_index, + mem_tools, + typing_tools, + diagnostics_tools, + process_tools, + }; } @@ -54,56 +39,202 @@ mod private {} // -#[ cfg( feature = "enabled" ) ] +// #[ cfg( feature = "enabled" ) ] +// // #[ cfg( not( feature = "no_std" ) ) ] +// ::meta_tools::mod_interface! +// { +// // #![ debug ] +// +// own use super::dependency::*; +// +// layer test; +// +// // xxx : comment out +// use super::exposed::meta; +// use super::exposed::mem; +// use super::exposed::typing; +// use super::exposed::dt; +// use super::exposed::diagnostics; +// use super::exposed::collection; +// // use super::exposed::process; +// +// // prelude use ::rustversion::{ nightly, stable }; +// +// // // xxx : eliminate need to do such things, putting itself to proper category +// // exposed use super::test::compiletime; +// // exposed use super::test::helper; +// // exposed use super::test::smoke_test; +// +// prelude use ::meta_tools as meta; +// prelude use ::mem_tools as mem; +// prelude use ::typing_tools as typing; +// prelude use ::data_type as dt; +// prelude use ::diagnostics_tools as diagnostics; +// prelude use ::collection_tools as collection; +// // prelude use ::process_tools as process; +// +// use ::collection_tools; // xxx : do that for all dependencies +// +// prelude use ::meta_tools:: +// { +// impls, +// index, +// tests_impls, +// tests_impls_optional, +// tests_index, +// }; +// +// prelude use ::typing_tools::{ implements }; +// +// } + +// xxx : use module namespaces +// #[ cfg( feature = "enabled" ) ] // #[ cfg( not( feature = "no_std" ) ) ] -::meta_tools::mod_interface! +// pub use test::{ compiletime, helper, smoke_test }; + +#[ cfg( feature = "enabled" ) ] +pub mod test; + +/// Error tools. +#[ cfg( feature = "enabled" ) ] +#[ cfg( feature = "standalone" ) ] +mod standalone { - // #![ debug ] - own use super::dependency::*; + /// Error tools. + #[ path = "../../../../core/error_tools/src/error/mod.rs" ] + pub mod error; + pub use error as error_tools; - layer test; + /// Collection tools. + #[ path = "../../../../core/collection_tools/src/collection/mod.rs" ] + pub mod collection; + pub use collection as collection_tools; - // xxx : comment out - use super::exposed::meta; - use super::exposed::mem; - use super::exposed::typing; - use super::exposed::dt; - use super::exposed::diagnostics; - use super::exposed::collection; - // use super::exposed::process; + /// impl and index macros. + #[ path = "../../../../core/impls_index/src/impls_index/mod.rs" ] + pub mod impls_index; + + /// Memory tools. + #[ path = "../../../../core/mem_tools/src/mem.rs" ] + pub mod mem_tools; + +} + +#[ cfg( feature = "enabled" ) ] +#[ cfg( feature = "standalone" ) ] +pub use standalone::*; + +#[ cfg( feature = "enabled" ) ] +#[ cfg( not( feature = "standalone" ) ) ] +pub use :: +{ + error_tools, + collection_tools, + impls_index, + mem_tools, +}; + +#[ cfg( feature = "enabled" ) ] +pub use :: +{ + typing_tools, + diagnostics_tools, + process_tools, +}; - // prelude use ::rustversion::{ nightly, stable }; +#[ cfg( feature = "enabled" ) ] +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +pub use own::*; - // // xxx : eliminate need to do such things, putting itself to proper category - // exposed use super::test::compiletime; - // exposed use super::test::helper; - // exposed use super::test::smoke_test; +/// Own namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod own +{ + use super::*; - prelude use ::meta_tools as meta; - prelude use ::mem_tools as mem; - prelude use ::typing_tools as typing; - prelude use ::data_type as dt; - prelude use ::diagnostics_tools as diagnostics; - prelude use ::collection_tools as collection; - // prelude use ::process_tools as process; + #[ doc( inline ) ] + pub use orphan::*; - use ::collection_tools; // xxx : do that for all dependencies + #[ doc( inline ) ] + pub use test::own::*; - prelude use ::meta_tools:: + #[ doc( inline ) ] + pub use { - impls, - index, - tests_impls, - tests_impls_optional, - tests_index, + error_tools::orphan::*, + collection_tools::orphan::*, + impls_index::orphan::*, + mem_tools::orphan::*, + typing_tools::orphan::*, + diagnostics_tools::orphan::*, }; - prelude use ::typing_tools::{ implements }; +} + +/// Shared with parent namespace of the module +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod orphan +{ + use super::*; + + #[ doc( inline ) ] + pub use exposed::*; + + #[ doc( inline ) ] + pub use test::orphan::*; } -// xxx : use module namespaces -// #[ cfg( feature = "enabled" ) ] -// #[ cfg( not( feature = "no_std" ) ) ] -// pub use test::{ compiletime, helper, smoke_test }; +/// Exposed namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod exposed +{ + use super::*; + + #[ doc( inline ) ] + pub use prelude::*; + + #[ doc( inline ) ] + pub use test::exposed::*; + + #[ doc( inline ) ] + pub use + { + error_tools::exposed::*, + collection_tools::exposed::*, + impls_index::exposed::*, + mem_tools::exposed::*, + typing_tools::exposed::*, + diagnostics_tools::exposed::*, + }; + +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; + + #[ doc( inline ) ] + pub use test::prelude::*; + + #[ doc( inline ) ] + pub use + { + error_tools::prelude::*, + collection_tools::prelude::*, + impls_index::prelude::*, + mem_tools::prelude::*, + typing_tools::prelude::*, + diagnostics_tools::prelude::*, + }; + +} diff --git a/module/core/test_tools/src/test/asset.rs b/module/core/test_tools/src/test/asset.rs index 410707ed36..c32cf9cb91 100644 --- a/module/core/test_tools/src/test/asset.rs +++ b/module/core/test_tools/src/test/asset.rs @@ -3,7 +3,7 @@ //! Test asset helper. //! -/// Internal namespace. +/// Define a private namespace for all its items. // #[ cfg( not( feature = "no_std" ) ) ] mod private { @@ -34,14 +34,73 @@ mod private } +// // +// // #[ cfg( not( feature = "no_std" ) ) ] +// crate::mod_interface! +// { // -// #[ cfg( not( feature = "no_std" ) ) ] -crate::mod_interface! +// // exposed use super; +// exposed use super::super::asset; +// +// // own use path_to_exe; +// +// } + +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +pub use own::*; + +/// Own namespace of the module. +#[ allow( unused_imports ) ] +pub mod own { + use super::*; + + #[ doc( inline ) ] + pub use + { + }; + +} + +/// Shared with parent namespace of the module +#[ allow( unused_imports ) ] +pub mod orphan +{ + use super::*; + + #[ doc( inline ) ] + pub use exposed::*; - // exposed use super; - exposed use super::super::asset; + pub use super::super::asset; + +} + +/// Exposed namespace of the module. +#[ allow( unused_imports ) ] +pub mod exposed +{ + use super::*; + + #[ doc( inline ) ] + pub use prelude::*; + + #[ doc( inline ) ] + pub use + { + }; + +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; - // own use path_to_exe; + #[ doc( inline ) ] + pub use + { + }; } diff --git a/module/core/test_tools/src/test/compiletime.rs b/module/core/test_tools/src/test/compiletime.rs index 4f29ec998e..9792d17e3d 100644 --- a/module/core/test_tools/src/test/compiletime.rs +++ b/module/core/test_tools/src/test/compiletime.rs @@ -3,7 +3,7 @@ //! Try building a program for negative testing. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { #[ doc( inline ) ] @@ -73,14 +73,74 @@ mod private // } // } -crate::mod_interface! +// crate::mod_interface! +// { +// // #![ debug ] +// // xxx : make it working +// // exposed use super; +// exposed use super::super::compiletime; +// own use +// { +// * +// }; +// } + +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +pub use own::*; + +/// Own namespace of the module. +#[ allow( unused_imports ) ] +pub mod own { - // #![ debug ] - // xxx : make it working - // exposed use super; - exposed use super::super::compiletime; - own use + use super::*; + + #[ doc( inline ) ] + pub use { - * + private::*, }; + +} + +/// Shared with parent namespace of the module +#[ allow( unused_imports ) ] +pub mod orphan +{ + use super::*; + + #[ doc( inline ) ] + pub use exposed::*; + + pub use super::super::compiletime; + +} + +/// Exposed namespace of the module. +#[ allow( unused_imports ) ] +pub mod exposed +{ + use super::*; + + #[ doc( inline ) ] + pub use prelude::*; + + #[ doc( inline ) ] + pub use + { + }; + +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; + + #[ doc( inline ) ] + pub use + { + }; + } diff --git a/module/core/test_tools/src/test/helper.rs b/module/core/test_tools/src/test/helper.rs index 49675e2ada..16100d426a 100644 --- a/module/core/test_tools/src/test/helper.rs +++ b/module/core/test_tools/src/test/helper.rs @@ -5,7 +5,7 @@ // use super::*; -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -75,16 +75,78 @@ mod private pub use doc_file_test; } -crate::mod_interface! +// crate::mod_interface! +// { +// // xxx +// // #![ debug ] +// // exposed use super; +// exposed use super::super::helper; +// +// prelude use +// { +// num, +// doc_file_test, +// }; +// } + +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +pub use own::*; + +/// Own namespace of the module. +#[ allow( unused_imports ) ] +pub mod own { - // xxx - // #![ debug ] - // exposed use super; - exposed use super::super::helper; + use super::*; - prelude use + #[ doc( inline ) ] + pub use { - num, - doc_file_test, + private::*, }; + +} + +/// Shared with parent namespace of the module +#[ allow( unused_imports ) ] +pub mod orphan +{ + use super::*; + + #[ doc( inline ) ] + pub use exposed::*; + + pub use super::super::helper; + +} + +/// Exposed namespace of the module. +#[ allow( unused_imports ) ] +pub mod exposed +{ + use super::*; + + #[ doc( inline ) ] + pub use prelude::*; + + #[ doc( inline ) ] + pub use + { + private::num, + private::doc_file_test, + }; + +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; + + #[ doc( inline ) ] + pub use + { + }; + } diff --git a/module/core/test_tools/src/test/mod.rs b/module/core/test_tools/src/test/mod.rs index 158406fbd1..c13f70ef67 100644 --- a/module/core/test_tools/src/test/mod.rs +++ b/module/core/test_tools/src/test/mod.rs @@ -5,12 +5,108 @@ mod private {} -// #[ cfg( not( feature = "no_std" ) ) ] -crate::mod_interface! +// // #[ cfg( not( feature = "no_std" ) ) ] +// crate::mod_interface! +// { +// layer asset; +// layer compiletime; +// layer helper; +// layer smoke_test; +// layer version; +// } + +pub mod asset; +pub mod compiletime; +pub mod helper; +pub mod smoke_test; +pub mod version; + +#[ cfg( feature = "enabled" ) ] +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +pub use own::*; + +/// Own namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod own +{ + use super::*; + + #[ doc( inline ) ] + pub use orphan::*; + + #[ doc( inline ) ] + pub use + { + asset::orphan::*, + compiletime::orphan::*, + helper::orphan::*, + smoke_test::orphan::*, + version::orphan::*, + }; + +} + +/// Shared with parent namespace of the module +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod orphan { - layer asset; - layer compiletime; - layer helper; - layer smoke_test; - layer version; + use super::*; + + #[ doc( inline ) ] + pub use exposed::*; + +} + +/// Exposed namespace of the module. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod exposed +{ + use super::*; + + #[ doc( inline ) ] + pub use prelude::*; + + #[ doc( inline ) ] + pub use + { + asset::exposed::*, + compiletime::exposed::*, + helper::exposed::*, + smoke_test::exposed::*, + version::exposed::*, + }; + + #[ doc( inline ) ] + pub use crate::impls_index:: + { + impls, + index, + tests_impls, + tests_impls_optional, + tests_index, + }; + +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ cfg( feature = "enabled" ) ] +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; + + #[ doc( inline ) ] + pub use + { + asset::prelude::*, + compiletime::prelude::*, + helper::prelude::*, + smoke_test::prelude::*, + version::prelude::*, + }; + } diff --git a/module/core/test_tools/src/test/smoke_test.rs b/module/core/test_tools/src/test/smoke_test.rs index 34ebd2f55f..a99b4ee1a0 100644 --- a/module/core/test_tools/src/test/smoke_test.rs +++ b/module/core/test_tools/src/test/smoke_test.rs @@ -8,11 +8,12 @@ // xxx2 : use process_tools to build and run rust programs, introduce program_ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( unused_imports ) ] use crate::*; - use dependency::process_tools::environment; + use process_tools::environment; // zzz : comment out // pub mod environment // { @@ -316,17 +317,83 @@ mod private } +// // +// crate::mod_interface! +// { // -crate::mod_interface! +// // exposed use super; +// exposed use super::super::smoke_test; +// +// exposed use SmokeModuleTest; +// exposed use smoke_test_run; +// exposed use smoke_tests_run; +// exposed use smoke_test_for_local_run; +// exposed use smoke_test_for_published_run; +// +// } + + +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +pub use own::*; + +/// Own namespace of the module. +#[ allow( unused_imports ) ] +pub mod own +{ + use super::*; + + #[ doc( inline ) ] + pub use + { + private::*, + }; + +} + +/// Shared with parent namespace of the module +#[ allow( unused_imports ) ] +pub mod orphan +{ + use super::*; + + #[ doc( inline ) ] + pub use exposed::*; + + pub use super::super::smoke_test; + +} + +/// Exposed namespace of the module. +#[ allow( unused_imports ) ] +pub mod exposed { + use super::*; + + #[ doc( inline ) ] + pub use prelude::*; - // exposed use super; - exposed use super::super::smoke_test; + #[ doc( inline ) ] + pub use private:: + { + SmokeModuleTest, + smoke_test_run, + smoke_tests_run, + smoke_test_for_local_run, + smoke_test_for_published_run, + }; + +} - exposed use SmokeModuleTest; - exposed use smoke_test_run; - exposed use smoke_tests_run; - exposed use smoke_test_for_local_run; - exposed use smoke_test_for_published_run; +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; + + #[ doc( inline ) ] + pub use + { + }; } diff --git a/module/core/test_tools/src/test/version.rs b/module/core/test_tools/src/test/version.rs index 7737b5b456..f20821e54e 100644 --- a/module/core/test_tools/src/test/version.rs +++ b/module/core/test_tools/src/test/version.rs @@ -3,21 +3,80 @@ //! Version of Rust compiler //! -/// Internal namespace. +/// Define a private namespace for all its items. // #[ cfg( not( feature = "no_std" ) ) ] mod private { } +// // +// // #[ cfg( not( feature = "no_std" ) ) ] +// crate::mod_interface! +// { // -// #[ cfg( not( feature = "no_std" ) ) ] -crate::mod_interface! +// // exposed use super; +// exposed use super::super::version; +// +// prelude use ::rustversion::{ nightly, stable }; +// +// } + + +#[ doc( inline ) ] +#[ allow( unused_imports ) ] +pub use own::*; + +/// Own namespace of the module. +#[ allow( unused_imports ) ] +pub mod own +{ + use super::*; + + #[ doc( inline ) ] + pub use + { + private::*, + }; + +} + +/// Shared with parent namespace of the module +#[ allow( unused_imports ) ] +pub mod orphan { + use super::*; - // exposed use super; - exposed use super::super::version; + #[ doc( inline ) ] + pub use exposed::*; + + pub use super::super::version; + +} + +/// Exposed namespace of the module. +#[ allow( unused_imports ) ] +pub mod exposed +{ + use super::*; + + #[ doc( inline ) ] + pub use prelude::*; + + #[ doc( inline ) ] + pub use rustversion::{ nightly, stable }; + +} + +/// Prelude to use essentials: `use my_module::prelude::*`. +#[ allow( unused_imports ) ] +pub mod prelude +{ + use super::*; - prelude use ::rustversion::{ nightly, stable }; + #[ doc( inline ) ] + pub use + { + }; } diff --git a/module/core/test_tools/tests/inc/basic_test.rs b/module/core/test_tools/tests/inc/impls_index_test.rs similarity index 99% rename from module/core/test_tools/tests/inc/basic_test.rs rename to module/core/test_tools/tests/inc/impls_index_test.rs index 8e631611f4..9b1133fb91 100644 --- a/module/core/test_tools/tests/inc/basic_test.rs +++ b/module/core/test_tools/tests/inc/impls_index_test.rs @@ -15,7 +15,6 @@ use super::*; use ::test_tools as the_module; - #[ cfg( feature = "enabled" ) ] #[ cfg( not( feature = "no_std" ) ) ] the_module::tests_impls! diff --git a/module/core/test_tools/tests/inc/mem_test.rs b/module/core/test_tools/tests/inc/mem_test.rs new file mode 100644 index 0000000000..1cf4a2b724 --- /dev/null +++ b/module/core/test_tools/tests/inc/mem_test.rs @@ -0,0 +1,26 @@ +use super::*; + +// + +#[ allow( dead_code ) ] +#[ test ] +fn same_data() +{ + let buf = [ 0u8; 128 ]; + assert!( the_module::mem::same_data( &buf, &buf ) ); + + let x = [ 0u8; 1 ]; + let y = 0u8; + + assert!( the_module::mem::same_data( &x, &y ) ); + + assert!( !the_module::mem::same_data( &buf, &x ) ); + assert!( !the_module::mem::same_data( &buf, &y ) ); + + struct H1( &'static str ); + struct H2( &'static str ); + + assert!( the_module::mem::same_data( &H1( "hello" ), &H2( "hello" ) ) ); + assert!( !the_module::mem::same_data( &H1( "qwerty" ), &H2( "hello" ) ) ); + +} diff --git a/module/core/test_tools/tests/inc/mod.rs b/module/core/test_tools/tests/inc/mod.rs index bf3d2e3d78..a6d6581d75 100644 --- a/module/core/test_tools/tests/inc/mod.rs +++ b/module/core/test_tools/tests/inc/mod.rs @@ -1,8 +1,26 @@ -#[ allow( unused_imports ) ] use super::*; -mod basic_test; +mod impls_index_test; +mod mem_test; mod try_build_test; // mod wtest_utility; // qqq : include tests of all internal dependencies + +// /// Error tools. +// #[ path = "../../../../core/error_tools/tests/inc/mod.rs" ] +// pub mod error; +// pub use error as error_tools; +// +// /// Collection tools. +// #[ path = "../../../../core/collection_tools/tests/inc/mod.rs" ] +// pub mod collection; +// pub use collection as collection_tools; + +// /// impl and index macros. +// #[ path = "../../../../core/impls_index/tests/inc/mod.rs" ] +// pub mod impls_index; + +// /// Memory tools. +// #[ path = "../../../../core/mem_tools/tests/inc/mod.rs" ] +// pub mod mem_tools; diff --git a/module/core/test_tools/tests/tests.rs b/module/core/test_tools/tests/tests.rs index 3cdbd75627..c9b1261fb2 100644 --- a/module/core/test_tools/tests/tests.rs +++ b/module/core/test_tools/tests/tests.rs @@ -1,12 +1,13 @@ +#![ allow( unused_imports ) ] + // #![ deny( rust_2018_idioms ) ] // #![ deny( missing_debug_implementations ) ] // #![ deny( missing_docs ) ] -#[ allow( unused_imports ) ] use test_tools as the_module; -#[ allow( unused_imports ) ] -#[ cfg( feature = "enabled" ) ] -#[ cfg( not( feature = "no_std" ) ) ] -use test_tools::exposed::*; + +// #[ cfg( feature = "enabled" ) ] +// #[ cfg( not( feature = "no_std" ) ) ] +// use test_tools::exposed::*; mod inc; diff --git a/module/core/variadic_from/src/variadic.rs b/module/core/variadic_from/src/variadic.rs index 715a135960..1297cb443c 100644 --- a/module/core/variadic_from/src/variadic.rs +++ b/module/core/variadic_from/src/variadic.rs @@ -2,7 +2,7 @@ //! Variadic constructor. Constructor with n arguments. Like Default, but with arguments. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/core/wtools/Cargo.toml b/module/core/wtools/Cargo.toml index 4d2e2f1f29..c8d108f307 100644 --- a/module/core/wtools/Cargo.toml +++ b/module/core/wtools/Cargo.toml @@ -58,7 +58,7 @@ meta_default = [ "meta_mod_interface", # "meta_former", # "meta_options", - "meta_constructors", + # "meta_constructors", "meta_idents_concat", ] meta_full = [ @@ -68,7 +68,7 @@ meta_full = [ "meta_mod_interface", # "meta_former", # "meta_options", - "meta_constructors", + # "meta_constructors", "meta_idents_concat", ] # meta_use_std = [ "meta", "meta_tools/use_std" ] @@ -79,7 +79,7 @@ meta_for_each = [ "meta", "meta_tools/meta_for_each" ] meta_impls_index = [ "meta", "meta_tools/meta_impls_index" ] meta_mod_interface = [ "meta" ] # meta_mod_interface = [ "meta", "meta_tools/mod_interface" ] -meta_constructors = [ "meta", "meta_tools/meta_constructors" ] +# meta_constructors = [ "meta", "meta_tools/meta_constructors" ] meta_idents_concat = [ "meta", "meta_tools/meta_idents_concat" ] # meta_former = [ "meta", "meta_tools/former" ] # meta_options = [ "meta", "meta_tools/options" ] diff --git a/module/move/assistant/.key/readme.md b/module/move/assistant/.key/readme.md new file mode 100644 index 0000000000..4209c24678 --- /dev/null +++ b/module/move/assistant/.key/readme.md @@ -0,0 +1,20 @@ +# Keys + +This document provides a concise example of an environment configuration script, used to set up environment variables for a project. These variables configure application behavior without altering the code. + +## Example of `.key/-env.sh` + +```bash +# OpenAI API key. +OPENAI_API_KEY=sk-proj-ABCDEFG +``` + +## How to Use in Shell + +To apply these variables to your current shell session, use: + +```bash +. ./key/-env.sh +``` + +This command sources the script, making the variables available in your current session. Ensure `-env.sh` is in the `key` directory relative to your current location. \ No newline at end of file diff --git a/module/move/assistant/Cargo.toml b/module/move/assistant/Cargo.toml index 144cfb6557..50700f8c3c 100644 --- a/module/move/assistant/Cargo.toml +++ b/module/move/assistant/Cargo.toml @@ -15,6 +15,7 @@ Assist AI in writing code. """ categories = [ "algorithms", "development-tools" ] keywords = [ "fundamental", "general-purpose" ] +default-run = "main" [lints] workspace = true @@ -32,15 +33,31 @@ enabled = [ "reflect_tools/enabled", ] +[[bin]] +name = "main" +path = "src/bin/main.rs" + +[[bin]] +name = "list_resources" +path = "src/bin/list_resources.rs" + [dependencies] # xxx : qqq : optimze features mod_interface = { workspace = true, features = [ "full" ] } former = { workspace = true, features = [ "full" ] } format_tools = { workspace = true, features = [ "full" ] } reflect_tools = { workspace = true, features = [ "full" ] } -openai-api-rs = { version = "=5.0.11" } +openai-api-rs = { version = "=5.0.14" } tokio = { version = "1", features = ["full"] } dotenv = "0.15" +clap = { version = "4.5.20", features = ["derive"] } +pth = "0.21.0" +serde = { version = "1.0.213", features = ["derive"] } +serde_with = "3.11.0" +error_tools = "0.17.0" +derive_tools = { version = "0.32.0", features = ["full"] } +regex = { version = "1.10.3" } +serde_yaml = "0.9" [dev-dependencies] test_tools = { workspace = true } diff --git a/module/move/assistant/design/agents_design.md b/module/move/assistant/design/agents_design.md new file mode 100644 index 0000000000..a4f9901294 --- /dev/null +++ b/module/move/assistant/design/agents_design.md @@ -0,0 +1,37 @@ +# Agents + +## YAML description structure + +Please refer to `examples/` directory. + +## Paths + +- Used in node types, templates. +- Parts are delimited with `::`. +- Absolute path has a leading `::`. +- All paths (expect absolute) **are subject to absolutization**. Absolutization also depends on the context: in `next` fields paths are absolutized to `::nodes` dir, in templates - to `::output` and so on. + +## Execution + +- YAML file contains section about `nodes:`. +- Next node is encoded in `next:` field. +- Output of the nodes are stored in `::output` dir. + +## Builtin scenarios + +- `::scenario::entry` +- `::scenario::termination` + +## Node types + +- Input nodes: + - `trigger::stdin` + - `trigger::file` +- Processing nodes: + - `script` + - `agent::completion` +- Output nodes: + - `event::stdout` + - `event::file` + +Refer to examples in `examples/` to see fields of nodes. \ No newline at end of file diff --git a/module/move/assistant/design/agents_examples/sql.yaml b/module/move/assistant/design/agents_examples/sql.yaml new file mode 100644 index 0000000000..5149f07a29 --- /dev/null +++ b/module/move/assistant/design/agents_examples/sql.yaml @@ -0,0 +1,23 @@ +nodes: + - id: input + type: trigger::stdin + prompt: 'Your query: ' + next: node::translator + + - id: sql_generator_stage1 + type: agent::completion + system_message: 'Your task is to think about how to translate the user query in natural langauge in SQL langauge. Think step by steps.' + user_message: '{{input}}' + next: node::sql_generator_stage2 + + - id: sql_generator_stage2 + type: agent::completion + system_message: 'Your task to make an SQL code based on user query in natural language and the results of thinking on that query'. + user_message: '{{sql_generator_stage1}}' + agent_reuse: node::sql_generator_stage2 + next: node::output + + - id: output + type: event::stdout + output: '{{sql_generator_stage2}}' + next: scenario::termination \ No newline at end of file diff --git a/module/move/assistant/design/commands.md b/module/move/assistant/design/commands.md new file mode 100644 index 0000000000..d1c0410dba --- /dev/null +++ b/module/move/assistant/design/commands.md @@ -0,0 +1,73 @@ +# Commands + +## Legend + +- `<...>` - argument. +- `<..?>` - optional argument. +- `<...=...>` - argument with default value. +- `(...)+` - one or more times. + +## OpenAI + +### Files + +```shell +assistant openai files upload +assistant openai files list +assistant openai files retrieve +assistant openai files delete +assistant openai files retrieve-content +``` + +### Assistants + +```shell +assistant openai assistants create +assistant openai assistants list +assistant openai assistants retrieve +assistant openai assistants modify +assistant openai assistants delete +``` + +### Threads + +```shell +assistant openai threads create +assistant openai threads retrieve +assistant openai threads delete +``` + +### Messages + +```shell +assistant openai messages create +assistant openai messages list +assistant openai messages retrieve +assistant openai messages modify +assistant openai messages delete +``` + +### Chat + +```shell +assistant openai chat create-completion ( )+ +``` + +### Runs + +```shell +assistant openai runs create +assistant openai runs create-with-thread +assistant openai runs list +assistant openai runs retrieve +assistant openai runs cancel +``` + +## Anthropic + +### Messages + +```shell +assistant anthropic messages create ( )+ +``` + diff --git a/module/move/assistant/design/entities.mmd b/module/move/assistant/design/entities.mmd new file mode 100644 index 0000000000..53e9e6baa5 --- /dev/null +++ b/module/move/assistant/design/entities.mmd @@ -0,0 +1,78 @@ +--- +title: OpenAI API +--- +erDiagram + File { + string id PK + string object + integer bytes + integer created_at + string file_name + string purpose + } + + Assistant { + string id PK + string object + string model + integer created_at + string name + string description + string instructions + tool[] tools + metadata metadata + headers headers + } + + Thread { + string id PK + string object + integer created_at + object tool_resources + metadata metadata + } + + Message { + string id PK + string object + integer created_at + string thread_id FK + string status + object incomplete_details + integer completed_at + integer incomplete_at + string role + array content + string assistant_id FK + string run_id FK + array attachments + metadata metadata + } + + Run { + string id PK + string object + integer created_at + string thread_id FK + string assistant_id FK + string status + object required_action + object last_error + integer expires_at + integer started_at + integer cancelled_at + integer failed_at + integer completed_at + object incomplete_details + string model + string instructions + tool[] tools + metadata metadata + headers headers + } + + Assistant |o--o{ Run : "" + + Thread ||--o{ Message : "" + Thread ||--o{ Run: "" + diff --git a/module/move/assistant/design/entities.png b/module/move/assistant/design/entities.png new file mode 100644 index 0000000000..69906c0fea Binary files /dev/null and b/module/move/assistant/design/entities.png differ diff --git a/module/move/assistant/design/scenarios.md b/module/move/assistant/design/scenarios.md new file mode 100644 index 0000000000..a32543fbc9 --- /dev/null +++ b/module/move/assistant/design/scenarios.md @@ -0,0 +1,32 @@ +# Scenarios + +## OpenAI + +### Assistants + +#### Make new assistant + +```shell +assistant openai assistants create gpt-4o-mini CoolBot 'CoolBot is a helpful assistant.' 'You are a helpful assistant.' +``` + +This command will return assistant ID. + +#### Chat with the assistant + +To chat with OpenAI assistant, one should do this: + +1. Create a thread. Thread is like a chat. +2. Write a message in thread (e.g. a question). +3. Run the assistant in the thread. + +```shell +assistant openai threads create +``` + +This command will return the new thread ID (referred as `thread_id`). To call an assistant, you need to know its ID. + +```shell +assistant openai messages create user '2 + 2 = ?' +assistant openai runs create +``` diff --git a/module/move/assistant/src/actions.rs b/module/move/assistant/src/actions.rs new file mode 100644 index 0000000000..826bf1603e --- /dev/null +++ b/module/move/assistant/src/actions.rs @@ -0,0 +1,13 @@ +//! +//! CLI actions of the tool. +//! + +mod private {} + +crate::mod_interface! +{ + layer openai; + layer openai_assistants_list; + layer openai_files_list; + layer openai_runs_list; +} diff --git a/module/move/assistant/src/actions/openai.rs b/module/move/assistant/src/actions/openai.rs new file mode 100644 index 0000000000..da8be32030 --- /dev/null +++ b/module/move/assistant/src/actions/openai.rs @@ -0,0 +1,66 @@ +//! +//! OpenAI API actions. +//! +//! This module also contains the definition of OpenAI Error. +//! + +mod private +{ + + use error_tools::typed::Error; + use derive_tools::{ AsRefStr }; + + use crate::*; + use ser::DisplayFromStr; + + use commands::TableConfig; + + /// Collective enum for errors in OpenAI actions. + #[ ser::serde_as ] + #[ derive( Debug, Error, AsRefStr, ser::Serialize ) ] + #[ serde( tag = "type", content = "data" ) ] + pub enum Error + { + /// API error from the underlying implementation crate. + #[ error( "OpenAI API returned error:\n{0}" ) ] + ApiError + ( + #[ from ] + #[ serde_as( as = "DisplayFromStr" ) ] + openai_api_rs::v1::error::APIError + ), + + /// User chosen a mix of table styles instead of a single one. + /// E.g.: both `--as-table` and `--as-records` were set, however only one style must be chosen + #[ error( "Select only one table style: either `--as-table`, `--as-records`, or `--columns`" ) ] + WrongTableStyle, + } + + /// Shorthand for `Result` in OpenAI actions. + pub type Result< T > = core::result::Result< T, Error >; + + /// Check the CLI arguments for table style. + /// There are 3 arguments: `--as-table`, `--as-records`, `--columns`. Only one argument + /// should be active a time. + pub fn check_table_style( table_config: &TableConfig ) -> Result< () > + { + if table_config.as_table && ( table_config.as_records || table_config.columns ) + || table_config.as_records && ( table_config.as_table || table_config.columns ) + || table_config.columns && ( table_config.as_records || table_config.as_table ) + { + return Err( Error::WrongTableStyle ) + } + + Ok( () ) + } +} + +crate::mod_interface! +{ + own use + { + Error, + Result, + check_table_style, + }; +} \ No newline at end of file diff --git a/module/move/assistant/src/actions/openai_assistants_list.rs b/module/move/assistant/src/actions/openai_assistants_list.rs new file mode 100644 index 0000000000..2326ac2a6a --- /dev/null +++ b/module/move/assistant/src/actions/openai_assistants_list.rs @@ -0,0 +1,63 @@ +//! +//! List assistants in OpenAI API (action part). +//! + +mod private +{ + + use std::fmt; + + use format_tools::AsTable; + + use crate::*; + use client::Client; + + use debug::AssistantObjectWrap; + + use actions::openai::{ Result, check_table_style }; + + use commands::TableConfig; + use util::display_table::display_tabular_data; + + /// Report for `openai assistants list`. + #[ derive( Debug ) ] + pub struct ListReport + { + /// Configure table formatting. + pub table_config : TableConfig, + + /// OpenAI assistants. + pub assistants: Vec< AssistantObjectWrap > + } + + impl fmt::Display for ListReport + { + fn fmt + ( + &self, + f : &mut fmt::Formatter< '_ > + ) -> fmt::Result + { + display_tabular_data( &AsTable::new( &self.assistants ), f, &self.table_config ) + } + } + + /// List OpenAI assistants action. + pub async fn action + ( + client : &Client, + table_config : TableConfig, + ) -> Result < ListReport > + { + check_table_style( &table_config )?; + + let response = client.list_assistant( None, None, None, None ).await?; + let assistants = response.data.into_iter().map( AssistantObjectWrap ).collect(); + Ok( ListReport { table_config, assistants } ) + } +} + +crate::mod_interface! +{ + own use action; +} \ No newline at end of file diff --git a/module/move/assistant/src/actions/openai_files_list.rs b/module/move/assistant/src/actions/openai_files_list.rs new file mode 100644 index 0000000000..12f6ab7bd0 --- /dev/null +++ b/module/move/assistant/src/actions/openai_files_list.rs @@ -0,0 +1,64 @@ +//! +//! List files in OpenAI API (action part). +//! + +mod private +{ + + use std::fmt; + + use format_tools::AsTable; + + use crate::*; + use client::Client; + + use debug::FileDataWrap; + + use actions::openai::{ Result, check_table_style }; + + use commands::TableConfig; + use util::display_table::display_tabular_data; + + /// Report for `openai files list`. + #[ derive( Debug ) ] + pub struct ListReport + { + /// Configure table formatting. + pub table_config : TableConfig, + + /// Files in OpenAI. + pub files : Vec< FileDataWrap > + } + + impl fmt::Display for ListReport + { + fn fmt + ( + &self, + f : &mut fmt::Formatter< '_ > + ) -> fmt::Result + { + display_tabular_data( &AsTable::new( &self.files ), f, &self.table_config ) + } + } + + /// List OpenAI files action. + pub async fn action + ( + client : &Client, + table_config : TableConfig, + ) -> Result < ListReport > + { + check_table_style( &table_config )?; + + let response = client.file_list().await?; + let files = response.data.into_iter().map( FileDataWrap ).collect(); + Ok( ListReport { table_config, files } ) + } + +} + +crate::mod_interface! +{ + own use action; +} \ No newline at end of file diff --git a/module/move/assistant/src/actions/openai_runs_list.rs b/module/move/assistant/src/actions/openai_runs_list.rs new file mode 100644 index 0000000000..d5bf8098c6 --- /dev/null +++ b/module/move/assistant/src/actions/openai_runs_list.rs @@ -0,0 +1,65 @@ +//! +//! List runs in OpenAI API (action part). +//! + +mod private +{ + + use std::fmt; + + use format_tools::AsTable; + + use crate::*; + use client::Client; + + use debug::RunObjectWrap; + + use actions::openai::{ Result, check_table_style }; + + use commands::TableConfig; + use util::display_table::display_tabular_data; + + /// Report for `openai runs list`. + #[ derive( Debug ) ] + pub struct ListReport + { + /// Configure table formatting. + pub table_config : TableConfig, + + /// Current OpenAI runs. + pub runs : Vec< RunObjectWrap >, + } + + impl fmt::Display for ListReport + { + fn fmt + ( + &self, + f : &mut fmt::Formatter< '_ > + ) -> fmt::Result + { + display_tabular_data( &AsTable::new( &self.runs ), f, &self.table_config ) + } + } + + /// List OpenAI runs action. + pub async fn action + ( + client : &Client, + thread_id : String, + table_config : TableConfig, + ) -> Result < ListReport > + { + check_table_style( &table_config )?; + + let response = client.list_run( thread_id, None, None, None, None ).await?; + let runs = response.data.into_iter().map( RunObjectWrap ).collect(); + Ok( ListReport { table_config, runs } ) + } + +} + +crate::mod_interface! +{ + own use action; +} \ No newline at end of file diff --git a/module/move/assistant/src/agents.rs b/module/move/assistant/src/agents.rs new file mode 100644 index 0000000000..0f04d8a61c --- /dev/null +++ b/module/move/assistant/src/agents.rs @@ -0,0 +1,16 @@ +//! +//! Main module for agents framework. +//! + +mod private {} + +crate::mod_interface! +{ + + layer path; + layer context; + layer scenario_raw; + layer scenario_raw_processors; + layer scenario_processed; + +} \ No newline at end of file diff --git a/module/move/assistant/src/agents/context.rs b/module/move/assistant/src/agents/context.rs new file mode 100644 index 0000000000..a18a535780 --- /dev/null +++ b/module/move/assistant/src/agents/context.rs @@ -0,0 +1,150 @@ +//! +//! Context representation. Can be used as compile-time context and as a runtime-context. +//! +//! Represents a simplistic "filesystem" with directories and terminal objects. +//! + +mod private +{ + use std::collections::HashMap; + + use crate::*; + use agents::path:: + { + Path, + PATH_SEPARATOR, + }; + + /// Represents a directory in a simplistic in-memory "filesystem" + /// with other directories and terminal objects. + /// + /// `T` is the type of terminal object. + #[ derive( Debug, PartialEq, Clone, Default ) ] + pub struct ContextDir< T > + { + /// Internal map of entry names and entries data (a directory or a terminal object). + map : HashMap< String, ContextEntry< T > >, + } + + impl< T > ContextDir< T > + { + /// Create an empty `ContextDir`. + pub fn new() -> Self + { + Self + { + map : HashMap::new() + } + } + + /// Add new entry to the directory. + /// + /// Returns `true` if entry was successfully added. + /// Returns `false` if there is already and entry with such name. + /// Old entry will not be overriden. + pub fn add( &mut self, name : impl Into< String >, entry : ContextEntry< T > ) -> bool + { + let name = name.into(); + + if self.map.contains_key( name.as_str() ) + { + false + } + else + { + self.map.insert( name, entry ); + true + } + } + + /// Get an entry by its name. Returns `None` is there is no such entry. + /// + /// `name` must be a valid path item. Refer to `path::PATH_ITEM_REGEX_STR` for syntax. + /// + /// This method is useful for quickly getting an entry only by its name. + /// For complex paths, where your object is located in several consecutives directories, + /// you can use `Path` type and use method `ContextDir::get_by_path`. + pub fn get( &self, name : impl AsRef< str > ) -> Option< &ContextEntry< T > > + { + self.map.get( name.as_ref() ) + } + + /// Get an entry by its path. Returns `None` is there is no such entry. + /// + /// This function accepts both relative and absolute paths and it will + /// treat itself as the root. + pub fn get_by_path( &self, path : &Path ) -> Option< &ContextEntry< T > > + { + let mut cur : Option< &ContextEntry< T > > = None; + + for component in path.components() + { + if component == PATH_SEPARATOR + { + continue; + } + + match cur + { + None => + { + cur = self.get( component ); + }, + + Some( entry ) => + { + match entry + { + ContextEntry::Terminal( _ ) => + { + return None; + }, + + ContextEntry::Dir( dir ) => + { + cur = dir.get( component ); + } + } + } + } + + if cur.is_none() + { + return None; + } + } + + cur + } + } + + /// Entry in a simplistic in-memory "filesystem": either a directory or a terminal object `T`. + /// + /// Notice, this struct does not store the name of the entry. + #[ derive( Debug, PartialEq, Clone ) ] + pub enum ContextEntry< T > + { + /// Directory in context. + Dir( ContextDir< T > ), + + /// Terminal object. + Terminal( T ), + } + + impl< T > Into< ContextEntry< T > > for ContextDir< T > + { + fn into( self ) -> ContextEntry< T > + { + ContextEntry::Dir( self ) + } + } +} + +crate::mod_interface! +{ + own use + { + ContextDir, + ContextEntry, + }; +} \ No newline at end of file diff --git a/module/move/assistant/src/agents/path.rs b/module/move/assistant/src/agents/path.rs new file mode 100644 index 0000000000..d0c29a15dd --- /dev/null +++ b/module/move/assistant/src/agents/path.rs @@ -0,0 +1,241 @@ +//! +//! Paths in agents graph. +//! + +mod private +{ + use std:: + { + io, + fmt, + ops::Deref, + sync::LazyLock, + }; + + use serde:: + { + Serialize, + Deserialize, + }; + + use regex::Regex; + + /// Path separator string. + pub const PATH_SEPARATOR : &str = "::"; + + /// Regular expression for `Path` items. Represented in `&str`. + /// It is not anchored to start and end of the string. + /// + /// If you want to match against this expression, use `PATH_ITEM_REGEX`. + pub const PATH_ITEM_REGEX_STR : &str = r"[a-zA-Z0-9_ -]+"; + + /// Regular expression for `Path`. You can match whole `&str` with this type. + pub static PATH_REGEX : LazyLock< Regex > = LazyLock::new( || + { + let regex = format! + ( + r"^({sep})?({item}({sep}{item})*({sep})?)?$", + sep = PATH_SEPARATOR, + item = PATH_ITEM_REGEX_STR, + ); + + Regex::new( ®ex ).unwrap() + }); + + /// New type for paths in agents graph. Use `TryFrom` implementation + /// to create `Path`s. + /// + /// Paths resemble filesystem path, path separator is `::`. + /// Absolute path starts with `::`. + #[ derive( Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize ) ] + pub struct Path( String ); + + impl Path + { + /// Returns the parent directory, if it exists. + /// + /// Returns `None` if the `Path` terminates in a root or if it's the empty string. + #[ inline ] + pub fn parent( &self ) -> Option< Path > + { + /// Find parent of a `Path`. + /// + /// This method uses `&str` as an argument instead of `Path` + /// in order to be more general and handle trailing `::` case. + fn find_parent( s : &str ) -> Option< &str > + { + s.rfind( PATH_SEPARATOR ) + .map( | sep_pos | + { + if sep_pos == 0 + { + // We found root. We should not return string before `::`, + // as it will be empty. + Some( PATH_SEPARATOR ) + } + else if sep_pos == s.len() - PATH_SEPARATOR.len() + { + // We found trailing `::`. We should continue looking for last separator. + find_parent( &s[ .. sep_pos ] ) + } + else + { + Some( &s[ .. sep_pos ] ) + } + }) + .flatten() + } + + find_parent( self.0.as_str() ) + .map( | s | Self( s.to_string() ) ) + } + + /// Returns whether the `Path` is relative (does not start with `::`). + pub fn is_relative( &self ) -> bool + { + !self.is_absolute() + } + + /// Returns whether the `Path` is absolute (starts with `::`). + pub fn is_absolute( &self ) -> bool + { + self.0.starts_with( PATH_SEPARATOR ) + } + + /// Creates an owned `Path` by joining a given path to `self`. + /// + /// If path is joined with an absolute path, then this absolute + /// path will be returned. + #[ inline ] + pub fn join( &self, path : &Path ) -> Self + { + if path.is_absolute() + { + path.clone() + } + else + { + if self.0.ends_with( PATH_SEPARATOR ) + { + Self( format!( "{}{}", self.0, path.0 ) ) + } + else + { + Self( format!( "{}::{}", self.0, path.0 ) ) + } + } + } + + /// Checks if the `Path` starts with a given base path. + #[ inline ] + pub fn starts_with( &self, base : &Path ) -> bool + { + self.0.starts_with( base.0.as_str() ) + } + + /// Returns the inner `String`. + #[ inline( always ) ] + pub fn inner( self ) -> String + { + self.0 + } + + /// Iterate over components of a `Path`. If the `Path` is absolute, then the first + /// element will be `::`. + pub fn components( &self ) -> impl Iterator< Item = &str > + { + self.0.split( PATH_SEPARATOR ).map( | c | + { + if c.is_empty() + { + PATH_SEPARATOR + } + else + { + c + } + }) + } + } + + impl fmt::Display for Path + { + #[ inline ] + fn fmt( &self, f : &mut fmt::Formatter<'_> ) -> fmt::Result + { + write!( f, "{}", self.0 ) + } + } + + impl TryFrom< String > for Path + { + type Error = io::Error; + + fn try_from( src : String ) -> Result< Self, Self::Error > + { + if PATH_REGEX.is_match( src.as_str() ) + { + Ok( Self ( src ) ) + } + else + { + Err( io::Error::from( io::ErrorKind::InvalidData ) ) + } + } + } + + impl TryFrom< &str > for Path + { + type Error = io::Error; + + fn try_from( src : &str ) -> Result< Self, Self::Error > + { + if PATH_REGEX.is_match( src ) + { + Ok( Self ( src.to_string() ) ) + } + else + { + Err( io::Error::from( io::ErrorKind::InvalidData ) ) + } + } + } + + impl AsRef< str > for Path + { + #[ inline ] + fn as_ref( &self ) -> &str + { + self.0.as_ref() + } + } + + impl Into< String > for Path + { + #[ inline ] + fn into( self ) -> String + { + self.0 + } + } + + impl Deref for Path + { + type Target = str; + + #[ inline ] + fn deref( &self ) -> &Self::Target + { + &self.0 + } + } +} + +crate::mod_interface! +{ + own use + { + Path, + PATH_SEPARATOR, + }; +} \ No newline at end of file diff --git a/module/move/assistant/src/agents/scenario_processed.rs b/module/move/assistant/src/agents/scenario_processed.rs new file mode 100644 index 0000000000..b43e9c0075 --- /dev/null +++ b/module/move/assistant/src/agents/scenario_processed.rs @@ -0,0 +1,99 @@ +//! +//! Scenario representation. Stores parsed representation of templates and paths. +//! This is the type used for running scenarios. +//! +//! For a more simplistic representation use `ScenarioRaw`. +//! + +mod private +{ + use std::collections::HashMap; + + use crate::*; + use agents:: + { + path::Path, + scenario_raw:: + { + ScenarioRaw, + NodeRaw, + }, + }; + + /// New type for templates in scenarios. + #[ derive( Debug, PartialEq ) ] + pub struct TemplateBody( pub String ); + + /// Struct that represents user written scenarios. + /// + /// This is a processed form of a scenario, paths are distinguished here with types. + /// For more simplistic representation of scenarios, use `ScenarioRaw` type. + #[ derive( Debug, PartialEq ) ] + pub struct ScenarioProcessed + { + /// Nodes in the scenario. + pub nodes: Vec< Node >, + } + + impl TryFrom< ScenarioRaw > for ScenarioProcessed + { + type Error = std::io::Error; + + fn try_from( scenario_raw : ScenarioRaw ) -> Result< Self, Self::Error > + { + let nodes : Result< Vec< Node >, Self::Error > = + scenario_raw.nodes.into_iter().map( | rn | Node::try_from( rn ) ).collect(); + + Ok( Self { nodes : nodes? } ) + } + } + + /// Node representation in a scenario file. + /// + /// This is a processed form of a node, paths are distinguished here with types. + /// For more simplistic representation of scenarios, use `NodeRaw` type. + #[ derive( Debug, PartialEq ) ] + pub struct Node + { + /// ID of the node. Must be unique, will also identify node output. + pub id : String, + + /// Type of the node. + pub r#type : Path, + + /// Parameters of the node. + pub params : HashMap< String, String >, + + /// ID of the next node to execute. + pub next : Path, + } + + impl TryFrom< NodeRaw > for Node + { + type Error = std::io::Error; + + fn try_from( node_raw : NodeRaw ) -> Result< Self, Self::Error > + { + Ok + ( + Self + { + id : node_raw.id, + r#type : Path::try_from( node_raw.r#type )?, + params : node_raw.params, + next : Path::try_from( node_raw.next )?, + } + ) + } + } +} + +crate::mod_interface! +{ + own use + { + TemplateBody, + ScenarioProcessed, + Node, + }; +} \ No newline at end of file diff --git a/module/move/assistant/src/agents/scenario_raw.rs b/module/move/assistant/src/agents/scenario_raw.rs new file mode 100644 index 0000000000..8aef1e2250 --- /dev/null +++ b/module/move/assistant/src/agents/scenario_raw.rs @@ -0,0 +1,71 @@ +//! +//! Raw scenario representation. Captures only the basic syntax of scenario file. +//! +//! For more detailed representation, use `ScenarioProcessed`. +//! + +mod private +{ + use std:: + { + io, + collections::HashMap, + }; + + use former::Former; + use serde:: + { + Serialize, + Deserialize, + }; + + /// Struct that represents user written scenarios. + /// + /// This is a raw form of a scenario, only the general structure is captured there. + /// For more detailed representation of scenarios, use `ScenarioProcessed` type. + #[ derive( Debug, Serialize, Deserialize, Former, PartialEq ) ] + pub struct ScenarioRaw + { + /// Nodes in the scenario. + pub nodes: Vec< NodeRaw >, + } + + impl ScenarioRaw + { + /// Read scenario file in YAML format. + pub fn read( reader : impl io::Read ) -> Result< Self, serde_yaml::Error > + { + serde_yaml::from_reader( reader ) + } + } + + /// Node representation in a scenario file. + /// + /// This is a raw form of a node, only the general structure is captured there. + /// For more detailed representation of scenarios, use `Node` type. + #[ derive( Debug, Serialize, Deserialize, Former, PartialEq ) ] + pub struct NodeRaw + { + /// ID of the node. Must be unique, will also identify node output. + pub id : String, + + /// Type of the node. Represented as a path. + pub r#type : String, + + /// Rest of the key-value pairs in the node that are specific to node types. + #[ serde( flatten ) ] + pub params : HashMap< String, String >, + + /// ID of the next node to execute. Represented as a path. + pub next : String, + } +} + +crate::mod_interface! +{ + own use + { + ScenarioRaw, + NodeRaw, + }; +} \ No newline at end of file diff --git a/module/move/assistant/src/agents/scenario_raw_processors.rs b/module/move/assistant/src/agents/scenario_raw_processors.rs new file mode 100644 index 0000000000..4e9ebb7798 --- /dev/null +++ b/module/move/assistant/src/agents/scenario_raw_processors.rs @@ -0,0 +1,13 @@ +//! +//! `ScenarioRaw` processors: functions that work with `ScenarioRaw`. +//! +//! Currently only formatters are implemented. +//! + +mod private {} + +crate::mod_interface! +{ + layer yaml_formatter; + layer plantuml_formatter; +} \ No newline at end of file diff --git a/module/move/assistant/src/agents/scenario_raw_processors/plantuml_formatter.rs b/module/move/assistant/src/agents/scenario_raw_processors/plantuml_formatter.rs new file mode 100644 index 0000000000..8f1114fe2d --- /dev/null +++ b/module/move/assistant/src/agents/scenario_raw_processors/plantuml_formatter.rs @@ -0,0 +1,76 @@ +//! +//! Format scenario in PlantUML diagram. +//! + +mod private +{ + use std::io; + + use crate::*; + use agents::scenario_raw::ScenarioRaw; + + /// Format scenario in PlantUML diagram. + pub fn plantuml_formatter + ( + scenario : &ScenarioRaw, + writer : &mut impl io::Write, + ) -> Result< (), io::Error > + { + writer.write( b"@startuml\n" )?; + + for node in &scenario.nodes + { + writer.write( b"json " )?; + writer.write( node.id.as_bytes() )?; + writer.write( b" {\n" )?; + + writer.write( b" \"type\": \"" )?; + writer.write( node.r#type.as_bytes() )?; + writer.write( b"\"" )?; + + if node.params.len() > 0 + { + writer.write( b"," )?; + } + + writer.write( b"\n" )?; + + for ( i, ( key, value ) ) in node.params.iter().enumerate() + { + writer.write( b" \"" )?; + writer.write( key.as_bytes() )?; + writer.write( b"\": \"" )?; + writer.write( value.as_bytes() )?; + writer.write( b"\"" )?; + + if i != node.params.len() - 1 + { + writer.write( b"," )?; + } + + writer.write( b"\n" )?; + } + + writer.write( b"}\n" )?; + } + + writer.write( b"json ::scenario::termination {\n" )?; + writer.write( b"}\n" )?; + + for node in &scenario.nodes + { + writer.write( node.id.as_bytes() )?; + writer.write( b" --> " )?; + writer.write( node.next.as_bytes() )?; + writer.write( b" : next\n" )?; + } + + writer.write( b"@enduml" )?; + Ok( () ) + } +} + +crate::mod_interface! +{ + own use plantuml_formatter; +} \ No newline at end of file diff --git a/module/move/assistant/src/agents/scenario_raw_processors/yaml_formatter.rs b/module/move/assistant/src/agents/scenario_raw_processors/yaml_formatter.rs new file mode 100644 index 0000000000..05d1bb5668 --- /dev/null +++ b/module/move/assistant/src/agents/scenario_raw_processors/yaml_formatter.rs @@ -0,0 +1,26 @@ +//! +//! Format scenario in YAML format (pretty-printing). +//! + +mod private +{ + use std::io; + + use crate::*; + use agents::scenario_raw::ScenarioRaw; + + /// Pretty-print `ScenarioRaw` in YAML format. + pub fn yaml_formatter + ( + scenario : &ScenarioRaw, + writer : &mut impl io::Write, + ) -> Result< (), serde_yaml::Error > + { + serde_yaml::to_writer( writer, scenario ) + } +} + +crate::mod_interface! +{ + own use yaml_formatter; +} \ No newline at end of file diff --git a/module/move/assistant/src/main.rs b/module/move/assistant/src/bin/list_resources.rs similarity index 93% rename from module/move/assistant/src/main.rs rename to module/move/assistant/src/bin/list_resources.rs index d8a93d1956..d85d524ceb 100644 --- a/module/move/assistant/src/main.rs +++ b/module/move/assistant/src/bin/list_resources.rs @@ -19,7 +19,8 @@ use dotenv::dotenv; use assistant:: { - client, + client::client, + Secret }; #[ tokio::main ] @@ -27,7 +28,9 @@ async fn main() -> Result< (), Box< dyn Error > > { dotenv().ok(); - let client = client()?; + let secret = Secret::load()?; + + let client = client( &secret )?; let response = client.file_list().await?; // println!( "Files: {:?}", response.data ); @@ -49,4 +52,4 @@ async fn main() -> Result< (), Box< dyn Error > > ); Ok( () ) -} +} \ No newline at end of file diff --git a/module/move/assistant/src/bin/main.rs b/module/move/assistant/src/bin/main.rs new file mode 100644 index 0000000000..419030d03b --- /dev/null +++ b/module/move/assistant/src/bin/main.rs @@ -0,0 +1,42 @@ +#![ 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/assistant/latest/assistant/" ) ] +#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] + +use std:: +{ + env, + error::Error, +}; + +use dotenv::dotenv; +use clap::Parser; + +use assistant:: +{ + client::client, + commands::{ Cli, CliCommand, self }, + Secret +}; + +#[ tokio::main ] +async fn main() -> Result< (), Box< dyn Error > > +{ + dotenv().ok(); + + let secret = Secret::load()?; + + let client = client( &secret )?; + + let cli = Cli::parse(); + + match cli.command + { + CliCommand::OpenAi( openai_command ) => + { + commands::openai::command( &client, openai_command ).await; + } + } + + Ok( () ) +} diff --git a/module/move/assistant/src/client.rs b/module/move/assistant/src/client.rs index 51a00cb368..1c9fd0bbee 100644 --- a/module/move/assistant/src/client.rs +++ b/module/move/assistant/src/client.rs @@ -2,40 +2,28 @@ //! Client of API. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { - pub use openai_api_rs::v1:: { api::OpenAIClient as Client, - // api::Client, assistant::AssistantObject, }; use std:: { - env, error::Error, }; - use former::Former; - - /// Options for configuring the OpenAI API client. - #[ derive( Former, Debug ) ] - pub struct ClientOptions - { - /// The API key for authenticating with the OpenAI API. - pub api_key : Option< String >, - } + use crate::*; + use secret::Secret; - /// Creates a new OpenAI API client using the API key from the environment variable `OPENAI_API_KEY`. - pub fn client() -> Result< Client, Box< dyn Error > > + /// Creates a new OpenAI API client using the secrets. + pub fn client( secrets : &Secret ) -> Result< Client, Box< dyn Error > > { - let api_key = env::var( "OPENAI_API_KEY" )?; - println!( "api_key : {}", api_key ); - Ok( Client::new( api_key ) ) + Ok( Client::new( secrets.OPENAI_API_KEY.clone() ) ) } } @@ -45,8 +33,7 @@ crate::mod_interface! exposed use { Client, - ClientOptions, AssistantObject, - client, + client }; } diff --git a/module/move/assistant/src/commands.rs b/module/move/assistant/src/commands.rs new file mode 100644 index 0000000000..480b13d8d5 --- /dev/null +++ b/module/move/assistant/src/commands.rs @@ -0,0 +1,77 @@ +//! +//! CLI commands of the tool. +//! + +/// Internal namespace. +mod private +{ + + use clap::{ Parser, Subcommand }; + + use crate::*; + use commands::openai; + + /// CLI commands of the tool. + #[ derive ( Debug, Parser ) ] + pub struct Cli + { + /// Root of the CLI commands. + #[ command ( subcommand ) ] + pub command : CliCommand, + } + + /// Root of the CLI commands. + #[ derive ( Debug, Subcommand ) ] + pub enum CliCommand + { + /// OpenAI API commands. + #[ command ( subcommand, name = "openai" ) ] + OpenAi( openai::Command ), + } + + const DEFAULT_MAX_TABLE_WIDTH : usize = 130; + + /// Common collection of arguments for formatting tabular data. + #[ derive( Debug, Parser ) ] + pub struct TableConfig + { + /// Limit table widht. + #[ arg( long, default_value_t = DEFAULT_MAX_TABLE_WIDTH ) ] + pub max_table_width : usize, + + /// Show tabular data as an ordinary table. + #[ arg( long ) ] + pub as_table : bool, + + /// Show each record of a tabular data as a separate table. + #[ arg( long ) ] + pub as_records : bool, + + /// Show only keys (columns) of tabular data. + #[ arg( long ) ] + pub columns : bool, + + /// Filter columns of tabular data. + #[ arg( long, value_delimiter( ',' ) ) ] + pub filter_columns : Vec< String >, + } + +} + +crate::mod_interface! +{ + layer openai; + layer openai_assistants; + layer openai_assistants_list; + layer openai_runs; + layer openai_runs_list; + layer openai_files; + layer openai_files_list; + + own use + { + Cli, + CliCommand, + TableConfig, + }; +} diff --git a/module/move/assistant/src/commands/openai.rs b/module/move/assistant/src/commands/openai.rs new file mode 100644 index 0000000000..42c7ea5595 --- /dev/null +++ b/module/move/assistant/src/commands/openai.rs @@ -0,0 +1,75 @@ +//! +//! Collection of OpenAI API commands. +//! + +mod private +{ + + use clap::Subcommand; + + use crate::*; + use client::Client; + use commands::{ openai_assistants, openai_files, openai_runs }; + + /// OpenAI API commands. + #[ derive ( Debug, Subcommand ) ] + pub enum Command + { + /// OpenAI assistants. + #[ command ( subcommand ) ] + Assistants + ( + openai_assistants::Command + ), + + /// OpenAI files. + #[ command ( subcommand ) ] + Files + ( + openai_files::Command + ), + + /// OpenAI runs. + #[ command ( subcommand ) ] + Runs + ( + openai_runs::Command + ), + } + + /// Execute OpenAI command. + pub async fn command + ( + client : &Client, + command : Command, + ) + { + match command + { + Command::Assistants( assistants_command ) => + { + openai_assistants::command( client, assistants_command ).await; + } + + Command::Files( files_command ) => + { + openai_files::command( client, files_command ).await; + } + + Command::Runs( runs_command ) => + { + openai_runs::command( client, runs_command ).await; + } + } + } + +} + +crate::mod_interface! +{ + own use + { + Command, + command, + }; +} \ No newline at end of file diff --git a/module/move/assistant/src/commands/openai_assistants.rs b/module/move/assistant/src/commands/openai_assistants.rs new file mode 100644 index 0000000000..0d941c94ba --- /dev/null +++ b/module/move/assistant/src/commands/openai_assistants.rs @@ -0,0 +1,52 @@ +//! +//! Collection of assistants commands for OpenAI API. +//! + +mod private +{ + + use clap::Subcommand; + + use crate::*; + use client::Client; + use commands::{ openai_assistants_list, TableConfig }; + + /// OpenAI assistants. + #[ derive ( Debug, Subcommand ) ] + pub enum Command + { + /// List OpenAI assistants. + List + { + /// Configure table formatting. + #[ clap( flatten ) ] + table_config : TableConfig, + }, + } + + /// Execute OpenAI command related to assistants. + pub async fn command + ( + client : &Client, + command : Command, + ) + { + match command + { + Command::List{ table_config } => + { + openai_assistants_list::command( client, table_config ).await; + } + } + } + +} + +crate::mod_interface! +{ + own use + { + Command, + command, + }; +} \ No newline at end of file diff --git a/module/move/assistant/src/commands/openai_assistants_list.rs b/module/move/assistant/src/commands/openai_assistants_list.rs new file mode 100644 index 0000000000..6ce7a80ac4 --- /dev/null +++ b/module/move/assistant/src/commands/openai_assistants_list.rs @@ -0,0 +1,34 @@ +//! +//! List assistants in OpenAI API (command part). +//! + +mod private +{ + + use crate::*; + use client::Client; + use actions; + use commands::TableConfig; + + /// List OpenAI assistants command. + pub async fn command + ( + client : &Client, + table_config : TableConfig, + ) + { + let result = actions::openai_assistants_list::action( client, table_config ).await; + + match result + { + Ok ( report ) => println!( "{}", report ), + Err ( error ) => println!( "{}", error ) + } + } + +} + +crate::mod_interface! +{ + own use command; +} \ No newline at end of file diff --git a/module/move/assistant/src/commands/openai_files.rs b/module/move/assistant/src/commands/openai_files.rs new file mode 100644 index 0000000000..ea72a42ad1 --- /dev/null +++ b/module/move/assistant/src/commands/openai_files.rs @@ -0,0 +1,52 @@ +//! +//! Collection of files commands for OpenAI API. +//! + +mod private +{ + + use clap::Subcommand; + + use crate::*; + use client::Client; + use commands::{ openai_files_list, TableConfig }; + + /// OpenAI files. + #[ derive ( Debug, Subcommand ) ] + pub enum Command + { + /// List OpenAI files. + List + { + /// Configure table formatting. + #[ clap( flatten ) ] + table_config : TableConfig, + }, + } + + /// Execute OpenAI commands related to files. + pub async fn command + ( + client : &Client, + command : Command, + ) + { + match command + { + Command::List{ table_config } => + { + openai_files_list::command( client, table_config ).await; + } + } + } + +} + +crate::mod_interface! +{ + own use + { + Command, + command, + }; +} \ No newline at end of file diff --git a/module/move/assistant/src/commands/openai_files_list.rs b/module/move/assistant/src/commands/openai_files_list.rs new file mode 100644 index 0000000000..6225b9faf2 --- /dev/null +++ b/module/move/assistant/src/commands/openai_files_list.rs @@ -0,0 +1,34 @@ +//! +//! List files in OpenAI API (command part). +//! + +mod private +{ + + use crate::*; + use client::Client; + use actions; + use commands::TableConfig; + + /// List files in your OpenAI API. + pub async fn command + ( + client : &Client, + table_config : TableConfig, + ) + { + let result = actions::openai_files_list::action( client, table_config ).await; + + match result + { + Ok ( report ) => println!( "{}", report ), + Err ( error ) => println!( "{}", error ) + } + } + +} + +crate::mod_interface! +{ + own use command; +} \ No newline at end of file diff --git a/module/move/assistant/src/commands/openai_runs.rs b/module/move/assistant/src/commands/openai_runs.rs new file mode 100644 index 0000000000..2cf7812000 --- /dev/null +++ b/module/move/assistant/src/commands/openai_runs.rs @@ -0,0 +1,55 @@ +//! +//! Collection of runs commands for OpenAI API. +//! + +mod private +{ + + use clap::Subcommand; + + use crate::*; + use client::Client; + use commands::{ openai_runs_list, TableConfig }; + + /// OpenAI runs. + #[ derive ( Debug, Subcommand ) ] + pub enum Command + { + /// List OpenAI runs in a thread. + List + { + /// Thread ID. + thread_id : String, + + /// Configure table formatting. + #[ clap( flatten ) ] + table_config : TableConfig, + } + } + + /// Execute OpenAI commands related to runs. + pub async fn command + ( + client : &Client, + command : Command, + ) + { + match command + { + Command::List { thread_id, table_config } => + { + openai_runs_list::command( client, thread_id, table_config ).await; + } + } + } + +} + +crate::mod_interface! +{ + own use + { + Command, + command, + }; +} \ No newline at end of file diff --git a/module/move/assistant/src/commands/openai_runs_list.rs b/module/move/assistant/src/commands/openai_runs_list.rs new file mode 100644 index 0000000000..6d08d64ed3 --- /dev/null +++ b/module/move/assistant/src/commands/openai_runs_list.rs @@ -0,0 +1,35 @@ +//! +//! List runs in OpenAI API (command part). +//! + +mod private +{ + + use crate::*; + use client::Client; + use actions; + use commands::TableConfig; + + /// List runs in the thread in OpenAI API. + pub async fn command + ( + client : &Client, + thread_id : String, + table_config : TableConfig, + ) + { + let result = actions::openai_runs_list::action( client, thread_id, table_config ).await; + + match result + { + Ok ( report ) => println!( "{}", report ), + Err ( error ) => println!( "{}", error ) + } + } + +} + +crate::mod_interface! +{ + own use command; +} \ No newline at end of file diff --git a/module/move/assistant/src/debug.rs b/module/move/assistant/src/debug.rs index e5966e4f2c..294333abf0 100644 --- a/module/move/assistant/src/debug.rs +++ b/module/move/assistant/src/debug.rs @@ -2,7 +2,7 @@ //! Client of API. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { @@ -17,6 +17,7 @@ use std::borrow::Cow; mod assistant_object; mod file_data; +mod run_object; crate::mod_interface! { @@ -24,5 +25,6 @@ crate::mod_interface! { assistant_object::AssistantObjectWrap, file_data::FileDataWrap, + run_object::RunObjectWrap, }; } diff --git a/module/move/assistant/src/debug/assistant_object.rs b/module/move/assistant/src/debug/assistant_object.rs index 1535245f67..9ebcead56e 100644 --- a/module/move/assistant/src/debug/assistant_object.rs +++ b/module/move/assistant/src/debug/assistant_object.rs @@ -5,6 +5,7 @@ use openai_api_rs::v1::assistant; #[ derive( Debug ) ] pub struct AssistantObjectWrap( pub assistant::AssistantObject ); +/// Manually implemented `Clone`, as `FileData` does not implement it. impl Clone for AssistantObjectWrap { fn clone( &self ) -> Self diff --git a/module/move/assistant/src/debug/file_data.rs b/module/move/assistant/src/debug/file_data.rs index ca1fb242d4..b8029949c7 100644 --- a/module/move/assistant/src/debug/file_data.rs +++ b/module/move/assistant/src/debug/file_data.rs @@ -8,6 +8,7 @@ use openai_api_rs::v1::file::FileData; #[ derive( Debug ) ] pub struct FileDataWrap( pub FileData ); +/// Manually implemented `Clone`, as `FileData` does not implement it. impl Clone for FileDataWrap { fn clone( &self ) -> Self diff --git a/module/move/assistant/src/debug/run_object.rs b/module/move/assistant/src/debug/run_object.rs new file mode 100644 index 0000000000..efe2ce1e02 --- /dev/null +++ b/module/move/assistant/src/debug/run_object.rs @@ -0,0 +1,73 @@ + +use super::*; +use openai_api_rs::v1::run::RunObject; + +// Assuming the `format_tools` module and `field!` macro are defined elsewhere + +/// A wrapper for `RunObject` to make pretty print. +#[ derive( Debug ) ] +pub struct RunObjectWrap( pub RunObject ); + +/// Manually implemented `Clone`, as `RunObject` does not implement it. +impl Clone for RunObjectWrap { + fn clone(&self) -> Self { + RunObjectWrap(RunObject { + id : self.0.id.clone(), + object : self.0.object.clone(), + created_at : self.0.created_at, + thread_id : self.0.thread_id.clone(), + assistant_id : self.0.assistant_id.clone(), + status : self.0.status.clone(), + required_action : self.0.required_action.clone(), + last_error : self.0.last_error.clone(), + expires_at : self.0.expires_at, + started_at : self.0.started_at, + cancelled_at : self.0.cancelled_at, + failed_at : self.0.failed_at, + completed_at : self.0.completed_at, + model : self.0.model.clone(), + instructions : self.0.instructions.clone(), + tools : self.0.tools.clone(), + metadata : self.0.metadata.clone(), + headers : self.0.headers.clone(), + }) + } +} + +impl TableWithFields for RunObjectWrap {} +impl Fields< &'_ str, Option< Cow< '_, str > > > +for RunObjectWrap +{ + type Key< 'k > = &'k str; + type Val< 'v > = Option< Cow< 'v, str > >; + + fn fields( &self ) -> impl format_tools::IteratorTrait< Item = ( &'_ str, Option< Cow< '_, str > > ) > + { + use format_tools::ref_or_display_or_debug_multiline::field; + let mut dst = Vec::new(); + + dst.push( field!( &self.0.id ) ); + dst.push( field!( &self.0.object ) ); + dst.push( ( "created_at", Some( Cow::Owned( self.0.created_at.to_string() ) ) ) ); + dst.push( field!( &self.0.thread_id ) ); + dst.push( field!( &self.0.assistant_id ) ); + dst.push( field!( &self.0.status ) ); + + dst.push( ( "required_action", self.0.required_action.as_ref().map( |ra| Cow::Owned( format!( "{:?}", ra ) ) ) ) ); + dst.push( ( "last_error", self.0.last_error.as_ref().map( |le| Cow::Owned( format!( "{:?}", le ) ) ) ) ); + dst.push( ( "expires_at", self.0.expires_at.map( |ea| Cow::Owned( ea.to_string() ) ) ) ); + dst.push( ( "started_at", self.0.started_at.map( |sa| Cow::Owned( sa.to_string() ) ) ) ); + dst.push( ( "cancelled_at", self.0.cancelled_at.map( |ca| Cow::Owned( ca.to_string() ) ) ) ); + dst.push( ( "failed_at", self.0.failed_at.map( |fa| Cow::Owned( fa.to_string() ) ) ) ); + dst.push( ( "completed_at", self.0.completed_at.map( |ca| Cow::Owned( ca.to_string() ) ) ) ); + + dst.push( field!( &self.0.model ) ); + dst.push( ( "instructions", self.0.instructions.as_ref().map( |i| Cow::Owned( i.clone() ) ) ) ); + + dst.push( ( "tools", Some( Cow::Owned( format!( "{:?}", self.0.tools ) ) ) ) ); + dst.push( ( "metadata", Some( Cow::Owned( format!( "{:?}", self.0.metadata ) ) ) ) ); + dst.push( ( "headers", self.0.headers.as_ref().map( |h| Cow::Owned( format!( "{:?}", h ) ) ) ) ); + + dst.into_iter() + } +} diff --git a/module/move/assistant/src/lib.rs b/module/move/assistant/src/lib.rs index 2c0c103663..4d21799cc5 100644 --- a/module/move/assistant/src/lib.rs +++ b/module/move/assistant/src/lib.rs @@ -4,12 +4,24 @@ #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] use mod_interface::mod_interface; +use error_tools::thiserror; -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } +/// Serde-related exports. +pub mod ser +{ + pub use serde:: + { + Serialize, + Deserialize, + }; + pub use serde_with::*; +} + // pub mod client; crate::mod_interface! @@ -17,6 +29,11 @@ crate::mod_interface! layer client; layer debug; + layer commands; + layer actions; + layer secret; + layer util; + layer agents; exposed use ::reflect_tools:: { diff --git a/module/move/assistant/src/secret.rs b/module/move/assistant/src/secret.rs new file mode 100644 index 0000000000..aa90da77bc --- /dev/null +++ b/module/move/assistant/src/secret.rs @@ -0,0 +1,219 @@ +//! +//! Tool's secrets. +//! + +/// Internal namespace. +mod private +{ + use crate::*; + use std:: + { + env, + sync::OnceLock, + }; + + use error_tools::typed::Error; + use ser::DisplayFromStr; + + /// Typed secret error. + #[ ser::serde_as ] + #[ derive( Debug, Error, ser::Serialize ) ] + #[ serde( tag = "type", content = "data" ) ] + pub enum Error + { + + /// Secret file is illformed. + #[ error( "Secret file is illformed\n{0}" ) ] + SecretFileIllformed + ( + #[ from ] + #[ serde_as( as = "DisplayFromStr" ) ] + dotenv::Error + ), + + /// Some variable in the secrets is missing. + #[ error( "Secret misssing the variable {0}" ) ] + VariableMissing( &'static str ), + + /// Some variable in the secrets is illformed. + #[ error( "Secret error processing the variable {0}\n{1}" ) ] + VariableIllformed( &'static str, String ), + + } + + /// Result type for `Secret` methods. + pub type Result< R > = core::result::Result< R, Error >; + + /// Represents the application secrets loaded from environment variables. + #[ derive( Debug ) ] + #[ allow( non_snake_case ) ] + pub struct Secret + { + /// OpenAI API key. + pub OPENAI_API_KEY : String, + } + + impl Secret + { + + /// Loads secrets from environment variables. + /// + /// # Returns + /// + /// * `Result< Self >` - On success, returns a `Secret` instance with values from environment variables. + /// * On failure, returns an error indicating which environment variable is missing or invalid. + #[ allow( non_snake_case ) ] + pub fn load() -> Result< Self > + { + let path = "./.key/-env.sh"; + + // Attempt to load environment variables from the specified file + let r = dotenv::from_filename( path ); + if let Err( ref err ) = r + { + // Only return an error if it's not an Io error, and include the file path in the error message + if !matches!( err, dotenv::Error::Io( _ ) ) + { + return Err( r.expect_err( &format!( "Failed to load {path}" ) ).into() ); + } + } + + let config = Self + { + OPENAI_API_KEY : var( "OPENAI_API_KEY", None )?, + }; + Ok( config ) + } + + /// Reads the secrets, panicking with an explanation if loading fails. + /// + /// # Returns + /// + /// * `Secret` - The loaded secrets. + /// + /// # Panics + /// + /// * Panics with a detailed explanation if the secrets cannot be loaded. + + pub fn read() -> Secret + { + Self::load().unwrap_or_else( | err | + { + let example = include_str!( "../.key/readme.md" ); + let explanation = format! + ( +r#" = Lack of secrets + +Failed to load secret or some its parameters. +{err} + + = Fix + +Either define missing environment variable or make sure `./.key/-env.toml` file has it defined. + + = More information + +{example} +"# + ); + panic!( "{}", explanation ); + }) + } + + /// Retrieves a static reference to the secrets, initializing it if necessary. + /// + /// # Returns + /// + /// * `&'static Secret` - A static reference to the secrets. + /// + /// # Warning + /// + /// * Do not use this function unless absolutely necessary. + /// * Avoid using it in `lib.rs`. + pub fn get() -> &'static Secret + { + static INSTANCE : OnceLock< Secret > = OnceLock::new(); + INSTANCE.get_or_init( || Self::read() ) + } + + } + + /// Retrieves the value of an environment variable as a `String`. + /// + /// This function attempts to fetch the value of the specified environment variable. + /// If the variable is not set, it returns a provided default value if available, or an error if not. + /// + /// # Arguments + /// + /// * `name` - The name of the environment variable to retrieve. + /// * `default` - An optional default value to return if the environment variable is not set. + /// + /// # Returns + /// + /// * `Result` - On success, returns the value of the environment variable or the default value. + /// * On failure, returns an error indicating the missing environment variable. + fn var + ( + name : &'static str, + default : Option< &'static str >, + ) -> Result< String > + { + match env::var( name ) + { + Ok( value ) => Ok( value ), + Err( _ ) => + { + if let Some( default_value ) = default + { + Ok( default_value.to_string() ) + } + else + { + Err( Error::VariableMissing( name ) ) + } + } + } + } + + /// Retrieves the value of an environment variable as an `AbsolutePath`. + /// + /// This function attempts to fetch the value of the specified environment variable and convert it into an `AbsolutePath`. + /// If the variable is not set, it returns a provided default value if available, or an error if not. + /// + /// # Arguments + /// + /// * `name` - The name of the environment variable to retrieve. + /// * `default` - An optional default value to return if the environment variable is not set. + /// + /// # Returns + /// + /// * `Result` - On success, returns the parsed `AbsolutePath`. + /// * On failure, returns an error indicating the missing or ill-formed environment variable. + fn _var_path + ( + name : &'static str, + default : Option< &'static str >, + ) -> Result< pth::AbsolutePath > + { + let p = var( name, default )?; + pth::AbsolutePath::from_paths( ( pth::CurrentPath, p ) ) + .map_err( |e| Error::VariableIllformed( name, e.to_string() ) ) + } + +} + +crate::mod_interface! +{ + + own use + { + Error, + Result, + }; + + orphan use + { + Secret, + }; + +} \ No newline at end of file diff --git a/module/move/assistant/src/util.rs b/module/move/assistant/src/util.rs new file mode 100644 index 0000000000..7e34c0fd16 --- /dev/null +++ b/module/move/assistant/src/util.rs @@ -0,0 +1,10 @@ +//! +//! Collection of utility functions for this crate. +//! + +mod private {} + +crate::mod_interface! +{ + layer display_table; +} \ No newline at end of file diff --git a/module/move/assistant/src/util/display_table.rs b/module/move/assistant/src/util/display_table.rs new file mode 100644 index 0000000000..c4e7ddcd28 --- /dev/null +++ b/module/move/assistant/src/util/display_table.rs @@ -0,0 +1,128 @@ +//! +//! Function for displaying tabular data according to `TableConfig`. +//! + +mod private +{ + + use std::fmt; + + use format_tools:: + { + TableFormatter, + output_format, + print, + TableOutputFormat, + }; + + use crate::*; + use commands::{ TableConfig }; + + /// Function for displaying tabular data according to `TableConfig`. + pub fn display_tabular_data<'a> + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ >, + table_config : &'a TableConfig, + ) -> fmt::Result + { + if table_config.as_table + { + display_table( data, f, table_config ) + } + else if table_config.as_records + { + display_records( data, f, table_config ) + } + else if table_config.columns + { + display_columns( data, f, table_config ) + } + else + { + display_table( data, f, table_config ) + } + } + + fn display_table<'a> + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ >, + table_config : &'a TableConfig, + ) -> fmt::Result + { + let mut format = output_format::Table::default(); + format.max_width = table_config.max_table_width; + + display_data + ( + data, + f, + format, + &table_config.filter_columns, + ) + } + + fn display_records<'a> + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ >, + table_config : &'a TableConfig, + ) -> fmt::Result + { + let mut format = output_format::Records::default(); + format.max_width = table_config.max_table_width; + + display_data + ( + data, + f, + format, + &table_config.filter_columns, + ) + } + + fn display_columns<'a> + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ >, + table_config : &'a TableConfig, + ) -> fmt::Result + { + let mut format = output_format::Records::default(); + format.max_width = table_config.max_table_width; + + display_data + ( + data, + f, + format, + &table_config.filter_columns, + ) + } + + fn display_data<'a> + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ >, + format : impl TableOutputFormat, + filter_columns : &'a Vec< String >, + ) -> fmt::Result + { + let mut printer = print::Printer::with_format( &format ); + let binding = | title : &str | + { + filter_columns.is_empty() || filter_columns.iter().any( |c| c.as_str() == title ) + }; + printer.filter_col = &binding; + + let mut context = print::Context::new( f, printer ); + TableFormatter::fmt( data, &mut context ) + } + +} + +crate::mod_interface! +{ + own use display_tabular_data; +} \ No newline at end of file diff --git a/module/move/assistant/tests/inc/agents_tests/context_test.rs b/module/move/assistant/tests/inc/agents_tests/context_test.rs new file mode 100644 index 0000000000..e28fc8c264 --- /dev/null +++ b/module/move/assistant/tests/inc/agents_tests/context_test.rs @@ -0,0 +1,128 @@ +use super::*; + +use the_module::agents:: +{ + path::Path, + context:: + { + ContextDir, + ContextEntry, + }, +}; + +#[ test ] +fn context_dir_add_terminal() +{ + let mut ctx : ContextDir< () > = ContextDir::new(); + let entry = ContextEntry::Terminal( () ); + let name = "test"; + + let res = ctx.add( name, entry.clone() ); + + assert!( res ); + assert_eq!( ctx.get( name ), Some( &entry ) ); +} + +#[ test ] +fn context_dir_add_dir() +{ + let mut ctx : ContextDir< () > = ContextDir::new(); + let entry : ContextEntry< () > = ContextDir::new().into(); + let name = "test"; + + let res = ctx.add( name, entry.clone() ); + + assert!( res ); + assert_eq!( ctx.get( name ), Some( &entry ) ); +} + +#[ test ] +fn context_dir_add_duplicate() +{ + let name = "test"; + let orig_entry = ContextEntry::Terminal( 1 ); + + let mut ctx : ContextDir< usize > = ContextDir::new(); + ctx.add( name, orig_entry.clone() ); + + let res = ctx.add( name, ContextEntry::Terminal( 2 ) ); + + assert!( !res ); + assert_eq!( ctx.get( name ), Some( &orig_entry ) ); +} + +#[ test ] +fn context_dir_get() +{ + let mut ctx : ContextDir< usize > = ContextDir::new(); + ctx.add( "test_1", ContextEntry::Terminal( 1 ) ); + ctx.add( "test_2", ContextEntry::Terminal( 2 ) ); + ctx.add( "test_3", ContextEntry::Terminal( 3 ) ); + + assert_eq!( ctx.get( "test_1" ), Some( &ContextEntry::Terminal( 1 ) ) ); + assert_eq!( ctx.get( "test_2" ), Some( &ContextEntry::Terminal( 2 ) ) ); + assert_eq!( ctx.get( "test_3" ), Some( &ContextEntry::Terminal( 3 ) ) ); +} + +#[ test ] +fn context_dir_get_non_existing() +{ + let ctx : ContextDir< () > = ContextDir::new(); + + let res = ctx.get( "test" ); + + assert!( res.is_none() ); +} + +#[ test ] +fn context_dir_get_by_path_relative() +{ + let value_1 = ContextEntry::Terminal( 1 ); + let value_2 = ContextEntry::Terminal( 2 ); + let value_3 = ContextEntry::Terminal( 3 ); + + let mut dir_1 : ContextDir< usize > = ContextDir::new(); + dir_1.add( "value_1", value_1.clone() ); + dir_1.add( "value_2", value_2.clone() ); + + let mut dir_3 : ContextDir< usize > = ContextDir::new(); + dir_3.add( "value_3", value_3.clone() ); + + let mut dir_2 : ContextDir< usize > = ContextDir::new(); + dir_2.add( "dir_3", dir_3.into() ); + + let mut ctx : ContextDir< usize > = ContextDir::new(); + ctx.add( "dir_1", dir_1.into() ); + ctx.add( "dir_2", dir_2.into() ); + + let got_value_1 = ctx.get_by_path( &Path::try_from( "dir_1::value_1" ).unwrap() ); + let got_value_2 = ctx.get_by_path( &Path::try_from( "dir_1::value_2" ).unwrap() ); + let got_value_3 = ctx.get_by_path( &Path::try_from( "dir_2::dir_3::value_3" ).unwrap() ); + + assert_eq!( got_value_1, Some( &value_1 ) ); + assert_eq!( got_value_2, Some( &value_2 ) ); + assert_eq!( got_value_3, Some( &value_3 ) ); +} + +#[ test ] +fn context_dir_get_by_path_absolute() +{ + let entry = ContextEntry::Terminal( () ); + let mut ctx : ContextDir< () > = ContextDir::new(); + ctx.add( "test", entry.clone() ); + + let res = ctx.get_by_path( &&Path::try_from( "::test" ).unwrap() ); + + assert!( res.is_some() ); + assert_eq!( res.unwrap(), &entry ); +} + +#[ test ] +fn context_dir_get_by_path_non_existing() +{ + let ctx : ContextDir< () > = ContextDir::new(); + + let res = ctx.get_by_path( &Path::try_from( "test" ).unwrap() ); + + assert!( res.is_none() ); +} \ No newline at end of file diff --git a/module/move/assistant/tests/inc/agents_tests/mod.rs b/module/move/assistant/tests/inc/agents_tests/mod.rs new file mode 100644 index 0000000000..f4260d9ed5 --- /dev/null +++ b/module/move/assistant/tests/inc/agents_tests/mod.rs @@ -0,0 +1,9 @@ +use super::*; + +mod test_scenarios; + +mod path_test; +mod context_test; +mod scenario_raw_test; +mod scenario_raw_processors; +mod scenario_processed_test; \ No newline at end of file diff --git a/module/move/assistant/tests/inc/agents_tests/path_test.rs b/module/move/assistant/tests/inc/agents_tests/path_test.rs new file mode 100644 index 0000000000..277f4965ff --- /dev/null +++ b/module/move/assistant/tests/inc/agents_tests/path_test.rs @@ -0,0 +1,259 @@ +use super::*; + +use the_module::agents::path::Path; + +#[ test ] +fn path_create_right() +{ + let path_str = "agent::completion"; + + let path = Path::try_from( path_str ); + + assert!( path.is_ok() ); + assert_eq! ( path.unwrap().inner(), path_str ); +} + +#[ test ] +fn path_create_wrong() +{ + let path = Path::try_from( "agent:completion" ); + assert!( path.is_err() ); +} + +#[ test ] +fn path_create_absolute() +{ + let path_str = "::agent::completion"; + + let path = Path::try_from( path_str ); + + assert!( path.is_ok() ); + assert_eq! ( path.unwrap().inner(), path_str ); +} + +#[ test ] +fn path_create_trailing() +{ + let path_str = "agent::completion::"; + + let path = Path::try_from( path_str ); + + assert!( path.is_ok() ); + assert_eq! ( path.unwrap().inner(), path_str ); +} + +#[ test ] +fn path_some_parent_relative() +{ + let path_str = "agent::completion"; + let path = Path::try_from( path_str ).unwrap(); + + let path_parent = path.parent(); + + assert!( path_parent.is_some() ); + assert_eq!( path_parent.unwrap().inner(), "agent" ); +} + +#[ test ] +fn path_some_parent_relative_trailing() +{ + let path_str = "agent::completion::"; + let path = Path::try_from( path_str ).unwrap(); + + let path_parent = path.parent(); + + assert!( path_parent.is_some() ); + assert_eq!( path_parent.unwrap().inner(), "agent" ); +} + +#[ test ] +fn path_some_parent_absolute() +{ + let path_str = "::agent"; + let path = Path::try_from( path_str ).unwrap(); + + let path_parent = path.parent(); + + assert!( path_parent.is_some() ); + assert_eq!( path_parent.unwrap().inner(), "::" ); +} + +#[ test ] +fn path_some_parent_absolute_trailing() +{ + let path_str = "::agent::"; + let path = Path::try_from( path_str ).unwrap(); + + let path_parent = path.parent(); + + assert!( path_parent.is_some() ); + assert_eq!( path_parent.unwrap().inner(), "::" ); +} + +#[ test ] +fn path_none_parent() +{ + let path_str = "agent"; + let path = Path::try_from( path_str ).unwrap(); + + let path_parent = path.parent(); + + assert!( path_parent.is_none() ); +} + +#[ test ] +fn path_is_relative() +{ + let path_str = "agent"; + let path = Path::try_from( path_str ).unwrap(); + + let is_relative = path.is_relative(); + let is_absolute = path.is_absolute(); + + assert!( is_relative ); + assert!( !is_absolute ); +} + +#[ test ] +fn path_is_absolute() +{ + let path_str = "::agent"; + let path = Path::try_from( path_str ).unwrap(); + + let is_relative = path.is_relative(); + let is_absolute = path.is_absolute(); + + assert!( !is_relative ); + assert!( is_absolute ); +} + +#[ test ] +fn path_join_relative() +{ + let orig_path = Path::try_from( "agent" ).unwrap(); + let append = Path::try_from( "completion" ).unwrap(); + + let combined = orig_path.join( &append ); + + assert_eq!( combined.inner(), "agent::completion" ); +} + +#[ test ] +fn path_join_absolute() +{ + let orig_path = Path::try_from( "agent" ).unwrap(); + let append = Path::try_from( "::completion" ).unwrap(); + + let combined = orig_path.join( &append ); + + assert_eq!( combined.inner(), "::completion" ); +} + +#[ test ] +fn path_join_root() +{ + let orig_path = Path::try_from( "::" ).unwrap(); + let append = Path::try_from( "agent" ).unwrap(); + + let combined = orig_path.join( &append ); + + assert_eq!( combined.inner(), "::agent" ); +} + +#[ test ] +fn path_join_trailing() +{ + let orig_path = Path::try_from( "agents::" ).unwrap(); + let append = Path::try_from( "completion" ).unwrap(); + + let combined = orig_path.join( &append ); + + assert_eq!( combined.inner(), "agents::completion" ); +} + +#[ test ] +fn path_starts_with_abs_abs() +{ + let a = Path::try_from( "::agent::completion" ).unwrap(); + let b = Path::try_from( "::agent" ).unwrap(); + + let starts_with = a.starts_with( &b ); + + assert!( starts_with ); +} + +#[ test ] +fn path_starts_with_abs_rel() +{ + let a = Path::try_from( "::agent::completion" ).unwrap(); + let b = Path::try_from( "agent" ).unwrap(); + + let starts_with = a.starts_with( &b ); + + assert!( !starts_with ); +} + +#[ test ] +fn path_starts_with_rel_abs() +{ + let a = Path::try_from( "agent" ).unwrap(); + let b = Path::try_from( "::agent::completion" ).unwrap(); + + let starts_with = a.starts_with( &b ); + + assert!( !starts_with ); +} + +#[ test ] +fn path_starts_with_rel_rel() +{ + let a = Path::try_from( "agent::completion" ).unwrap(); + let b = Path::try_from( "agent" ).unwrap(); + + let starts_with = a.starts_with( &b ); + + assert!( starts_with ); +} + +#[ test ] +fn path_not_starts_with_abs_abs() +{ + let a = Path::try_from( "::agent::completion" ).unwrap(); + let b = Path::try_from( "::output" ).unwrap(); + + let starts_with = a.starts_with( &b ); + + assert!( !starts_with ); +} + +#[ test ] +fn path_not_starts_with_rel_rel() +{ + let a = Path::try_from( "agent::completion" ).unwrap(); + let b = Path::try_from( "output" ).unwrap(); + + let starts_with = a.starts_with( &b ); + + assert!( !starts_with ); +} + +#[ test ] +fn path_inner() +{ + let path_str = "::agent::completion"; + let path = Path::try_from( path_str ).unwrap(); + + let inner = path.inner(); + + assert_eq!( inner, path_str ); +} + +#[ test ] +fn path_components() +{ + let path = Path::try_from( "::agents::completion" ).unwrap(); + + let components : Vec< &str > = path.components().collect(); + + assert_eq!( components, vec![ "::", "agents", "completion" ] ); +} \ No newline at end of file diff --git a/module/move/assistant/tests/inc/agents_tests/scenario_processed_test.rs b/module/move/assistant/tests/inc/agents_tests/scenario_processed_test.rs new file mode 100644 index 0000000000..5fc734ae41 --- /dev/null +++ b/module/move/assistant/tests/inc/agents_tests/scenario_processed_test.rs @@ -0,0 +1,25 @@ +use super::*; + +use the_module::agents::scenario_processed::ScenarioProcessed; + +use test_scenarios:: +{ + gen_test_scenario_raw, + gen_test_scenario_raw_wrong, +}; + +#[ test ] +fn scenario_processed_right() +{ + let scenario_processed = ScenarioProcessed::try_from( gen_test_scenario_raw() ); + + assert!( scenario_processed.is_ok() ); +} + +#[ test ] +fn scenario_processed_wrong() +{ + let scenario_processed = ScenarioProcessed::try_from( gen_test_scenario_raw_wrong() ); + + assert!( scenario_processed.is_err() ); +} \ No newline at end of file diff --git a/module/move/assistant/tests/inc/agents_tests/scenario_raw_processors/mod.rs b/module/move/assistant/tests/inc/agents_tests/scenario_raw_processors/mod.rs new file mode 100644 index 0000000000..bbaccfe254 --- /dev/null +++ b/module/move/assistant/tests/inc/agents_tests/scenario_raw_processors/mod.rs @@ -0,0 +1,4 @@ +use super::*; + +mod plantuml_formatter_test; +mod yaml_formatter_test; \ No newline at end of file diff --git a/module/move/assistant/tests/inc/agents_tests/scenario_raw_processors/plantuml_formatter_test.rs b/module/move/assistant/tests/inc/agents_tests/scenario_raw_processors/plantuml_formatter_test.rs new file mode 100644 index 0000000000..44d5cf86b7 --- /dev/null +++ b/module/move/assistant/tests/inc/agents_tests/scenario_raw_processors/plantuml_formatter_test.rs @@ -0,0 +1,33 @@ +use super::*; + +use the_module::agents::scenario_raw_processors::plantuml_formatter::plantuml_formatter; + +use test_scenarios::gen_test_scenario_raw; + + +#[ test ] +fn plantuml_formatter_test() +{ + let expected_plantuml = r#"@startuml +json node_1 { + "type": "agents::completion", + "model": "gpt-4o-mini" +} +json node_2 { + "type": "agents::classify", + "model": "gpt-4o" +} +json ::scenario::termination { +} +node_1 --> node_2 : next +node_2 --> ::scenario::termination : next +@enduml"#; + + let scenario_raw = gen_test_scenario_raw(); + + let mut buffer = Vec::new(); + let result = plantuml_formatter( &scenario_raw, &mut buffer ); + + assert!( result.is_ok() ); + assert_eq!( String::from_utf8( buffer ).unwrap(), expected_plantuml ); +} diff --git a/module/move/assistant/tests/inc/agents_tests/scenario_raw_processors/yaml_formatter_test.rs b/module/move/assistant/tests/inc/agents_tests/scenario_raw_processors/yaml_formatter_test.rs new file mode 100644 index 0000000000..fd64cbacec --- /dev/null +++ b/module/move/assistant/tests/inc/agents_tests/scenario_raw_processors/yaml_formatter_test.rs @@ -0,0 +1,33 @@ +use super::*; + +use the_module::agents::scenario_raw_processors::yaml_formatter::yaml_formatter; + +use test_scenarios::gen_test_scenario_raw; + +#[ test ] +fn yaml_formatter_test() +{ + let expected_yaml = r#"nodes: +- id: node_1 + type: agents::completion + model: gpt-4o-mini + next: node_2 +- id: node_2 + type: agents::classify + model: gpt-4o + next: ::scenario::termination"#; + + let scenario_raw = gen_test_scenario_raw(); + + let mut buffer = Vec::new(); + let result = yaml_formatter( &scenario_raw, &mut buffer ); + assert!( result.is_ok() ); + + let result = String::from_utf8( buffer ); + assert!( result.is_ok() ); + + let result = result.unwrap(); + println!( "{}", result ); + + assert_eq!( result.trim(), expected_yaml.trim() ); +} diff --git a/module/move/assistant/tests/inc/agents_tests/scenario_raw_test.rs b/module/move/assistant/tests/inc/agents_tests/scenario_raw_test.rs new file mode 100644 index 0000000000..2f8acc60fe --- /dev/null +++ b/module/move/assistant/tests/inc/agents_tests/scenario_raw_test.rs @@ -0,0 +1,49 @@ +use super::*; + +use the_module::agents::scenario_raw::ScenarioRaw; + +use test_scenarios::gen_test_scenario_raw; + +#[ test ] +fn scenario_read() +{ + let scenario_text = r#" + nodes: + - id: node_1 + type: agents::completion + model: gpt-4o-mini + next: node_2 + + - id: node_2 + type: agents::classify + model: gpt-4o + next: ::scenario::termination + "#; + + let expected_scenario_raw = gen_test_scenario_raw(); + + let scenario_raw = ScenarioRaw::read( scenario_text.as_bytes() ); + + assert!( scenario_raw.is_ok() ); + + let scenario_raw = scenario_raw.unwrap(); + assert_eq!( scenario_raw, expected_scenario_raw ); +} + +#[ test ] +fn scenario_wrong() +{ + let scenario_text = r#" + nodes: + - completion: + model: + company: openai + name: gpt-4o + depends_on: + node_2 + "#; + + let scenario_raw = ScenarioRaw::read( scenario_text.as_bytes() ); + + assert!( scenario_raw.is_err() ); +} \ No newline at end of file diff --git a/module/move/assistant/tests/inc/agents_tests/test_scenarios.rs b/module/move/assistant/tests/inc/agents_tests/test_scenarios.rs new file mode 100644 index 0000000000..02433a68ea --- /dev/null +++ b/module/move/assistant/tests/inc/agents_tests/test_scenarios.rs @@ -0,0 +1,64 @@ +use super::*; + +use the_module::agents::scenario_raw:: +{ + ScenarioRaw, + NodeRaw, +}; + +/// Generates an example `ScenarioRaw`. +pub fn gen_test_scenario_raw() -> ScenarioRaw +{ + ScenarioRaw::former() + .nodes( vec! + [ + NodeRaw::former() + .id( "node_1".to_string() ) + .r#type( "agents::completion".to_string() ) + .params( + { + let mut map : HashMap< String, String > = HashMap::new(); + map.insert( "model".into(), "gpt-4o-mini".into() ); + map + } + ) + .next( "node_2".to_string() ) + .form(), + + NodeRaw::former() + .id( "node_2".to_string() ) + .r#type( "agents::classify".to_string() ) + .params( + { + let mut map : HashMap< String, String > = HashMap::new(); + map.insert( "model".into(), "gpt-4o".into() ); + map + } + ) + .next( "::scenario::termination".to_string() ) + .form(), + ] ) + .form() +} + +/// Generates a `ScenarioRaw` with wrong syntax for `Path`. +pub fn gen_test_scenario_raw_wrong() -> ScenarioRaw +{ + ScenarioRaw::former() + .nodes( vec! + [ + NodeRaw::former() + .id( "node_1".to_string() ) + .r#type( ":agents:".to_string() ) // This part is incorrect. Path written in wrong syntax. + .params( + { + let mut map : HashMap< String, String > = HashMap::new(); + map.insert( "model".into(), "gpt-4o-mini".into() ); + map + } + ) + .next( "node_2".to_string() ) + .form(), + ] ) + .form() +} \ No newline at end of file diff --git a/module/move/assistant/tests/inc/mod.rs b/module/move/assistant/tests/inc/mod.rs index 0706620c6e..abf35e2f97 100644 --- a/module/move/assistant/tests/inc/mod.rs +++ b/module/move/assistant/tests/inc/mod.rs @@ -1,6 +1,7 @@ #[ allow( unused_imports ) ] use super::*; -mod basic_test; +mod agents_tests; +mod basic_test; mod experiment; diff --git a/module/move/crates_tools/Readme.md b/module/move/crates_tools/Readme.md index dabc50fb6c..f407d2599e 100644 --- a/module/move/crates_tools/Readme.md +++ b/module/move/crates_tools/Readme.md @@ -1,6 +1,6 @@ -# Module :: crates_tools +# Module :: `crates_tools` [![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_crates_tools_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_crates_tools_push.yml) [![docs.rs](https://img.shields.io/docsrs/crates_tools?color=e3e8f0&logo=docs.rs)](https://docs.rs/crates_tools) [![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%2Fmove%2Fcrates_tools%2Fexamples%2Fcrates_tools_trivial.rs,RUN_POSTFIX=--example%20crates_tools_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) @@ -25,7 +25,6 @@ Some possible use cases are: ```rust use crates_tools::*; -fn main() { #[ cfg( feature = "enabled" ) ] { diff --git a/module/move/crates_tools/src/lib.rs b/module/move/crates_tools/src/lib.rs index 92dc8c0048..1d60bb2135 100644 --- a/module/move/crates_tools/src/lib.rs +++ b/module/move/crates_tools/src/lib.rs @@ -3,24 +3,26 @@ #![ doc( html_root_url = "https://docs.rs/crates_tools/latest/crates_tools/" ) ] #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( feature = "enabled" ) ] mod private { use std::collections::HashMap; - use std::fmt::Formatter; + use core::fmt::Formatter; use std::io::Read; use std::path::{ Path, PathBuf }; - use std::time::Duration; - use ureq::{ Agent, AgentBuilder }; + use core::time::Duration; + use ureq::AgentBuilder; /// Represents a `.crate` archive, which is a collection of files and their contents. #[ derive( Default, Clone, PartialEq ) ] pub struct CrateArchive( HashMap< PathBuf, Vec< u8 > > ); - impl std::fmt::Debug for CrateArchive + impl core::fmt::Debug for CrateArchive { - fn fmt( &self, f : &mut Formatter< '_ > ) -> std::fmt::Result + #[ allow( clippy::implicit_return, clippy::min_ident_chars ) ] + #[ inline] + fn fmt( &self, f : &mut Formatter< '_ > ) -> core::fmt::Result { f.debug_struct( "CrateArchive" ).field( "files", &self.0.keys() ).finish() } @@ -29,24 +31,33 @@ mod private impl CrateArchive { /// Reads and decode a `.crate` archive from a given path. + /// # Errors + /// qqq: doc + #[ allow( clippy::question_mark_used, clippy::implicit_return ) ] + #[ inline ] pub fn read< P >( path : P ) -> std::io::Result< Self > where P : AsRef< Path >, { let mut file = std::fs::File::open( path )?; let mut buf = vec![]; + #[ allow( clippy::verbose_file_reads ) ] file.read_to_end( &mut buf )?; Self::decode( buf ) } #[ cfg( feature = "network" ) ] + #[ allow( clippy::question_mark_used, clippy::implicit_return, clippy::result_large_err ) ] /// Downloads and decodes a `.crate` archive from a given url. + /// # Errors + /// qqq: docs + #[ inline ] pub fn download< Url >( url : Url ) -> Result< Self, ureq::Error > where Url : AsRef< str >, { - let agent: Agent = AgentBuilder::new() + let agent = AgentBuilder::new() .timeout_read( Duration::from_secs( 5 ) ) .timeout_write( Duration::from_secs( 5 ) ) .build(); @@ -63,16 +74,24 @@ mod private /// Requires the full version of the package, in the format of `"x.y.z"` /// /// Returns error if the package with specified name and version - not exists. + /// # Errors + /// qqq: doc #[ cfg( feature = "network" ) ] + #[ allow( clippy::implicit_return, clippy::result_large_err ) ] + #[ inline ] pub fn download_crates_io< N, V >( name : N, version : V ) -> Result< Self, ureq::Error > where - N : std::fmt::Display, - V : std::fmt::Display, + N : core::fmt::Display, + V : core::fmt::Display, { Self::download( format!( "https://static.crates.io/crates/{name}/{name}-{version}.crate" ) ) } /// Decodes a bytes that represents a `.crate` file. + /// # Errors + /// qqq: doc + #[ allow( clippy::question_mark_used, unknown_lints, clippy::implicit_return ) ] + #[ inline ] pub fn decode< B >( bytes : B ) -> std::io::Result< Self > where B : AsRef<[ u8 ]>, @@ -81,43 +100,44 @@ mod private use flate2::bufread::GzDecoder; use tar::Archive; - let bytes = bytes.as_ref(); - if bytes.is_empty() + let bytes_slice = bytes.as_ref(); + if bytes_slice.is_empty() { return Ok( Self::default() ) } - let gz = GzDecoder::new( bytes ); + let gz = GzDecoder::new( bytes_slice ); let mut archive = Archive::new( gz ); let mut output = HashMap::new(); for file in archive.entries()? { - let mut file = file?; + let mut archive_file = file?; let mut contents = vec![]; - file.read_to_end( &mut contents )?; + archive_file.read_to_end( &mut contents )?; - output.insert( file.path()?.to_path_buf(), contents ); + output.insert( archive_file.path()?.to_path_buf(), contents ); } Ok( Self( output ) ) } - } - impl CrateArchive - { /// Returns a list of files from the `.crate` file. + #[ allow( clippy::implicit_return ) ] + #[ inline ] pub fn list( &self ) -> Vec< &Path > { self.0.keys().map( PathBuf::as_path ).collect() } /// Returns content of file by specified path from the `.crate` file in bytes representation. + #[ allow( clippy::implicit_return ) ] + #[ inline ] pub fn content_bytes< P >( &self, path : P ) -> Option< &[ u8 ] > - where - P : AsRef< Path >, + where + P : AsRef< Path >, { self.0.get( path.as_ref() ).map( Vec::as_ref ) } @@ -126,7 +146,7 @@ mod private #[ cfg( feature = "enabled" ) ] #[ doc( inline ) ] -#[ allow( unused_imports ) ] +#[ allow( unused_imports, clippy::pub_use ) ] pub use own::*; /// Own namespace of the module. @@ -134,9 +154,9 @@ pub use own::*; #[ allow( unused_imports ) ] pub mod own { - use super::*; + use super::orphan; #[ doc( inline ) ] - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::pub_use ) ] pub use orphan::*; } @@ -145,9 +165,9 @@ pub mod own #[ allow( unused_imports ) ] pub mod orphan { - use super::*; + use super::exposed; #[ doc( inline ) ] - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::pub_use ) ] pub use exposed::*; } @@ -156,9 +176,9 @@ pub mod orphan #[ allow( unused_imports ) ] pub mod exposed { - use super::*; + use super::prelude; #[ doc( inline ) ] - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::pub_use ) ] pub use prelude::*; } @@ -167,8 +187,8 @@ pub mod exposed #[ allow( unused_imports ) ] pub mod prelude { - use super::*; + use super::private; #[ doc( inline ) ] - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::pub_use ) ] pub use private::CrateArchive; } diff --git a/module/move/deterministic_rand/Cargo.toml b/module/move/deterministic_rand/Cargo.toml index 1a469f1249..ae667e3e41 100644 --- a/module/move/deterministic_rand/Cargo.toml +++ b/module/move/deterministic_rand/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deterministic_rand" -version = "0.5.0" +version = "0.6.0" edition = "2021" authors = [ "Kostiantyn Wandalen ", diff --git a/module/move/deterministic_rand/src/hrng_deterministic.rs b/module/move/deterministic_rand/src/hrng_deterministic.rs index ceb64b06c0..e489d8522e 100644 --- a/module/move/deterministic_rand/src/hrng_deterministic.rs +++ b/module/move/deterministic_rand/src/hrng_deterministic.rs @@ -6,7 +6,7 @@ //! Both have the same interface and are interchengable by switching on/off a feature `determinsim`. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/move/deterministic_rand/src/hrng_non_deterministic.rs b/module/move/deterministic_rand/src/hrng_non_deterministic.rs index 1ab19d55d2..57db16656b 100644 --- a/module/move/deterministic_rand/src/hrng_non_deterministic.rs +++ b/module/move/deterministic_rand/src/hrng_non_deterministic.rs @@ -6,7 +6,7 @@ //! Both have the same interface and are interchengable by switching on/off a feature `determinsim`. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/move/deterministic_rand/src/iter.rs b/module/move/deterministic_rand/src/iter.rs index caab96a148..cdfb83e100 100644 --- a/module/move/deterministic_rand/src/iter.rs +++ b/module/move/deterministic_rand/src/iter.rs @@ -3,7 +3,7 @@ //! Extensions of iterator for determinism. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/move/deterministic_rand/src/seed.rs b/module/move/deterministic_rand/src/seed.rs index c7f1e078a9..fc68cc4cdf 100644 --- a/module/move/deterministic_rand/src/seed.rs +++ b/module/move/deterministic_rand/src/seed.rs @@ -3,7 +3,7 @@ //! Master seed. //! -/// Internal namespace. +/// Define a private namespace for all its items. mod private { #[ cfg( feature = "no_std" ) ] diff --git a/module/move/graphs_tools/src/abs/edge.rs b/module/move/graphs_tools/src/abs/edge.rs index 550a350efb..214f8f10d9 100644 --- a/module/move/graphs_tools/src/abs/edge.rs +++ b/module/move/graphs_tools/src/abs/edge.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/move/graphs_tools/src/abs/factory.rs b/module/move/graphs_tools/src/abs/factory.rs index 0f6d19e324..ad6bc76c8b 100644 --- a/module/move/graphs_tools/src/abs/factory.rs +++ b/module/move/graphs_tools/src/abs/factory.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/move/graphs_tools/src/abs/id_generator.rs b/module/move/graphs_tools/src/abs/id_generator.rs index 943315c041..2090439804 100644 --- a/module/move/graphs_tools/src/abs/id_generator.rs +++ b/module/move/graphs_tools/src/abs/id_generator.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::prelude::*; diff --git a/module/move/graphs_tools/src/abs/identity.rs b/module/move/graphs_tools/src/abs/identity.rs index 412b759d73..287e69f4b1 100644 --- a/module/move/graphs_tools/src/abs/identity.rs +++ b/module/move/graphs_tools/src/abs/identity.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::prelude::*; diff --git a/module/move/graphs_tools/src/abs/node.rs b/module/move/graphs_tools/src/abs/node.rs index b227581718..703bd0893d 100644 --- a/module/move/graphs_tools/src/abs/node.rs +++ b/module/move/graphs_tools/src/abs/node.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/move/graphs_tools/src/algo/dfs.rs b/module/move/graphs_tools/src/algo/dfs.rs index 0a75884e2c..13e7c81e84 100644 --- a/module/move/graphs_tools/src/algo/dfs.rs +++ b/module/move/graphs_tools/src/algo/dfs.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/move/graphs_tools/src/canonical/edge.rs b/module/move/graphs_tools/src/canonical/edge.rs index 3bf782aaee..4d02b207d4 100644 --- a/module/move/graphs_tools/src/canonical/edge.rs +++ b/module/move/graphs_tools/src/canonical/edge.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/move/graphs_tools/src/canonical/factory_generative.rs b/module/move/graphs_tools/src/canonical/factory_generative.rs index ba735895c4..1e2e838081 100644 --- a/module/move/graphs_tools/src/canonical/factory_generative.rs +++ b/module/move/graphs_tools/src/canonical/factory_generative.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/move/graphs_tools/src/canonical/factory_readable.rs b/module/move/graphs_tools/src/canonical/factory_readable.rs index 9ec9bf6012..d545d38d89 100644 --- a/module/move/graphs_tools/src/canonical/factory_readable.rs +++ b/module/move/graphs_tools/src/canonical/factory_readable.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/move/graphs_tools/src/canonical/identity.rs b/module/move/graphs_tools/src/canonical/identity.rs index 90b53e8879..f4c1a38eba 100644 --- a/module/move/graphs_tools/src/canonical/identity.rs +++ b/module/move/graphs_tools/src/canonical/identity.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/move/graphs_tools/src/canonical/node.rs b/module/move/graphs_tools/src/canonical/node.rs index 94d7f7d313..ce0aa547bd 100644 --- a/module/move/graphs_tools/src/canonical/node.rs +++ b/module/move/graphs_tools/src/canonical/node.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/move/gspread/.secret/readme.md b/module/move/gspread/.secret/readme.md new file mode 100644 index 0000000000..5200f5ef71 --- /dev/null +++ b/module/move/gspread/.secret/readme.md @@ -0,0 +1,61 @@ +# Getting API Keys for OAuth Authentication + +Follow these steps to create and configure your OAuth credentials for using Google APIs. + +## 1. Configure Consent Screen + +1. Go to the [Google API Console](https://console.developers.google.com/). +2. From the projects list, select an existing project or create a new one. +3. Go to **OAuth consent screen** +4. Choose **Extrenal** User Type +5. Fill **App name**, **User support email** and **Developer contact information**. Click **continue** +6. Click on **ADD OR REMOVE SCOPES** +7. Add **.../auth/userinfo.email** and **.../auth/userinfo.profile** spoces. +8. Finish configuration + +## 2. Enable Google Sheets API + +1. Go to the [Google API Console](https://console.developers.google.com/). +2. In the left side menu, select **Enabled APIs & Services**. +3. Click on **ENABLE APIS AND SERVICES** +4. Search for **Google Sheets API** +5. Click on **Enable** + +## 2. Create API Credentials + +1. Go to the [Google API Console](https://console.developers.google.com/). +2. From the projects list, select an existing project or create a new one. +3. In the left side menu, select **APIs & Services**. +4. On the left menu, click **Credentials**. +5. Click **Create Credentials** and select **OAuth client ID**. +6. In the **Application type** section, select **Desktop app**. +7. Provide an appropriate name for your client ID (e.g., "Gspread OAuth Client"). +8. Click **Create**. + +Once the credential is created, you will receive a **Client ID** and **Client Secret**. These are required for accessing the API. + +## 3. Store Your Credentials + +Save the **Client ID** and **Client Secret** in a `.env` within a `.secret` directory. The file should look like this: + +```bash +CLIENT_ID=YOUR_CLIENT_ID +CLIENT_SECRET=YOUR_SECRET_KEY +``` + +## 4. Why do we need it? + +After executing each command, you need to grant the GSPREAD program access to the Google API. You will receive a link that begin with 'Please direct your browser to https://....' that will redirect you to your browser, where you must authorize the access. You will need to select the appropriate Google account that has the credentials for the application. The **CLIENT_ID** and **CLIENT_SECRET** are set up to do this process. + +## 5. Troubleshooting + +If you encounter a page displaying an error instead of the Google account selection screen, it is likely that you need to add **AUTH_URI** or **TOKEN_URI** to the .env file. In this case, all four secrets are required. To retrieve them, download the API key you created in JSON format. Open the file and copy the necessary keys into the .env file. After making these changes, your .env file should look like this: + +```bash +CLIENT_ID=YOUR_CLIENT_ID +CLIENT_SECRET=YOUR_SECRET_KEY +AUTH_URI=YOUR_AUTH_URI +TOKEN_URI=YOUR_TOKEN_URI +``` + +If you still get some issues, follow [Google OAuth Documentation](https://developers.google.com/identity/protocols/oauth2/). \ No newline at end of file diff --git a/module/move/gspread/Cargo.toml b/module/move/gspread/Cargo.toml new file mode 100644 index 0000000000..21a63abb7b --- /dev/null +++ b/module/move/gspread/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "gspread" +version = "0.1.0" +edition = "2021" +authors = [ + "Vsevolod Bakutov " +] +license = "MIT" +description = """ + Google Sheets Cli API +""" +categories = [ "algorithms", "development-tools" ] +keywords = [ "fundamental", "general-purpose" ] +default-run = "main" + +[[bin]] +name = "main" +path = "src/bin/main.rs" + +[features] +with_online = [] +default = [ "enabled" ] +full = [ "enabled" ] +enabled = [ + "former/enabled", + "format_tools/enabled", + "reflect_tools/enabled", +] + +[dependencies] +mod_interface = { workspace = true, features = ["full"] } +former = { workspace = true, features = ["full"] } +format_tools = { workspace = true, features = ["full"] } +reflect_tools = { workspace = true, features = [ "full" ] } +clap = { version = "4.5.20", features = ["derive"] } +tokio = { version = "1", features = ["full"] } +google-sheets4 = "6.0.0" +hyper-util = "0.1.10" +yup-oauth2 = "11.0.0" +pth = "0.21.0" +dotenv = "0.15" +serde = { version = "1.0.213", features = ["derive"] } +serde_with = "3.11.0" +error_tools = "0.19.0" +derive_tools = { version = "0.32.0", features = ["full"] } +serde_json = "1.0.132" +regex = "1.11.1" +unicode-width = "0.2.0" + +[dev-dependencies] +test_tools = { workspace = true } +httpmock = "0.7.0-rc.1" +reqwest = "0.12.9" \ No newline at end of file diff --git a/module/move/gspread/readme.md b/module/move/gspread/readme.md new file mode 100644 index 0000000000..991a5abe04 --- /dev/null +++ b/module/move/gspread/readme.md @@ -0,0 +1,7 @@ +## Module :: gspread + +[![experimental](https://img.shields.io/badge/status-experimental-orange)](https://github.com/emersion/stability-badges#experimental) +[![ask](https://img.shields.io/badge/discord-join%20chat-7289DA)](https://discord.gg/RzQGqF5z) + + +**NOT ready for production** \ No newline at end of file diff --git a/module/move/gspread/src/actions.rs b/module/move/gspread/src/actions.rs new file mode 100644 index 0000000000..1c96538040 --- /dev/null +++ b/module/move/gspread/src/actions.rs @@ -0,0 +1,16 @@ +//! +//! CLI actions of the tool. +//! + +mod private {} + +crate::mod_interface! +{ + layer gspread; + layer gspread_get_header; + layer gspread_get_rows; + layer gspread_cell_get; + layer gspread_cell_set; + layer gspread_cells_set; +} + diff --git a/module/move/gspread/src/actions/gspread.rs b/module/move/gspread/src/actions/gspread.rs new file mode 100644 index 0000000000..711547926d --- /dev/null +++ b/module/move/gspread/src/actions/gspread.rs @@ -0,0 +1,212 @@ +//! +//! Google Sheets API actions. +//! +//! This module also contains the definition of Google Sheets Error. +//! + +mod private +{ + use regex::Regex; + use error_tools::typed::Error; + use derive_tools::AsRefStr; + use crate::*; + use ser:: + { + DisplayFromStr, + JsonValue + }; + use std::collections::HashMap; + use google_sheets4::api:: + { + BatchUpdateValuesResponse, + BatchUpdateValuesRequest, + ValueRange + }; + + #[ ser::serde_as ] + #[ derive( Debug, Error, AsRefStr, ser::Serialize ) ] + #[ serde( tag = "type", content = "data" ) ] + + /// Represents errors that can occur while interacting with the Google Sheets API + /// or during related operations in the application. + pub enum Error + { + /// Represents an error returned by the Google Sheets API. + /// + /// # Details + /// This error occurs when the API returns a specific error message. + /// The error message from the Google Sheets API is stored and displayed. + /// + /// # Fields + /// - `google_sheets4::Error`: The raw error returned by the API. + #[ error( "Google Sheets returned error:\n{0}" ) ] + ApiError + ( + #[ from ] + #[ serde_as( as = "DisplayFromStr" ) ] + google_sheets4::Error + ), + + /// Represents an error that occurs while initializing Google Sheets Hub. + /// + /// # Details + /// This error indicates that the application failed to properly configure with the Google Sheets Hub. + /// + /// # Fields + /// - `String`: A detailed error message describing the issue. + #[ error( "Hub Error:\n{0}" ) ] + HubError + ( + String + ), + + /// Represents an error caused by an invalid URL format. + /// + /// # Details + /// This error occurs when the provided URL does not match the expected format + /// + /// # Fields + /// - `String`: The invalid URL or a message describing the issue. + #[ error( "Invalid URL format:\n{0}" ) ] + InvalidUrl + ( + String + ), + + /// Represents an error related to a cell in the spreadsheet. + /// + /// # Details + /// This error indicates that a cell was not got or updated + /// + /// # Fields + /// - `String`: A message describing the issue with the cell. + #[ error( "Cell error:\n{0}" ) ] + CellError + ( + String + ), + + /// Represents an error caused by invalid JSON input or parsing issues. + /// + /// # Details + /// This error occurs when the provided JSON data does not conform to the expected + /// structure or format. + /// + /// # Fields + /// - `String`: A detailed error message describing the JSON issue. + #[ error( "Invalid JSON format:\n{0}" ) ] + InvalidJSON + ( + String + ), + + /// Represents a generic parsing error. + /// + /// # Details + /// This error is raised when a string or other input cannot be parsed + /// into the expected format or structure. + /// + /// # Fields + /// - `String`: A message describing the parse error. + #[ error( "Parse error:\n{0}" ) ] + ParseError + ( + String + ) + } + + /// Retrive spreadsheet id from url + pub fn get_spreadsheet_id_from_url + ( + url : &str + ) -> Result< &str > + { + + let re = Regex::new( r"d/([^/]+)/edit" ).unwrap(); + if let Some( captures ) = re.captures( url ) + { + if let Some( id ) = captures.get( 1 ) + { + return Ok( id.as_str() ); + } + } + + Err + ( + Error::InvalidUrl( "Wrong url format.\nFix: copy sheet's the whole url from your browser. Usage: --url ''".to_string() ) + ) + } + + /// Function to update a row on a Google Sheet. + /// + /// It sends HTTP request to Google Sheets API and change row wich provided values. + /// + /// **Params** + /// - `spreadsheet_id` : Spreadsheet identifire. + /// - `sheet_name` : Sheet name. + /// - `row_key` : row's key. + /// - `row_key_val` : pairs of key value, where key is a column name and value is a new value. + /// + /// **Returns** + /// - `Result` + pub async fn update_row + ( + spreadsheet_id : &str, + sheet_name : &str, + row_key : &str, + row_key_val : HashMap< String, String > + ) -> Result< BatchUpdateValuesResponse > + { + let secret = Secret::read(); + let hub = hub(&secret) + .await + .map_err( | _ | { + Error::HubError( format!( "Failed to create a hub. Ensure that you have a .env file with Secrets" ) ) + })?; + + let mut value_ranges = Vec::with_capacity( row_key_val.len() ); + + for ( col_name, value ) in row_key_val { + value_ranges.push + ( + ValueRange + { + major_dimension: Some( String::from( "ROWS" ) ), + values: Some( vec![ vec![ JsonValue::String( value ) ] ] ), + range: Some( format!( "{}!{}{}", sheet_name, col_name, row_key ) ), + } + ) + } + + let req = BatchUpdateValuesRequest + { + value_input_option: Some( "USER_ENTERED".to_string() ), + data: Some( value_ranges ), + include_values_in_response: Some( true ), + ..Default::default() + }; + + match hub + .spreadsheets() + .values_batch_update( req, spreadsheet_id ) + .doit() + .await + { + Ok( ( _, response ) ) => Ok( response ), + Err( error ) => Err( Error::ApiError( error ) ), + } + } + + pub type Result< T > = core::result::Result< T, Error >; +} + +crate::mod_interface! +{ + own use + { + Error, + Result, + update_row, + get_spreadsheet_id_from_url, + }; +} \ No newline at end of file diff --git a/module/move/gspread/src/actions/gspread_cell_get.rs b/module/move/gspread/src/actions/gspread_cell_get.rs new file mode 100644 index 0000000000..effa3a9170 --- /dev/null +++ b/module/move/gspread/src/actions/gspread_cell_get.rs @@ -0,0 +1,49 @@ +//! +//! Action for command "cell get" +//! +//! It returns a selected cell +//! + +mod private +{ + + + use crate::*; + use actions::gspread:: + { + Error, + Result + }; + use client::SheetsType; + use ser::JsonValue; + + pub async fn action + ( + hub : &SheetsType, + spreadsheet_id : &str, + table_name : &str, + cell_id : &str, + ) -> Result< JsonValue > + { + match hub + .spreadsheets() + .values_get( spreadsheet_id, format!( "{}!{}", table_name, cell_id ).as_str() ) + .doit() + .await + { + Ok( (_, response ) ) => + match response.values + { + Some( values ) => Ok( values.get( 0 ).unwrap().get( 0 ).unwrap().clone() ), + None => Ok( JsonValue::Null.clone() ) + } + Err( error ) => Err( Error::ApiError( error ) ) + } + + } +} + +crate::mod_interface! +{ + own use action; +} \ No newline at end of file diff --git a/module/move/gspread/src/actions/gspread_cell_set.rs b/module/move/gspread/src/actions/gspread_cell_set.rs new file mode 100644 index 0000000000..5743a45f97 --- /dev/null +++ b/module/move/gspread/src/actions/gspread_cell_set.rs @@ -0,0 +1,61 @@ +//! +//! Action for command "cell set" +//! +//! It updates a selected cell +//! + + +mod private +{ + use google_sheets4::api::ValueRange; + use crate::*; + use actions::gspread:: + { + Result, + Error + }; + use client::SheetsType; + use ser::JsonValue; + + pub async fn action + ( + hub : &SheetsType, + spreadsheet_id : &str, + table_name : &str, + cell_id : &str, + value : &str + ) -> Result< i32 > + { + + let value = JsonValue::String( value.to_string() ); + let value_range = ValueRange + { + values : Some( vec![ vec![ value ] ] ), + ..ValueRange::default() + }; + + match hub + .spreadsheets() + .values_update( value_range, spreadsheet_id, format!( "{}!{}", table_name, cell_id ).as_str() ) + .value_input_option( "USER_ENTERED" ) + .doit() + .await + { + Ok( ( _, response) ) => + { + match response.updated_cells + { + Some( number ) => Ok( number ), + None => Err( Error::CellError( "Some problem with cell updating".to_string() ) ) + } + } + Err( error) => Err( Error::ApiError( error ) ) + } + + } +} + +crate::mod_interface! +{ + own use action; +} \ No newline at end of file diff --git a/module/move/gspread/src/actions/gspread_cells_set.rs b/module/move/gspread/src/actions/gspread_cells_set.rs new file mode 100644 index 0000000000..1099a613d4 --- /dev/null +++ b/module/move/gspread/src/actions/gspread_cells_set.rs @@ -0,0 +1,135 @@ +//! +//! Set command -> set specified values in specified columns in specified row +//! + +mod private +{ + use crate::*; + use actions::gspread:: + { + Error, + Result, + update_row + }; + use ser:: Deserialize; + use std::collections::HashMap; + + /// Structure to keep rows key and new values for cells updating. + #[ derive( Deserialize, Debug ) ] + struct ParsedJson< 'a > + { + row_key : &'a str, + row_key_val : HashMap< String, String > + } + + /// Function to parse `--json` flag. + /// + /// It retirive `--select-row-by-key` flag from json and set it to `row_key` field. + /// Other pairs it set to `row_key_val` + /// + /// **Returns** + /// - `ParsedJson` object + fn parse_json< 'a > + ( + json_str : &'a str, + select_row_by_key : &str, + ) -> Result< ParsedJson< 'a > > + { + let mut parsed_json: HashMap< String, String > = serde_json::from_str( json_str ) + .map_err( | error | Error::InvalidJSON( format!( "Failed to parse JSON: {}", error ) ) )?; + + let row_key = if let Some( row_key ) = parsed_json.remove( select_row_by_key ) + { + Box::leak( row_key.into_boxed_str() ) + } + else + { + return Err + ( + Error::InvalidJSON + ( + format!( "Key '{}' not found in JSON", select_row_by_key) + ) + ); + }; + + for ( col_name, _ ) in &parsed_json + { + if !col_name.chars().all( | c | c.is_alphabetic() && c.is_uppercase() ) + { + return Err + ( + Error::InvalidJSON + ( + format!( "Invalid column name: {}. Allowed only uppercase alphabetic letters (A-Z)", col_name ) + ) + ); + } + }; + + Ok + ( + ParsedJson + { + row_key : row_key, + row_key_val : parsed_json + } + ) + } + + /// Check availables keys. + /// Available keys: "id" -> row's id + fn check_select_row_by_key + ( + key : &str + ) -> Result< () > + { + let keys = vec![ "id" ]; + if keys.contains( &key ) + { + Ok( () ) + } + else + { + Err + ( + Error::ParseError( format!( "Invalid select_row_by_key: '{}'. Allowed keys: {:?}", key, keys ) ) + ) + } + } + + pub async fn action + ( + select_row_by_key : &str, + json_str : &str, + spreadsheet_id : &str, + table_name : &str + ) -> Result< i32 > + { + check_select_row_by_key( select_row_by_key )?; + + match parse_json( json_str, select_row_by_key ) + { + Ok( parsed_json ) => + match update_row( spreadsheet_id, table_name, parsed_json.row_key, parsed_json.row_key_val ).await + { + Ok( response ) => + { + match response.total_updated_cells + { + Some( val ) => Ok( val ), + None => Ok( 0 ), + } + }, + Err( error ) => Err( error ) + } + Err( error ) => Err( error ), + } + } + +} + +crate::mod_interface! +{ + own use action; +} \ No newline at end of file diff --git a/module/move/gspread/src/actions/gspread_get_header.rs b/module/move/gspread/src/actions/gspread_get_header.rs new file mode 100644 index 0000000000..e8de1dc4bc --- /dev/null +++ b/module/move/gspread/src/actions/gspread_get_header.rs @@ -0,0 +1,70 @@ +//! +//! Action for command "header" +//! +//! It returns header (first row) +//! + + +mod private +{ + use std::fmt; + use crate::*; + use client::SheetsType; + use actions::gspread:: + { + Error, + Result + }; + use format_tools::AsTable; + use util::display_table::display_header; + use ser::JsonValue; + + #[ derive( Debug ) ] + pub struct Report + { + pub rows : Vec< RowWrapper > + } + + impl fmt::Display for Report + { + fn fmt + ( + &self, + f : &mut fmt::Formatter + ) -> fmt::Result + { + display_header( &AsTable::new( &self.rows ), f ) + } + } + + pub async fn action + ( + hub : &SheetsType, + spreadsheet_id : &str, + table_name : &str + ) -> Result< Vec< Vec< JsonValue > > > + { + match hub + .spreadsheets() + .values_get( spreadsheet_id, format!( "{}!A1:Z1", table_name ).as_str() ) + .doit() + .await + { + Ok( ( _, response ) ) => + { + match response.values + { + Some( values ) => Ok( values ), + None => Ok( Vec::new() ) + } + }, + Err( error ) => Err( Error::ApiError( error ) ) + } + } + +} + +crate::mod_interface! +{ + own use action; +} \ No newline at end of file diff --git a/module/move/gspread/src/actions/gspread_get_rows.rs b/module/move/gspread/src/actions/gspread_get_rows.rs new file mode 100644 index 0000000000..7f1f7a5c26 --- /dev/null +++ b/module/move/gspread/src/actions/gspread_get_rows.rs @@ -0,0 +1,48 @@ +//! +//! Action for command "rows" +//! +//! It returns all rows but not header +//! + + +mod private +{ + use crate::*; + use client::SheetsType; + use actions::gspread:: + { + Error, + Result + }; + use ser::JsonValue; + + pub async fn action + ( + hub : &SheetsType, + spreadsheet_id : &str, + table_name : &str + ) -> Result< Vec< Vec < JsonValue > > > + { + match hub + .spreadsheets() + .values_get( spreadsheet_id, format!( "{}!A2:Z", table_name ).as_str() ) + .doit() + .await + { + Ok( ( _, response ) ) => + { + match response.values + { + Some( values ) => Ok( values ), + None => Ok( Vec::new() ) + } + }, + Err( error ) => Err( Error::ApiError( error ) ) + } + } +} + +crate::mod_interface! +{ + own use action; +} diff --git a/module/move/gspread/src/bin/main.rs b/module/move/gspread/src/bin/main.rs new file mode 100644 index 0000000000..8f55f07f1c --- /dev/null +++ b/module/move/gspread/src/bin/main.rs @@ -0,0 +1,32 @@ +use std::error::Error; +use clap::Parser; +use dotenv::dotenv; + +use gspread:: +{ + client::hub, + commands::{ Cli, CliCommand, self }, + secret::Secret, +}; + +#[ tokio::main ] +async fn main() -> Result< (), Box< dyn Error > > +{ + dotenv().ok(); + + let secret = Secret::read(); + + let hub = hub( &secret ).await?; + + let cli = Cli::parse(); + + match cli.command + { + CliCommand::GSpread( cmd ) => + { + commands::gspread::command( &hub, cmd ).await; + } + } + + Ok( () ) +} diff --git a/module/move/gspread/src/client.rs b/module/move/gspread/src/client.rs new file mode 100644 index 0000000000..c836ccf4d3 --- /dev/null +++ b/module/move/gspread/src/client.rs @@ -0,0 +1,79 @@ +//! +//! Client of API. +//! + +mod private +{ + + use google_sheets4 as sheets4; + use sheets4::Sheets; + use sheets4::hyper_rustls; + use sheets4::hyper_util; + use sheets4::yup_oauth2:: + { + self, + ApplicationSecret + }; + use hyper_util::client::legacy::connect::HttpConnector; + + pub use hyper_util::client::legacy::Client; + + use std:: + { + error::Error, + }; + + use crate::*; + use secret::Secret; + + pub type SheetsType = Sheets< hyper_rustls::HttpsConnector< HttpConnector > >; + + pub async fn hub( secrets: &Secret ) -> Result< SheetsType, Box< dyn Error > > + { + let secret: ApplicationSecret = ApplicationSecret + { + client_id : secrets.CLIENT_ID.clone(), + auth_uri : secrets.AUTH_URI.clone(), + token_uri : secrets.TOKEN_URI.clone(), + client_secret : secrets.CLIENT_SECRET.clone(), + .. Default::default() + }; + + let auth = yup_oauth2::InstalledFlowAuthenticator::builder + ( + secret, + yup_oauth2::InstalledFlowReturnMethod::HTTPRedirect, + ) + .build() + .await + .unwrap(); + + let client = Client::builder + ( + hyper_util::rt::TokioExecutor::new() + ) + .build + ( + hyper_rustls::HttpsConnectorBuilder::new() + .with_native_roots() + .unwrap() + .https_or_http() + .enable_http1() + .build() + ); + + Ok( Sheets::new( client, auth ) ) + } + + +} + +crate::mod_interface! +{ + exposed use + { + hub, + Client, + SheetsType + }; +} \ No newline at end of file diff --git a/module/move/gspread/src/commands.rs b/module/move/gspread/src/commands.rs new file mode 100644 index 0000000000..5ce88f9eb2 --- /dev/null +++ b/module/move/gspread/src/commands.rs @@ -0,0 +1,52 @@ +//! +//! Commands +//! + + +mod private +{ + + use clap:: + { + Parser, + Subcommand + }; + + use crate::*; + use commands::gspread; + + /// CLI commands of the tool. + #[ derive ( Debug, Parser ) ] + pub struct Cli + { + /// Root of the CLI commands. + #[ command ( subcommand ) ] + pub command : CliCommand, + } + + /// Root of the CLI commands. + #[ derive ( Debug, Subcommand ) ] + pub enum CliCommand + { + /// Google Sheets commands. + #[ command ( subcommand, name = "gspread" ) ] + GSpread( gspread::Command ), + } + +} + +crate::mod_interface! +{ + layer gspread; + layer gspread_header; + layer gspread_rows; + layer gspread_cell; + layer gspread_cells; + + own use + { + Cli, + CliCommand, + }; +} + diff --git a/module/move/gspread/src/commands/gspread.rs b/module/move/gspread/src/commands/gspread.rs new file mode 100644 index 0000000000..7150856df1 --- /dev/null +++ b/module/move/gspread/src/commands/gspread.rs @@ -0,0 +1,123 @@ +//! +//! Collection of Google Sheets API commands. +//! + + +mod private +{ + + use clap::{ Subcommand, Parser }; + + use crate::*; + use client::SheetsType; + + use commands:: + { + gspread_header, + gspread_rows, + gspread_cell, + gspread_cells + }; + + #[ derive( Debug, Parser ) ] + pub struct CommonArgs + { + #[ arg( long, help = "Full URL of Google Sheet.\n\ + It has to be inside of '' to avoid parse errors.\n\ + Example: 'https://docs.google.com/spreadsheets/d/your_spreadsheet_id/edit?gid=0#gid=0'" ) ] + pub url : String, + + #[ arg( long, help = "Sheet name.\nExample: Sheet1" ) ] + pub tab : String + } + + #[ derive( Debug, Subcommand ) ] + pub enum Command + { + + /// Command to get header of a sheet. Header is a first raw. + /// + /// Command example: + /// + /// gspread header + /// --url 'https://docs.google.com/spreadsheets/d/1EAEdegMpitv-sTuxt8mV8xQxzJE7h_J0MxQoyLH7xxU/edit?gid=0#gid=0' + /// --tab tab1 + #[ command ( name = "header" ) ] + Header + ( + CommonArgs + ), + + /// Command to get all raws of a sheet but not header. + /// + /// Command example: + /// + /// gspread rows + /// --url 'https://docs.google.com/spreadsheets/d/1EAEdegMpitv-sTuxt8mV8xQxzJE7h_J0MxQoyLH7xxU/edit?gid=0#gid=0' + /// --tab tab1 + #[ command( name = "rows" ) ] + Rows + ( + CommonArgs + ), + + /// Command to get or update a cell from a sheet. + #[ command ( subcommand, name = "cell" ) ] + Cell + ( + gspread_cell::Commands + ), + + /// Commands to set a new value to a cell or get a value from a cell. + #[ command ( subcommand, name = "cells" ) ] + Cells + ( + gspread_cells::Commands + ) + + } + + pub async fn command + ( + hub : &SheetsType, + command : Command, + ) + { + match command + { + + Command::Header( header_command ) => + { + gspread_header::command( hub, header_command ).await; + }, + + Command::Rows( rows_command ) => + { + gspread_rows::command( hub, rows_command ).await; + }, + + Command::Cell( cell_command ) => + { + gspread_cell::command( hub, cell_command ).await; + }, + + Command::Cells( cells_command) => + { + // hub + gspread_cells::command( cells_command ).await; + }, + + } + } + +} + +crate::mod_interface! +{ + own use + { + CommonArgs, + Command, + command, + }; +} \ No newline at end of file diff --git a/module/move/gspread/src/commands/gspread_cell.rs b/module/move/gspread/src/commands/gspread_cell.rs new file mode 100644 index 0000000000..a0fd55f361 --- /dev/null +++ b/module/move/gspread/src/commands/gspread_cell.rs @@ -0,0 +1,145 @@ +//! +//! Collection of subcommands fo command "cell" +//! + +mod private +{ + + use clap::Subcommand; + + use crate::*; + use actions; + use actions::gspread::get_spreadsheet_id_from_url; + use client::SheetsType; + + #[ derive( Debug, Subcommand ) ] + pub enum Commands + { + /// Command to get a value from a sheet's cell + /// + /// Command example: + /// + /// gspread cell get + /// --url 'https://docs.google.com/spreadsheets/d/1EAEdegMpitv-sTuxt8mV8xQxzJE7h_J0MxQoyLH7xxU/edit?gid=0#gid=0' + /// --tab tab1 + /// --cell A1 + #[ command( name = "get" ) ] + Get + { + #[ arg( long, help = "Full URL of Google Sheet.\n\ + It has to be inside of '' to avoid parse errors.\n\ + Example: 'https://docs.google.com/spreadsheets/d/your_spreadsheet_id/edit?gid=0#gid=0'" ) ] + url : String, + + #[ arg( long, help = "Sheet name.\nExample: Sheet1" ) ] + tab : String, + + #[ arg( long, help = "Cell id. You can set it in format:\n \ + - A1, where A is column name and 1 is row number\n\ + Example: --cell A4" ) ] + cell : String, + }, + + /// Command to set a new value to a sheet's cell. + /// + /// Command example: + /// + /// gspread cell set + /// --url 'https://docs.google.com/spreadsheets/d/1EAEdegMpitv-sTuxt8mV8xQxzJE7h_J0MxQoyLH7xxU/edit?gid=0#gid=0' + /// --tab tab1 + /// --cell A1 + /// --val 13 + #[ command( name = "set" ) ] + Set + { + #[ arg( long, help = "Full URL of Google Sheet.\n\ + It has to be inside of '' to avoid parse errors.\n\ + Example: 'https://docs.google.com/spreadsheets/d/your_spreadsheet_id/edit?gid=0#gid=0'" ) ] + url : String, + + #[ arg( long, help = "Sheet name.\nExample: Sheet1" ) ] + tab : String, + + #[ arg( long, help = "Cell id. You can set it in format:\n \ + - A1, where A is column name and 1 is row number\n\ + Example: --cell A4" ) ] + cell : String, + + #[ arg( long, help = "Value you want to set. It can be written on any language.\nExample: --val hello" ) ] + val : String + } + } + + pub async fn command + ( + hub : &SheetsType, + commands : Commands + ) + { + match commands + { + Commands::Get { url, tab, cell } => + { + let spreadsheet_id = match get_spreadsheet_id_from_url( url.as_str() ) + { + Ok( id ) => id, + Err( error ) => + { + eprintln!( "Error extracting spreadsheet ID: {}", error ); + return; + } + }; + + match actions::gspread_cell_get::action + ( + hub, + spreadsheet_id, + tab.as_str(), + cell.as_str() + ) + .await + { + Ok( value ) => println!( "Value: {}", value ), + Err( error ) => println!( "Error:\n{}", error ), + } + }, + + Commands::Set { url, tab, cell, val } => + { + let spreadsheet_id = match get_spreadsheet_id_from_url( url.as_str() ) + { + Ok( id ) => id, + Err( error ) => + { + eprintln!( "Error extracting spreadsheet ID: {}", error ); + return; + } + }; + + match actions::gspread_cell_set::action + ( + hub, + spreadsheet_id, + tab.as_str(), + cell.as_str(), + val.as_str() + ) + .await + { + Ok( number ) => println!( "You successfully update {} cell!", number ), + Err( error ) => println!( "Error:\n{}", error ), + } + } + + } + } +} + +crate::mod_interface! +{ + own use + { + command, + Commands, + }; +} \ No newline at end of file diff --git a/module/move/gspread/src/commands/gspread_cells.rs b/module/move/gspread/src/commands/gspread_cells.rs new file mode 100644 index 0000000000..dd53d80d10 --- /dev/null +++ b/module/move/gspread/src/commands/gspread_cells.rs @@ -0,0 +1,99 @@ +//! +//! Cells commands. +//! set command -> set specified values in specified columns in specified row. +//! + +mod private +{ + use clap::Subcommand; + + use crate::*; + use actions::gspread::get_spreadsheet_id_from_url; + + #[ derive( Debug, Subcommand ) ] + pub enum Commands + { + /// Command to set values range to a google sheet + /// + /// Command example: + /// + /// gspread cells set + /// --url 'https://docs.google.com/spreadsheets/d/1EAEdegMpitv-sTuxt8mV8xQxzJE7h_J0MxQoyLH7xxU/edit?gid=0#gid=0' + /// --tab tab1 + /// --select-row-by-key "id" + /// --json '{"id": "2", "A": "1", "B": "2"}' + #[ command( name = "set" ) ] + Set + { + #[ arg( long, help = "Identifier of a row. Available identifiers: id (row's unique identifier).\n\ + Example: --select_row_by_key \"id\"" ) ] + select_row_by_key : String, + + #[ arg( long, help = "Value range. It must contain select_row_by_key. + The key is a column name (not a header name, but a column name, which can only contain Latin letters). + Every key and value must be a string. + Depending on the shell, different handling might be required.\n\ + Examples:\n\ + 1. --json '{\"id\": \"3\", \"A\": \"1\", \"B\": \"2\"}'\n\ + 2. --json \"{\"id\": \"3\", \"A\": \"1\", \"B\": \"2\"}\"\n\ + 3. --json '{\\\"id\\\": \\\"3\\\", \\\"A\\\": \\\"1\\\", \\\"B\\\": \\\"2\\\"}'\n\ + 4. --json \"{\\\"id\\\": \\\"3\\\", \\\"A\\\": \\\"1\\\", \\\"B\\\": \\\"2\\\"}\" " ) ] + json : String, + + #[ arg( long, help = "Full URL of Google Sheet.\n\ + It has to be inside of '' to avoid parse errors.\n\ + Example: 'https://docs.google.com/spreadsheets/d/your_spreadsheet_id/edit?gid=0#gid=0'" ) ] + url : String, + + #[ arg( long, help = "Sheet name.\nExample: Sheet1" ) ] + tab : String + } + + } + + pub async fn command + ( + // hub : &SheetsType, + commands : Commands + ) + { + match commands + { + Commands::Set { select_row_by_key, json, url, tab } => + { + let spreadsheet_id = match get_spreadsheet_id_from_url( url.as_str() ) + { + Ok( id ) => id, + Err( error ) => + { + eprintln!( "Error extracting spreadsheet ID: {}", error ); + return; + } + }; + + match actions::gspread_cells_set::action + ( + // &hub, + select_row_by_key.as_str(), + json.as_str(), + spreadsheet_id, + tab.as_str() + ) + .await + { + Ok( val ) => println!( "{} cells were sucsessfully updated!", val ), + Err( error ) => println!( "Error:\n{}", error ) + } + } + } + } +} + +crate::mod_interface! +{ + own use + { + command, + Commands + }; +} \ No newline at end of file diff --git a/module/move/gspread/src/commands/gspread_header.rs b/module/move/gspread/src/commands/gspread_header.rs new file mode 100644 index 0000000000..6ee00db284 --- /dev/null +++ b/module/move/gspread/src/commands/gspread_header.rs @@ -0,0 +1,85 @@ +//! +//! Command "header" +//! + +mod private +{ + use std::fmt; + use crate::*; + use commands::gspread::CommonArgs; + use client::SheetsType; + use actions; + use actions::gspread::get_spreadsheet_id_from_url; + use format_tools::AsTable; + use util::display_table::display_header; + + #[ derive( Debug ) ] + pub struct Report + { + pub rows : Vec< RowWrapper > + } + + impl fmt::Display for Report + { + fn fmt + ( + &self, + f : &mut fmt::Formatter + ) -> fmt::Result + { + display_header( &AsTable::new( &self.rows ), f ) + } + } + + pub async fn command + ( + hub : &SheetsType, + args : CommonArgs, + ) + { + match args + { + CommonArgs { url, tab } => + { + let spreadsheet_id = match get_spreadsheet_id_from_url( url.as_str() ) + { + Ok( id ) => id, + Err( error ) => + { + eprintln!( "Error extracting spreadsheet ID: {}", error ); + return; + } + }; + + match actions::gspread_get_header::action + ( + hub, + spreadsheet_id, + tab.as_str() + ) + .await + { + Ok( header ) => + { + let header_wrapped = header + .into_iter() + .map( | row | RowWrapper{ max_len: row.len(), row } ) + .collect(); + + println!( "Header:\n{}", Report{ rows: header_wrapped } ); + } + Err( error ) => eprintln!( "Error:\n{}", error ), + } + } + } + } +} + +crate::mod_interface! +{ + own use + { + command + }; +} + diff --git a/module/move/gspread/src/commands/gspread_rows.rs b/module/move/gspread/src/commands/gspread_rows.rs new file mode 100644 index 0000000000..6c526d0f78 --- /dev/null +++ b/module/move/gspread/src/commands/gspread_rows.rs @@ -0,0 +1,84 @@ +//! +//! Command "rows" +//! + +mod private +{ + use std::fmt; + use crate::*; + use commands::gspread::CommonArgs; + use client::SheetsType; + use actions; + use actions::gspread::get_spreadsheet_id_from_url; + use format_tools::AsTable; + use util::display_table::display_rows; + + pub struct Report + { + pub rows : Vec< RowWrapper > + } + + impl fmt::Display for Report + { + fn fmt + ( + &self, + f : &mut fmt::Formatter + ) -> fmt::Result + { + display_rows( &AsTable::new( &self.rows ), f ) + } + } + + pub async fn command + ( + hub : &SheetsType, + args : CommonArgs + ) + { + match args + { + CommonArgs { url, tab } => + { + let spreadsheet_id = match get_spreadsheet_id_from_url( url.as_str() ) + { + Ok( id ) => id, + Err( error ) => + { + eprintln!( "Error extracting spreadsheet ID: {}", error ); + return; + } + }; + + match actions::gspread_get_rows::action + ( + hub, + spreadsheet_id, + tab.as_str() + ) + .await + { + Ok( rows ) => + { + let max_len = rows.iter().map(|row| row.len()).max().unwrap_or(0); + let rows_wrapped: Vec = rows + .into_iter() + .map(|row| RowWrapper { row, max_len }) + .collect(); + + println!( "Rows:\n{}", Report{ rows: rows_wrapped } ); + } + Err( error ) => eprintln!( "Error:\n{}", error ), + } + } + } + } +} + +crate::mod_interface! +{ + own use + { + command + }; +} diff --git a/module/move/gspread/src/debug.rs b/module/move/gspread/src/debug.rs new file mode 100644 index 0000000000..7f1d303941 --- /dev/null +++ b/module/move/gspread/src/debug.rs @@ -0,0 +1,23 @@ +mod private +{ +} + +use format_tools:: +{ + Fields, + TableWithFields, +}; +use std::borrow::Cow; + +pub mod row_wrapper; + +crate::mod_interface! +{ + exposed use + { + row_wrapper:: + { + RowWrapper + } + }; +} diff --git a/module/move/gspread/src/debug/row_wrapper.rs b/module/move/gspread/src/debug/row_wrapper.rs new file mode 100644 index 0000000000..7802773c47 --- /dev/null +++ b/module/move/gspread/src/debug/row_wrapper.rs @@ -0,0 +1,62 @@ +//! +//! Gspread wrapper for outputting data to console +//! +//! It is used for "header" and "rows" commands +//! +use super::*; +use crate::*; +use ser::JsonValue; + + +#[ derive( Debug ) ] +pub struct RowWrapper +{ + pub row: Vec< JsonValue >, + pub max_len: usize +} +impl Clone for RowWrapper +{ + fn clone( &self ) -> Self + { + Self + { + row: self.row.clone(), + max_len: self.max_len.clone() + } + } +} +impl TableWithFields for RowWrapper {} +impl Fields< &'_ str, Option< Cow< '_, str > > > +for RowWrapper +{ + type Key< 'k > = &'k str; + type Val< 'v > = Option< Cow< 'v, str > >; + fn fields( &self ) -> impl IteratorTrait< Item= ( &'_ str, Option > ) > + { + let mut dst = Vec::new(); + + for ( index, value ) in self.row.iter().enumerate() + { + let column_name = format!( "{} ", index ); + let title = Box::leak( column_name.into_boxed_str() ) as &str; + let cleaned: String = value + .to_string() + .chars() + .skip( 1 ) + .take( value.to_string().chars().count() - 2 ) + .collect(); + + dst.push( ( title, Some( Cow::Owned( cleaned ) ) ) ) + } + + //adding empty values for missing cells + for index in self.row.len()..self.max_len + { + let column_name = format!( "Column{}", index ); + let column_name = format!( "{}", index ); + let title = Box::leak( column_name.into_boxed_str() ) as &str; + dst.push( ( title, Some( Cow::Owned( "".to_string() ) ) ) ); + } + dst.into_iter() + } +} \ No newline at end of file diff --git a/module/move/gspread/src/lib.rs b/module/move/gspread/src/lib.rs new file mode 100644 index 0000000000..c0d2432985 --- /dev/null +++ b/module/move/gspread/src/lib.rs @@ -0,0 +1,41 @@ +use mod_interface::mod_interface; +use error_tools::thiserror; + +mod private +{ +} + +pub mod ser +{ + pub use serde:: + { + Serialize, + Deserialize, + }; + pub use serde_json:: + { + value::{ Value as JsonValue, Number as JsonNumber }, + error::Error, + self + }; + pub use serde_with::*; +} + +crate::mod_interface! +{ + + layer client; + layer debug; + layer commands; + layer actions; + layer secret; + layer util; + + exposed use ::reflect_tools:: + { + Fields, + _IteratorTrait, + IteratorTrait, + }; + +} \ No newline at end of file diff --git a/module/move/gspread/src/secret.rs b/module/move/gspread/src/secret.rs new file mode 100644 index 0000000000..48567b77f4 --- /dev/null +++ b/module/move/gspread/src/secret.rs @@ -0,0 +1,159 @@ +//! +//! Tool's secret +//! + +mod private +{ + use crate::*; + use std:: + { + env, + sync::OnceLock, + }; + + use error_tools::typed::Error; + use ser::DisplayFromStr; + + #[ ser::serde_as ] + #[ derive( Debug, Error, ser::Serialize ) ] + #[ serde( tag = "type", content = "data" ) ] + pub enum Error + { + #[ error( "Secret file is illformed\n{0}" ) ] + SecretFileIllformed + ( + #[ from ] + #[ serde_as( as = "DisplayFromStr" ) ] + dotenv::Error + ), + + #[ error( "Secret missing the variable {0}" ) ] + VariableMissing( &'static str ), + + #[ error( "Secret error processing in the variable {0}\n{1}" ) ] + VariableIllformed( &'static str, String ), + + } + + pub type Result< R > = std::result::Result< R, Error >; + + #[ derive( Debug ) ] + #[ allow( non_snake_case ) ] + pub struct Secret + { + pub CLIENT_SECRET : String, + pub CLIENT_ID: String, + pub AUTH_URI : String, + pub TOKEN_URI : String, + } + + impl Secret + { + #[ allow( non_snake_case ) ] + pub fn load() -> Result< Self > + { + let path = "./.secret/.env"; + + let r = dotenv::from_path( path ); + if let Err( ref err ) = r + { + if !matches!( err, dotenv::Error::Io(_) ) + { + return Err( r.expect_err( &format!( "Failed to load {path}" ) ).into() ); + } + } + + let config = Self + { + CLIENT_SECRET : var( "CLIENT_SECRET", None )?, + CLIENT_ID : var( "CLIENT_ID", None )?, + AUTH_URI : var ( "AUTH_URI", Some( "https://accounts.google.com/o/oauth2/auth" ) )?, + TOKEN_URI : var ( "TOKEN_URI", Some( "https://oauth2.googleapis.com/token" ) )? + }; + Ok( config ) + } + + pub fn read() -> Secret + { + Self::load().unwrap_or_else( | err | + { + let example = include_str!("../.secret/readme.md"); + let explanation = format! + ( + r#" = Lack of secrets + +Failed to load secret or some its parameters. +{err} + + = Fix + +Add missing secret to .env file in .secret directory. Example: MISSING_SECRET=YOUR_MISSING_SECRET + + = More information + +{example} +"# + ); + panic!( "{}", explanation ); + }) + } + + pub fn get() -> &'static Secret + { + static INSTANCE : OnceLock< Secret > = OnceLock::new(); + INSTANCE.get_or_init( || Self::read() ) + } + + } + + fn var + ( + name : &'static str, + default : Option< &'static str >, + ) -> Result < String > + { + match env::var( name ) + { + Ok( val ) => Ok ( val ), + Err( _ ) => + { + if let Some( default_value ) = default + { + Ok( default_value.to_string() ) + } + else + { + Err ( Error::VariableMissing( name ) ) + } + } + } + } + + fn _var_path + ( + name : &'static str, + default : Option<&'static str>, + ) -> Result < pth::AbsolutePath > + { + let p = var( name, default )?; + pth::AbsolutePath::from_paths( ( pth::CurrentPath, p ) ) + .map_err( |e| Error::VariableIllformed( name, e.to_string() ) ) + } + +} + +crate::mod_interface! +{ + + own use + { + Error, + Result, + }; + + orphan use + { + Secret, + }; + +} \ No newline at end of file diff --git a/module/move/gspread/src/util.rs b/module/move/gspread/src/util.rs new file mode 100644 index 0000000000..ac76ad86b2 --- /dev/null +++ b/module/move/gspread/src/util.rs @@ -0,0 +1,6 @@ +mod private {} + +crate::mod_interface! +{ + layer display_table; +} \ No newline at end of file diff --git a/module/move/gspread/src/util/display_table.rs b/module/move/gspread/src/util/display_table.rs new file mode 100644 index 0000000000..3d96964d9b --- /dev/null +++ b/module/move/gspread/src/util/display_table.rs @@ -0,0 +1,55 @@ + + +mod private +{ + + use std::fmt; + + use format_tools:: + { + TableFormatter, + print, + output_format, + TableOutputFormat + }; + + pub fn display_rows< 'a > + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ > + ) -> fmt::Result + { + display_data( data, f, output_format::Table::default() ) + } + + pub fn display_header < 'a > + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ > + ) -> fmt::Result + { + display_data( data, f, output_format::Table::default() ) + } + + pub fn display_data < 'a > + ( + data : &'a impl TableFormatter< 'a >, + f : &mut fmt::Formatter< '_ >, + format : impl TableOutputFormat, + ) -> fmt::Result + { + let printer = print::Printer::with_format( &format ); + let mut context = print::Context::new( f, printer ); + TableFormatter::fmt( data, &mut context ) + } + +} + +crate::mod_interface! +{ + own use + { + display_rows, + display_header + }; +} \ No newline at end of file diff --git a/module/move/gspread/tests/inc/cell_tests.rs b/module/move/gspread/tests/inc/cell_tests.rs new file mode 100644 index 0000000000..f93ec7b1a4 --- /dev/null +++ b/module/move/gspread/tests/inc/cell_tests.rs @@ -0,0 +1,99 @@ +#[ allow( unused_imports ) ] +use super::*; + +use the_module:: +{ + hub, + Secret, + actions, + SheetsType, + ser::JsonValue +}; + +async fn setup() -> ( SheetsType, &'static str, &'static str ) +{ + let secret = Secret::load().expect( "Failed to load secret" ); + let hub = hub( &secret ).await.expect( "Failed to create a hub" ); + let spreadsheet_id = "1EAEdegMpitv-sTuxt8mV8xQxzJE7h_J0MxQoyLH7xxU"; + let table_name = "tab5"; + + ( hub, spreadsheet_id, table_name ) +} + +#[ tokio::test ] +async fn test_get_cell() +{ + let ( hub, spreadsheet_id, table_name ) = setup().await; + let cell_id = "R2C1"; + + let result = actions::gspread_cell_get::action + ( + &hub, + spreadsheet_id, + table_name, + cell_id + ) + .await + .expect( "Error getting cell" ); + + assert_eq!( result, "Vsevolod" ) +} + +#[ tokio::test ] +async fn test_get_cell_empty() +{ + let ( hub, spreadsheet_id, table_name ) = setup().await; + let cell_id = "R4C1"; + + let result = actions::gspread_cell_get::action + ( + &hub, + spreadsheet_id, + table_name, + cell_id + ) + .await + .expect( "Error getting cell" ); + + assert_eq!( result, JsonValue::Null ) +} + +#[ tokio::test ] +async fn test_set_cell() +{ + let ( hub, spreadsheet_id, table_name ) = setup().await; + let cell_id = "R2C1"; + let value = "Seva"; + + let result = actions::gspread_cell_set::action + ( + &hub, + spreadsheet_id, + table_name, + cell_id, + value + ) + .await; + + assert!( result.is_ok() ); +} + +#[ tokio::test ] +async fn test_set_empty_cell() +{ + let ( hub, spreadsheet_id, table_name ) = setup().await; + let cell_id = "R4C1"; + let value = "Stanislav"; + + let result = actions::gspread_cell_set::action + ( + &hub, + spreadsheet_id, + table_name, + cell_id, + value + ) + .await; + + assert!( result.is_ok() ); +} \ No newline at end of file diff --git a/module/move/gspread/tests/inc/cells_tests.rs b/module/move/gspread/tests/inc/cells_tests.rs new file mode 100644 index 0000000000..4c91a9a19c --- /dev/null +++ b/module/move/gspread/tests/inc/cells_tests.rs @@ -0,0 +1,79 @@ +#[ allow( unused_imports ) ] +use super::*; + +use the_module:: +{ + hub, + Secret, + actions, + SheetsType, +}; + +async fn setup() -> ( SheetsType, &'static str, &'static str, &'static str ) +{ + let secret = Secret::load().expect( "Failed to load secret" ); + let hub = hub( &secret ).await.expect( "Failed to create a hub" ); + let select_row_by_key = "id"; + let spreadsheet_id = "1EAEdegMpitv-sTuxt8mV8xQxzJE7h_J0MxQoyLH7xxU"; + let table_name = "tab7"; + + ( hub, select_row_by_key, spreadsheet_id, table_name ) +} + +#[ tokio::test ] +async fn test_set_cells() +{ + let + ( + hub, + select_row_by_key, + spreadsheet_id, + table_name + ) = setup().await; + + let json = r#"{ "id": "2", "A": "new_val1", "B": "new_val2"}"#; + + let result = actions::gspread_cells_set::action + ( + &hub, + select_row_by_key, + json, + spreadsheet_id, + table_name, + ) + .await + .expect( "Error while updating" ); + + assert_eq!( result, "Cells were sucsessfully updated!" ) +} + +#[ tokio::test ] +async fn test_set_cells_wrong_row() +{ + let + ( + hub, + select_row_by_key, + spreadsheet_id, + table_name + ) = setup().await; + + let json = r#"{ "id": "a", "A": "new_val1", "B": "new_val2"}"#; + + let result = actions::gspread_cells_set::action + ( + &hub, + select_row_by_key, + json, + spreadsheet_id, + table_name, + ) + .await + .expect( "Error while updating" ); + + assert_eq! + ( + result, + r#"Bad Request: {"error":{"code":400,"message":"Invalid data[0]: Unable to parse range: tab7!Aa","status":"INVALID_ARGUMENT"}}"# + ) +} \ No newline at end of file diff --git a/module/move/gspread/tests/inc/header_tests.rs b/module/move/gspread/tests/inc/header_tests.rs new file mode 100644 index 0000000000..046d8e1d69 --- /dev/null +++ b/module/move/gspread/tests/inc/header_tests.rs @@ -0,0 +1,91 @@ +#[ allow( unused_imports ) ] +use super::*; + +use the_module:: +{ + hub, + Secret, + actions, + SheetsType +}; + +async fn setup() -> ( SheetsType, &'static str ) +{ + let secret = Secret::load().expect( "Failed to load secret" ); + let hub = hub( &secret ).await.expect( "Failed to create a hub" ); + let spreadsheet_id = "1EAEdegMpitv-sTuxt8mV8xQxzJE7h_J0MxQoyLH7xxU"; + + ( hub, spreadsheet_id ) +} + +#[ tokio::test ] +async fn test_get_header() +{ + let ( hub, spreadsheet_id ) = setup().await; + let table_name = "tab1"; + + let result = actions::gspread_get_header::action + ( + &hub, + spreadsheet_id, + table_name + ) + .await + .expect( "Error getting header" ); + + assert_eq!( result, vec![ vec![ "Name", "Surname", "Age" ] ] ); +} + +#[ tokio::test ] +async fn test_get_header_with_spaces() +{ + let ( hub, spreadsheet_id ) = setup().await; + let table_name = "tab2"; + + let result = actions::gspread_get_header::action + ( + &hub, + spreadsheet_id, + table_name + ) + .await + .expect( "Error getting header" ); + + assert_eq!( result, vec![ vec![ "Name", "", "Age" ] ] ); +} + +#[ tokio::test ] +async fn test_get_header_empty() +{ + let ( hub, spreadsheet_id ) = setup().await; + let table_name = "tab3"; + + let result = actions::gspread_get_header::action + ( + &hub, + spreadsheet_id, + table_name + ) + .await + .expect( "Error getting header" ); + + assert_eq!( result, Vec::< Vec< String > >::new() ); +} + +#[ tokio::test ] +async fn test_get_header_with_empty_end() +{ + let ( hub, spreadsheet_id ) = setup().await; + let table_name = "tab4"; + + let result = actions::gspread_get_header::action + ( + &hub, + spreadsheet_id, + table_name + ) + .await + .expect( "Error getting header" ); + + assert_eq!( result, vec![ vec![ "Name", "Surname" ] ] ); +} \ No newline at end of file diff --git a/module/move/gspread/tests/inc/mod.rs b/module/move/gspread/tests/inc/mod.rs new file mode 100644 index 0000000000..a357c3fe4a --- /dev/null +++ b/module/move/gspread/tests/inc/mod.rs @@ -0,0 +1,14 @@ +//! +//! Here is used the +//! https://docs.google.com/spreadsheets/d/1EAEdegMpitv-sTuxt8mV8xQxzJE7h_J0MxQoyLH7xxU/edit?gid=0#gid=0 +//! test spreadsheet +//! + + +#[ allow( unused_imports ) ] +use super::*; + +mod header_tests; +mod rows_tests; +mod cell_tests; +mod cells_tests; \ No newline at end of file diff --git a/module/move/gspread/tests/inc/rows_tests.rs b/module/move/gspread/tests/inc/rows_tests.rs new file mode 100644 index 0000000000..d9032f8544 --- /dev/null +++ b/module/move/gspread/tests/inc/rows_tests.rs @@ -0,0 +1,93 @@ +#[ allow( unused_imports ) ] +use super::*; + +use the_module:: +{ + hub, + Secret, + actions, + SheetsType +}; + +async fn setup() -> ( SheetsType, &'static str ) +{ + let secret = Secret::load().expect( "Failed to load secret" ); + let hub = hub( &secret ).await.expect( "Failed to create a hub" ); + let spreadsheet_id = "1EAEdegMpitv-sTuxt8mV8xQxzJE7h_J0MxQoyLH7xxU"; + + ( hub, spreadsheet_id ) +} + +#[ tokio::test ] +async fn test_get_rows() +{ + let ( hub, spreadsheet_id ) = setup().await; + let table_name = "tab1"; + + let result = actions::gspread_get_rows::action + ( + &hub, + spreadsheet_id, + table_name + ) + .await + .expect( "Error getting rows" ); + + assert_eq! + ( + result, + vec![ + vec![ "Vsevolod", "Bakutov", "20" ], + vec![ "Victor", "Ovsyanik", "85" ], + vec![ "Olexandr", "Optimus", "28" ], + vec![ "Ivan", "Optimus", "34" ], + vec![ "Bogdan", "Optimus", "28" ], + ] + ) +} + +#[ tokio::test ] +async fn test_get_rows_with_spaces() +{ + let ( hub, spreadsheet_id ) = setup().await; + let table_name = "tab2"; + + let result = actions::gspread_get_rows::action + ( + &hub, + spreadsheet_id, + table_name + ) + .await + .expect( "Error getting rows" ); + + assert_eq! + ( + result, + vec![ + vec![ "Vsevolod", "Bakutov" ], + vec![ "Victor", "", "85" ], + vec![ "", "Optimus", "28" ], + vec![ ], + vec![ "Bogdan", "Optimus", "28" ], + ] + ) +} + +#[ tokio::test ] +async fn test_get_rows_empty() +{ + let ( hub, spreadsheet_id ) = setup().await; + let table_name = "tab3"; + + let result = actions::gspread_get_rows::action + ( + &hub, + spreadsheet_id, + table_name + ) + .await + .expect( "Error getting rows" ); + + assert_eq!( result, Vec::< Vec< String > >::new() ) +} \ No newline at end of file diff --git a/module/move/gspread/tests/mock/cell_tests.rs b/module/move/gspread/tests/mock/cell_tests.rs new file mode 100644 index 0000000000..488eb60d02 --- /dev/null +++ b/module/move/gspread/tests/mock/cell_tests.rs @@ -0,0 +1,93 @@ +//! +//! Get and set cell tests. +//! In these examples: +//! - url is /v4/spreadsheets/{spreadsheet_id}}/values/{range} +//! - everything is fake: spreadsheet_id, sheet's name, range and response json +//! + +use httpmock::prelude::*; +use reqwest; + +#[ tokio::test ] +async fn test_get_cell_with_mock() +{ + let server = MockServer::start(); + let body = r#"{ "A2": "Steeve" }"#; + let mock = server.mock( | when, then | { + when.method( GET ) + .path( "/v4/spreadsheets/12345/values/tab2!R2C1" ); + then.status( 200 ) + .header( "Content-Type", "application/json" ) + .body( body ); + } ); + + let response = reqwest::get + ( + server.url + ( + "/v4/spreadsheets/12345/values/tab2!R2C1" + ) + ) + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 200 ); +} + +#[ tokio::test ] +async fn test_get_cell_empty_with_mock() +{ + let server = MockServer::start(); + let mock = server.mock( | when, then | { + when.method( GET ) + .path( "/v4/spreadsheets/12345/values/tab2!R2C1" ); + then.status( 200 ) + .header( "Content-Type", "application/json" ) + .body( r#"{}"# ); + } ); + + let response = reqwest::get + ( + server.url + ( + "/v4/spreadsheets/12345/values/tab2!R2C1" + ) + ) + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 200 ); +} + +#[ tokio::test ] +async fn test_set_cell_with_mock() +{ + let server = MockServer::start(); + let body = r#"A2": "Some value"#; + let mock = server.mock( | when, then | { + when.method( POST ) + .path( "/v4/spreadsheets/12345/values/tab2!R2C1" ) + .header("content-type", "application/json") + .body( body ); + // returns amount of updated cells + then.status( 201 ) + .header( "Content-Type", "application/json" ) + .body( "1" ); + } ); + + let response = reqwest::Client::new() + .post( server.url( "/v4/spreadsheets/12345/values/tab2!R2C1" ) ) + .header( "Content-Type", "application/json" ) + .body( body ) + .send() + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 201 ); +} \ No newline at end of file diff --git a/module/move/gspread/tests/mock/cells_tests.rs b/module/move/gspread/tests/mock/cells_tests.rs new file mode 100644 index 0000000000..b03b78fd71 --- /dev/null +++ b/module/move/gspread/tests/mock/cells_tests.rs @@ -0,0 +1,67 @@ +//! +//! Set cells tests. +//! In these examples: +//! - url is /v4/spreadsheets/{spreadsheet_id}}/values/{range} +//! - everything is fake: spreadsheet_id, sheet's name, range and response json +//! + +use httpmock::prelude::*; +use reqwest; + +#[ tokio::test ] +async fn test_set_cells_with_mock() +{ + let server = MockServer::start(); + let body = r#"{ "id": "2", "A": "new_val1", "B": "new_val2"}"#; + let mock = server.mock( | when, then | { + when.method( POST ) + .path( "/v4/spreadsheets/12345/values/tab3!A2:B2" ) + .header( "Content-Type", "application/json" ) + .body( body ); + // returns amount of updated cells + then.status( 201 ) + .header( "Content-Type", "application/json" ) + .body( "2" ); + } ); + + let response = reqwest::Client::new() + .post( server.url( "/v4/spreadsheets/12345/values/tab3!A2:B2" ) ) + .header( "Content-Type", "application/json" ) + .body( body ) + .send() + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 201 ); +} + +#[ tokio::test ] +async fn test_set_cells_wrong_row_with_mock() +{ + let server = MockServer::start(); + let body = r#"{ "id": "a", "A": "new_val1", "B": "new_val2"}"#; + let response_body = r#"{"error":{"code":400,"message":"Invalid data[0]: Unable to parse range: tab3!Aa","status":"INVALID_ARGUMENT"}}"#; + let mock = server.mock( | when, then | { + when.method( POST ) + .path( "/v4/spreadsheets/12345/values/tab3!Aa:Ba" ) + .header( "Content-Type", "application/json" ) + .body( body ); + then.status( 400 ) + .header( "Content-Type", "application/json" ) + .body( response_body ); + } ); + + let response = reqwest::Client::new() + .post( server.url( "/v4/spreadsheets/12345/values/tab3!Aa:Ba" ) ) + .header( "Content-Type", "application/json" ) + .body( body ) + .send() + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 400 ); +} \ No newline at end of file diff --git a/module/move/gspread/tests/mock/header_tests.rs b/module/move/gspread/tests/mock/header_tests.rs new file mode 100644 index 0000000000..5927b1a8a6 --- /dev/null +++ b/module/move/gspread/tests/mock/header_tests.rs @@ -0,0 +1,123 @@ +//! +//! Get header tests. +//! In these examples: +//! - url is /v4/spreadsheets/{spreadsheet_id}}/values/{range} +//! - everything is fake: spreadsheet_id, sheet's name, range and response json +//! + +use httpmock::prelude::*; +use reqwest; + + +#[ tokio::test ] +async fn test_get_header() +{ + let server = MockServer::start(); + let body = r#"{ "A1": "Name", "B1": "Surname", "C1": "Age" }"#; + let mock = server.mock( | when, then | { + when.method( GET ) + .path( "/v4/spreadsheets/12345/values/tab1!A1:Z1" ); + then.status( 200 ) + .header("Content-Type", "application/json" ) + .body( body ); + } ); + + let response = reqwest::get + ( + server.url + ( + "/v4/spreadsheets/12345/values/tab1!A1:Z1" + ) + ) + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 200 ) + +} + +#[ tokio::test ] +async fn test_get_header_with_spaces_with_mock() +{ + let server = MockServer::start(); + let body = r#"{ "A1": "Name", "B1": "", "C1": "Age" }"#; + let mock = server.mock( | when, then | { + when.method( GET ) + .path( "/v4/spreadsheets/12345/values/tab1!A1:Z1" ); + then.status( 200 ) + .header("Content-Type", "application/json" ) + .body( body ); + } ); + + let response = reqwest::get + ( + server.url + ( + "/v4/spreadsheets/12345/values/tab1!A1:Z1" + ) + ) + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 200 ) +} + +#[ tokio::test ] +async fn test_get_header_empty_with_mock() +{ + let server = MockServer::start(); + + let mock = server.mock( | when, then | { + when.method( GET ) + .path( "/v4/spreadsheets/12345/values/tab1!A1:Z1" ); + then.status( 200 ) + .header("Content-Type", "application/json" ) + .body( r#"{}"# ); + } ); + + let response = reqwest::get + ( + server.url + ( + "/v4/spreadsheets/12345/values/tab1!A1:Z1" + ) + ) + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 200 ) +} + +#[ tokio::test ] +async fn test_get_header_with_empty_end_with_mock() +{ + let server = MockServer::start(); + let body = r#"{ "A1": "Name", "B1": "Surname" }"#; + let mock = server.mock( | when, then | { + when.method( GET ) + .path( "/v4/spreadsheets/12345/values/tab1!A1:Z1" ); + then.status( 200 ) + .header("Content-Type", "application/json" ) + .body( body ); + } ); + + let response = reqwest::get + ( + server.url + ( + "/v4/spreadsheets/12345/values/tab1!A1:Z1" + ) + ) + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 200 ) +} \ No newline at end of file diff --git a/module/move/gspread/tests/mock/mod.rs b/module/move/gspread/tests/mock/mod.rs new file mode 100644 index 0000000000..1c6c49e281 --- /dev/null +++ b/module/move/gspread/tests/mock/mod.rs @@ -0,0 +1,8 @@ +#[ allow( unused_imports ) ] +use super::*; + +mod oauth_tests; +mod header_tests; +mod cell_tests; +mod cells_tests; +mod rows_tests; \ No newline at end of file diff --git a/module/move/gspread/tests/mock/oauth_tests.rs b/module/move/gspread/tests/mock/oauth_tests.rs new file mode 100644 index 0000000000..a22ef9a792 --- /dev/null +++ b/module/move/gspread/tests/mock/oauth_tests.rs @@ -0,0 +1,102 @@ +//! +//! OAuth2 tests. +//! + +use httpmock::prelude::*; +use reqwest; +use serde_json::json; + +#[ tokio::test ] +async fn oauth2_first_endpoint_with_mock() +{ + let server = MockServer::start(); + let mock = server.mock( | when, then | { + when.method( GET ) + .path( "/o/oauth2/auth" ) + .query_param( "scope", "https://www.googleapis.com/auth/drive.readonly" ) + .query_param( "access_type", "offline" ) + .query_param( "redirect_uri", "http://localhost:44444" ) + .query_param( "response_type", "code" ) + .query_param( "client_id", "YOUR_CLIENT_ID" ); + then.status( 302 ); + }); + + let response = reqwest::get + ( + server.url + ( + "/o/oauth2/auth?\ + scope=https://www.googleapis.com/auth/drive.readonly&\ + access_type=offline&\ + redirect_uri=http://localhost:44444&\ + response_type=code&\ + client_id=YOUR_CLIENT_ID" + ) + ) + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 302 ); +} + + +#[ tokio::test ] +async fn oauth2_second_endpoint_with_mock() +{ + let server = MockServer::start(); + + // url == first endpoint + let mock = server.mock( | when, then | { + when.path( "/o/oauth2/auth" ) + .query_param( "scope", "https://..." ); + then.status( 302 ); + } ); + + // in real program at that point we have to open generated url and give access to our program from browser + let response = reqwest::get( server.url( "/o/oauth2/auth?scope=https://..." ) ).await.unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 302 ); +} + +#[ tokio::test ] +async fn oauth2_third_endpoint_with_mock() +{ + let server = MockServer::start(); + let body = r#"code=AUTHORIZATION_CODE&client_secret=YOUR_CLIENT_SECRET&"#; + let mock = server.mock( | when, then | { + when.method( POST ) + .path( "/token" ) + .header("Content-Type", "application/json" ) + .body( body ); + then.status( 200 ) + .header("Content-Type", "application/json" ) + .json_body + ( + json! + ( + { + "access_token" : "access_token", + "token_type" : "Bearer", + "expires_in" : "3600", + "scope" : "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email openid" + } + ) + ); + }); + + let response = reqwest::Client::new() + .post( server.url( "/token" ) ) + .header( "Content-Type", "application/json" ) + .body( body ) + .send() + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 200 ); +} \ No newline at end of file diff --git a/module/move/gspread/tests/mock/rows_tests.rs b/module/move/gspread/tests/mock/rows_tests.rs new file mode 100644 index 0000000000..05b43663b3 --- /dev/null +++ b/module/move/gspread/tests/mock/rows_tests.rs @@ -0,0 +1,93 @@ +//! +//! Get rows tests. +//! In these examples: +//! - url is /v4/spreadsheets/{spreadsheet_id}}/values/{range} +//! - everything is fake: spreadsheet_id, sheet's name, range and response json +//! + +use httpmock::prelude::*; +use reqwest; + +#[ tokio::test ] +async fn test_get_rows_with_mock() +{ + let server = MockServer::start(); + let body = r#"{"A2" : "Steeve", "B2": "John", "A3": "Seva", "B3": "Oleg" }"#; + let mock = server.mock( | when, then | { + when.method( GET ) + .path( "/v4/spreadsheets/12345/values/A2:B3" ); + then.status( 200 ) + .header( "Content-Type", "application/json" ) + .body( body ); + }); + + let response = reqwest::get + ( + server.url + ( + "/v4/spreadsheets/12345/values/A2:B3" + ) + ) + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 200 ); +} + +#[ tokio::test ] +async fn test_get_rows_with_spaces_with_mock() +{ + let server = MockServer::start(); + let body = r#"{"A2" : "Steeve", "B2": "", "A3": "Seva", "B3": "Oleg" }"#; + let mock = server.mock( | when, then | { + when.method( GET ) + .path( "/v4/spreadsheets/12345/values/A2:B3" ); + then.status( 200 ) + .header( "Content-Type", "application/json" ) + .body( body ); + }); + + let response = reqwest::get + ( + server.url + ( + "/v4/spreadsheets/12345/values/A2:B3" + ) + ) + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 200 ); +} + +#[ tokio::test ] +async fn test_get_rows_empty_with_mock() +{ + let server = MockServer::start(); + let body = r#"{}"#; + let mock = server.mock( | when, then | { + when.method( GET ) + .path( "/v4/spreadsheets/12345/values/A2:B3" ); + then.status( 200 ) + .header( "Content-Type", "application/json" ) + .body( body ); + }); + + let response = reqwest::get + ( + server.url + ( + "/v4/spreadsheets/12345/values/A2:B3" + ) + ) + .await + .unwrap(); + + mock.assert(); + + assert_eq!( response.status(), 200 ); +} \ No newline at end of file diff --git a/module/move/gspread/tests/smoke_test.rs b/module/move/gspread/tests/smoke_test.rs new file mode 100644 index 0000000000..28e533e551 --- /dev/null +++ b/module/move/gspread/tests/smoke_test.rs @@ -0,0 +1,11 @@ +#[ test ] +fn local_smoke_test() +{ + test_tools::smoke_test_for_local_run(); +} + +#[ test ] +fn published_smoke_test() +{ + test_tools::smoke_test_for_published_run(); +} \ No newline at end of file diff --git a/module/move/gspread/tests/tests.rs b/module/move/gspread/tests/tests.rs new file mode 100644 index 0000000000..31c81bb6b2 --- /dev/null +++ b/module/move/gspread/tests/tests.rs @@ -0,0 +1,10 @@ +#[ allow( unused_imports ) ] +use gspread as the_module; +#[ allow( unused_imports ) ] +use test_tools::exposed::*; + +#[ cfg( feature = "with_online" ) ] +mod inc; + +#[ cfg( feature = "default" ) ] +mod mock; \ No newline at end of file diff --git a/module/move/optimization_tools/Cargo.toml b/module/move/optimization_tools/Cargo.toml index de8500b846..4a276984c9 100644 --- a/module/move/optimization_tools/Cargo.toml +++ b/module/move/optimization_tools/Cargo.toml @@ -17,8 +17,8 @@ categories = [ "algorithms", "development-tools" ] keywords = [ "fundamental", "general-purpose" ] # xxx : qqq : switch that on -# [lints] -# workspace = true +#[lints] +#workspace = true [package.metadata.docs.rs] features = [ "full" ] @@ -40,7 +40,9 @@ lp_parse = [ "dep:exmex" ] derive_tools = { workspace = true, features = [ "derive_more", "full", "strum" ] } deterministic_rand = { workspace = true, features = [ "default" ] } iter_tools = { workspace = true, features = [ "default" ] } -meta_tools = { workspace = true, features = [ "meta_constructors" ] } +# meta_tools = { workspace = true, features = [ "meta_constructors" ] } +meta_tools = { workspace = true, features = [] } +collection_tools = { workspace = true } # qqq : use intead of meta_tools error_tools = { workspace = true, features = ["default"] } env_logger = "0.10.1" log = "0.4.20" @@ -58,7 +60,7 @@ plotters = { version = "0.3.5", default-features = false, features = [ "bitmap_backend", ] } plotters-backend = { version = "0.3.5", optional = true } -piston_window = { version = "0.120.0", optional = true } +piston_window = { version = "0.132.0", optional = true } exmex = { version = "0.18.0", features = [ "partial" ], optional = true } rayon = "1.8.0" thiserror = "1.0.56" diff --git a/module/move/plot_interface/src/plot/abs/change.rs b/module/move/plot_interface/src/plot/abs/change.rs index b6ba9fc235..fc14b77ec9 100644 --- a/module/move/plot_interface/src/plot/abs/change.rs +++ b/module/move/plot_interface/src/plot/abs/change.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/abs/changer.rs b/module/move/plot_interface/src/plot/abs/changer.rs index 99e39449e0..9e09820670 100644 --- a/module/move/plot_interface/src/plot/abs/changer.rs +++ b/module/move/plot_interface/src/plot/abs/changer.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/abs/context.rs b/module/move/plot_interface/src/plot/abs/context.rs index 526b5bf488..c9f844e802 100644 --- a/module/move/plot_interface/src/plot/abs/context.rs +++ b/module/move/plot_interface/src/plot/abs/context.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/abs/identity.rs b/module/move/plot_interface/src/plot/abs/identity.rs index d8be2ccff7..1fe2b0e613 100644 --- a/module/move/plot_interface/src/plot/abs/identity.rs +++ b/module/move/plot_interface/src/plot/abs/identity.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/abs/registry.rs b/module/move/plot_interface/src/plot/abs/registry.rs index b6d662b429..21a2cd6be7 100644 --- a/module/move/plot_interface/src/plot/abs/registry.rs +++ b/module/move/plot_interface/src/plot/abs/registry.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/color.rs b/module/move/plot_interface/src/plot/color.rs index b14a3e268e..fc2b94c17f 100644 --- a/module/move/plot_interface/src/plot/color.rs +++ b/module/move/plot_interface/src/plot/color.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/context.rs b/module/move/plot_interface/src/plot/sys/context.rs index e5c23e71f6..ee2f95fbf3 100644 --- a/module/move/plot_interface/src/plot/sys/context.rs +++ b/module/move/plot_interface/src/plot/sys/context.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/context_changer.rs b/module/move/plot_interface/src/plot/sys/context_changer.rs index 2f87310469..fa33094931 100644 --- a/module/move/plot_interface/src/plot/sys/context_changer.rs +++ b/module/move/plot_interface/src/plot/sys/context_changer.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/drawing.rs b/module/move/plot_interface/src/plot/sys/drawing.rs index 7fdca77c2d..1ec732286b 100644 --- a/module/move/plot_interface/src/plot/sys/drawing.rs +++ b/module/move/plot_interface/src/plot/sys/drawing.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/drawing/change_new.rs b/module/move/plot_interface/src/plot/sys/drawing/change_new.rs index 914678a907..4661f9587b 100644 --- a/module/move/plot_interface/src/plot/sys/drawing/change_new.rs +++ b/module/move/plot_interface/src/plot/sys/drawing/change_new.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/drawing/changer.rs b/module/move/plot_interface/src/plot/sys/drawing/changer.rs index bfe7cf170f..7fd62e8e44 100644 --- a/module/move/plot_interface/src/plot/sys/drawing/changer.rs +++ b/module/move/plot_interface/src/plot/sys/drawing/changer.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/drawing/command.rs b/module/move/plot_interface/src/plot/sys/drawing/command.rs index f98cedfd22..998272ee16 100644 --- a/module/move/plot_interface/src/plot/sys/drawing/command.rs +++ b/module/move/plot_interface/src/plot/sys/drawing/command.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/drawing/queue.rs b/module/move/plot_interface/src/plot/sys/drawing/queue.rs index c68de594ba..c3148011bb 100644 --- a/module/move/plot_interface/src/plot/sys/drawing/queue.rs +++ b/module/move/plot_interface/src/plot/sys/drawing/queue.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/drawing/rect_change_new.rs b/module/move/plot_interface/src/plot/sys/drawing/rect_change_new.rs index 7b1a3acfc7..57fe8b5898 100644 --- a/module/move/plot_interface/src/plot/sys/drawing/rect_change_new.rs +++ b/module/move/plot_interface/src/plot/sys/drawing/rect_change_new.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/drawing/rect_change_region.rs b/module/move/plot_interface/src/plot/sys/drawing/rect_change_region.rs index bdbb18321d..84c1634301 100644 --- a/module/move/plot_interface/src/plot/sys/drawing/rect_change_region.rs +++ b/module/move/plot_interface/src/plot/sys/drawing/rect_change_region.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/drawing/rect_changer.rs b/module/move/plot_interface/src/plot/sys/drawing/rect_changer.rs index 85d56d9b48..cb5ddf757f 100644 --- a/module/move/plot_interface/src/plot/sys/drawing/rect_changer.rs +++ b/module/move/plot_interface/src/plot/sys/drawing/rect_changer.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/stroke_brush.rs b/module/move/plot_interface/src/plot/sys/stroke_brush.rs index 08c73b350b..edfbfc4878 100644 --- a/module/move/plot_interface/src/plot/sys/stroke_brush.rs +++ b/module/move/plot_interface/src/plot/sys/stroke_brush.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/stroke_brush/change_color.rs b/module/move/plot_interface/src/plot/sys/stroke_brush/change_color.rs index ae615f89a4..76bd951613 100644 --- a/module/move/plot_interface/src/plot/sys/stroke_brush/change_color.rs +++ b/module/move/plot_interface/src/plot/sys/stroke_brush/change_color.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/stroke_brush/change_new.rs b/module/move/plot_interface/src/plot/sys/stroke_brush/change_new.rs index d147f3241b..caa1c2f75c 100644 --- a/module/move/plot_interface/src/plot/sys/stroke_brush/change_new.rs +++ b/module/move/plot_interface/src/plot/sys/stroke_brush/change_new.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/stroke_brush/change_width.rs b/module/move/plot_interface/src/plot/sys/stroke_brush/change_width.rs index 192b42e8ad..758fbe75a7 100644 --- a/module/move/plot_interface/src/plot/sys/stroke_brush/change_width.rs +++ b/module/move/plot_interface/src/plot/sys/stroke_brush/change_width.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/stroke_brush/changer.rs b/module/move/plot_interface/src/plot/sys/stroke_brush/changer.rs index c6f8ab0f5f..d6208455a0 100644 --- a/module/move/plot_interface/src/plot/sys/stroke_brush/changer.rs +++ b/module/move/plot_interface/src/plot/sys/stroke_brush/changer.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/plot_interface/src/plot/sys/target.rs b/module/move/plot_interface/src/plot/sys/target.rs index 96f38bfe51..820f3a3b97 100644 --- a/module/move/plot_interface/src/plot/sys/target.rs +++ b/module/move/plot_interface/src/plot/sys/target.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::prelude::*; diff --git a/module/move/sqlx_query/src/lib.rs b/module/move/sqlx_query/src/lib.rs index b0855a6219..53d4a4043e 100644 --- a/module/move/sqlx_query/src/lib.rs +++ b/module/move/sqlx_query/src/lib.rs @@ -17,7 +17,7 @@ #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/../../../", "Readme.md" ) ) ] -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( feature = "enabled" ) ] mod private { diff --git a/module/move/unitore/Cargo.toml b/module/move/unitore/Cargo.toml index fa560e6cae..08313bc8e0 100644 --- a/module/move/unitore/Cargo.toml +++ b/module/move/unitore/Cargo.toml @@ -43,7 +43,7 @@ toml = "0.8.10" serde = "1.0.196" url = { version = "2.0", features = ["serde"] } humantime-serde = "1.1.1" -gluesql = "0.15.0" +gluesql = "0.16.2" async-trait = "0.1.41" wca = { workspace = true } mockall = "0.12.1" diff --git a/module/move/wca/Cargo.toml b/module/move/wca/Cargo.toml index da8d1227b6..06791cf645 100644 --- a/module/move/wca/Cargo.toml +++ b/module/move/wca/Cargo.toml @@ -40,12 +40,12 @@ harness = false [dependencies] ## internal -error_tools = { workspace = true, features = [ "default" ] } -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 +error_tools = { workspace = true, features = [ "enabled", "error_typed", "error_untyped" ] } +mod_interface = { workspace = true, features = [ "enabled" ] } +iter_tools = { workspace = true, features = [ "enabled" ] } +former = { workspace = true, features = [ "enabled", "derive_former" ] } +# xxx : aaa : optimize set of features +# aaa : done. ## external log = "0.4" diff --git a/module/move/wca/Readme.md b/module/move/wca/Readme.md index b808fce2bc..ecda885b57 100644 --- a/module/move/wca/Readme.md +++ b/module/move/wca/Readme.md @@ -14,7 +14,7 @@ The tool to make CLI ( commands user interface ). It is able to aggregate extern ```rust #[ cfg( not( feature = "no_std" ) ) ] { - use wca::{ VerifiedCommand, Context, Type }; + use wca::{ VerifiedCommand, Type }; fn main() { @@ -37,7 +37,7 @@ The tool to make CLI ( commands user interface ). It is able to aggregate extern .end() .perform(); - let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); + let args: Vec< String > = std::env::args().skip( 1 ).collect(); ca.perform( args ).unwrap(); } diff --git a/module/move/wca/examples/wca_custom_error.rs b/module/move/wca/examples/wca_custom_error.rs new file mode 100644 index 0000000000..47fef16985 --- /dev/null +++ b/module/move/wca/examples/wca_custom_error.rs @@ -0,0 +1,43 @@ +//! +//! # Handling Errors with CommandsAggregator +//! +//! This module provides an example of how to use `wca::CommandsAggregator` to manage error handling in a command-line interface. The `CommandsAggregator` offers a fluent interface for defining commands and associating them with various error types, making it straightforward to handle and present errors in a structured way. +//! +//! ## Purpose +//! +//! The primary goal of this example is to showcase how `CommandsAggregator` facilitates error handling, whether errors are simple strings, custom typed errors, untyped errors, or errors with additional context. This approach ensures that error management is both consistent and extensible. +//! + +#[ derive( Debug, error_tools::typed::Error )] +enum CustomError +{ + #[ error( "this is typed error" ) ] + TheError, +} + +fn main() -> error_tools::error::untyped::Result< () > +{ + let ca = wca::CommandsAggregator::former() + .command( "error.string" ) + .hint( "Returns error as a string" ) + .routine( || { Err( "this is string error" ) } ) + .end() + .command( "error.typed" ) + .hint( "Returns error as a custom error" ) + .routine( || { Err( CustomError::TheError ) } ) + .end() + .command( "error.untyped" ) + .hint( "Returns error as untyped error" ) + .routine( || { Err( error_tools::error::untyped::format_err!( "this is untyped error" ) ) } ) + .end() + .command( "error.with_context" ) + .hint( "Returns error as untyped error with context" ) + .routine( || { Err( error_tools::error::untyped::format_err!( "this is untyped error" ).context( "with context" ) ) } ) + .end() + .perform(); + + let args: Vec< String > = std::env::args().skip( 1 ).collect(); + () = ca.perform( args )?; + + Ok( () ) +} \ No newline at end of file diff --git a/module/move/wca/examples/wca_fluent.rs b/module/move/wca/examples/wca_fluent.rs index 487d6ee97d..3d5475a481 100644 --- a/module/move/wca/examples/wca_fluent.rs +++ b/module/move/wca/examples/wca_fluent.rs @@ -7,10 +7,10 @@ //! -use wca::{ Context, Handler, Type, VerifiedCommand }; +use wca::{ executor::{ Context, Handler }, Type, VerifiedCommand }; use std::sync::{ Arc, Mutex }; -fn main() +fn main() -> error_tools::error::untyped::Result< () > { let ca = wca::CommandsAggregator::former() @@ -45,7 +45,8 @@ fn main() .end() .perform(); - let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); - ca.perform( args ).unwrap(); + let args: Vec< String > = std::env::args().skip( 1 ).collect(); + ca.perform( args )?; + Ok( () ) } diff --git a/module/move/wca/examples/wca_suggest.rs b/module/move/wca/examples/wca_suggest.rs index 2bb73fa111..b9b54989a8 100644 --- a/module/move/wca/examples/wca_suggest.rs +++ b/module/move/wca/examples/wca_suggest.rs @@ -22,7 +22,7 @@ use wca::{ CommandsAggregator, Type, VerifiedCommand }; -fn main() +fn main() -> error_tools::error::untyped::Result< () > { let ca = CommandsAggregator::former() @@ -34,14 +34,11 @@ fn main() { println!( "= Args\n{:?}\n\n= Properties\n{:?}\n", o.args, o.props ); }) - .end() + .end() .perform(); - let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); - match ca.perform( args.join( " " ) ) - { - Ok( _ ) => {} - Err( err ) => println!( "{err}" ), - }; + let args: Vec< String > = std::env::args().skip( 1 ).collect(); + ca.perform( args.join( " " ) )?; + Ok( () ) } diff --git a/module/move/wca/examples/wca_trivial.rs b/module/move/wca/examples/wca_trivial.rs index c228e6e20a..1df6dec815 100644 --- a/module/move/wca/examples/wca_trivial.rs +++ b/module/move/wca/examples/wca_trivial.rs @@ -16,7 +16,7 @@ fn exit() std::process::exit( 0 ) } -fn main() +fn main() -> error_tools::error::untyped::Result< () > { let ca = CommandsAggregator::former() .command( "exit" ) @@ -33,7 +33,7 @@ fn main() .perform() ; - // aaa : qqq2 : for Bohdan : that should work + // aaa : aaa2 : for Bohdan : that should work // let ca = wca::CommandsAggregator::former() // .command( "echo" ) // .hint( "prints all subjects and properties" ) @@ -50,6 +50,8 @@ fn main() // ca.execute( input ).unwrap(); //aaa: works - let input = std::env::args().skip( 1 ).collect::< Vec< String > >(); - ca.perform( input ).unwrap(); + let input: Vec< String > = std::env::args().skip( 1 ).collect(); + ca.perform( input )?; + + Ok( () ) } diff --git a/module/move/wca/src/ca/aggregator.rs b/module/move/wca/src/ca/aggregator.rs index 60668ad4a0..fb3725ba16 100644 --- a/module/move/wca/src/ca/aggregator.rs +++ b/module/move/wca/src/ca/aggregator.rs @@ -1,9 +1,10 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use ca:: { - Verifier, Executor, grammar::command:: { @@ -14,15 +15,17 @@ mod private }, help::{ HelpGeneratorFn, HelpGeneratorOptions, HelpVariants }, }; + use verifier::{ Verifier, VerificationError, VerifiedCommand }; + use parser::{ Program, Parser, ParserError }; + use grammar::Dictionary; + use executor::Context; - // qqq : group uses - use std::collections::HashSet; - use std::fmt; + use std:: + { + fmt, + collections::HashSet + }; use former::StoragePreform; - // use wtools:: - // { - // }; - // use wtools::thiserror; use error:: { // Result, @@ -54,11 +57,11 @@ mod private /// source of the program input : String, /// original error - error : wError, + error : ParserError, }, /// This variant represents errors that occur during grammar conversion. #[ error( "Can not identify a command.\nDetails: {0}" ) ] - Verifier( wError ), + Verifier( VerificationError ), /// This variant is used to represent errors that occur during executor conversion. #[ error( "Can not find a routine for a command.\nDetails: {0}" ) ] ExecutorConverter( wError ), @@ -70,16 +73,17 @@ mod private { /// This variant is used to represent validation errors. /// It carries a `ValidationError` payload that provides additional information about the error. - #[ error( "Validation error. {0}" ) ] + #[ error( "Validation error\n{0}" ) ] Validation( ValidationError ), /// This variant represents execution errors. - #[ error( "Execution failed. {0:?}" ) ] + #[ error( "Execution failed\n{0:?}" ) ] Execution( wError ), } - // xxx : qqq : qqq2 : for Bohdan : one level is obviously redundant + // xxx : aaa : aaa2 : for Bohdan : one level is obviously redundant // Program< Namespace< ExecutableCommand_ > > -> Program< ExecutableCommand_ > // aaa : done. The concept of `Namespace` has been removed + #[ allow( clippy::type_complexity ) ] struct CommandsAggregatorCallback( Box< dyn Fn( &str, &Program< VerifiedCommand > ) > ); impl fmt::Debug for CommandsAggregatorCallback @@ -93,7 +97,7 @@ mod private /// The `CommandsAggregator` struct is responsible for aggregating all commands that the user defines, /// and for parsing and executing them. It is the main entry point of the library. /// - /// CommandsAggregator component brings everything together. This component is responsible for configuring the `Parser`, `Grammar`, and `Executor` components based on the user’s needs. It also manages the entire pipeline of processing, from parsing the raw text input to executing the final command(parse -> validate -> execute). + /// `CommandsAggregator` component brings everything together. This component is responsible for configuring the `Parser`, `Grammar`, and `Executor` components based on the user’s needs. It also manages the entire pipeline of processing, from parsing the raw text input to executing the final command(parse -> validate -> execute). /// /// # Example: /// @@ -144,8 +148,8 @@ mod private let dictionary = ca.dictionary.get_or_insert_with( Dictionary::default ); dictionary.order = ca.order.unwrap_or_default(); - let help_generator = std::mem::take( &mut ca.help_generator ).unwrap_or_default(); - let help_variants = std::mem::take( &mut ca.help_variants ).unwrap_or_else( || HashSet::from([ HelpVariants::All ]) ); + let help_generator = core::mem::take( &mut ca.help_generator ).unwrap_or_default(); + let help_variants = core::mem::take( &mut ca.help_variants ).unwrap_or_else( || HashSet::from([ HelpVariants::All ]) ); if help_variants.contains( &HelpVariants::All ) { @@ -170,6 +174,8 @@ mod private /// # Arguments /// /// * `name` - The name of the command. + /// # Panics + /// qqq: doc pub fn command< IntoName >( self, name : IntoName ) -> CommandAsSubformer< Self, impl CommandAsSubformerEnd< Self > > where IntoName : Into< String >, @@ -203,6 +209,7 @@ mod private /// /// The modified instance of `Self`. // `'static` means that the value must be owned or live at least as a `Context' + #[ must_use ] pub fn with_context< T >( mut self, value : T ) -> Self where T : Sync + Send + 'static, @@ -230,6 +237,7 @@ mod private /// ca.perform( ".help" )?; /// # Ok( () ) } /// ``` + #[ must_use ] pub fn help< HelpFunction >( mut self, func : HelpFunction ) -> Self where HelpFunction : Fn( &Dictionary, HelpGeneratorOptions< '_ > ) -> String + 'static @@ -255,6 +263,7 @@ mod private /// ca.perform( ".help" )?; /// # Ok( () ) } /// ``` + #[ must_use ] pub fn callback< Callback >( mut self, callback : Callback ) -> Self where Callback : Fn( &str, &Program< VerifiedCommand > ) + 'static, @@ -269,21 +278,23 @@ mod private /// Parse, converts and executes a program /// /// Takes a string with program and executes it + /// # Errors + /// qqq: doc pub fn perform< S >( &self, program : S ) -> Result< (), Error > where S : IntoInput { let Input( ref program ) = program.into_input(); - let raw_program = self.parser.parse( program ).map_err( | e | Error::Validation( ValidationError::Parser { input : format!( "{:?}", program ), error : e } ) )?; + let raw_program = self.parser.parse( program ).map_err( | e | Error::Validation( ValidationError::Parser { input : format!( "{program:?}" ), error : e } ) )?; let grammar_program = self.verifier.to_program( &self.dictionary, raw_program ).map_err( | e | Error::Validation( ValidationError::Verifier( e ) ) )?; if let Some( callback ) = &self.callback_fn { - callback.0( &program.join( " " ), &grammar_program ) + callback.0( &program.join( " " ), &grammar_program ); } - self.executor.program( &self.dictionary, grammar_program ).map_err( | e | Error::Execution( e ) ) + self.executor.program( &self.dictionary, grammar_program ).map_err( | e | Error::Execution( e.into() ) ) } } } @@ -293,8 +304,8 @@ mod private crate::mod_interface! { exposed use CommandsAggregator; - exposed use CommandsAggregatorFormer; - exposed use Error; - exposed use ValidationError; + orphan use CommandsAggregatorFormer; + orphan use Error; + orphan use ValidationError; exposed use Order; } diff --git a/module/move/wca/src/ca/executor/context.rs b/module/move/wca/src/ca/executor/context.rs index df60994a23..a9611b618e 100644 --- a/module/move/wca/src/ca/executor/context.rs +++ b/module/move/wca/src/ca/executor/context.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { use std::sync::Arc; @@ -7,7 +8,7 @@ mod private /// # Examples: /// /// ``` - /// # use wca::{ Routine, Handler, Context, Value, Args, Props, VerifiedCommand }; + /// # use wca::{ executor::{ Routine, Handler, Args, Props, Context }, Value, VerifiedCommand }; /// # use std::sync::{ Arc, Mutex }; /// let routine = Routine::from( Handler::from /// ( @@ -33,11 +34,11 @@ mod private /// } /// assert_eq!( 1, *ctx.get::< Mutex< i32 > >().unwrap().lock().unwrap() ); /// ``` - // qqq : ? + // xxx clarification is needed qqq : поточнити #[ derive( Debug, Clone ) ] pub struct Context { - inner : Arc< dyn std::any::Any + Send + Sync >, + inner : Arc< dyn core::any::Any + Send + Sync >, } impl Default for Context @@ -80,6 +81,7 @@ mod private /// An `Option` containing a reference-counted smart pointer (`Arc`) to the object of type `T` if it exists in the context. /// `None` is returned if the object does not exist or if it cannot be downcasted to type `T`. // `'static` means that the object must be owned or live at least as a `Context' + #[ must_use ] pub fn get< T : Send + Sync + 'static >( &self ) -> Option< Arc< T > > { self.inner.clone().downcast::< T >().ok() @@ -91,5 +93,5 @@ mod private crate::mod_interface! { - exposed use Context; + orphan use Context; } diff --git a/module/move/wca/src/ca/executor/executor.rs b/module/move/wca/src/ca/executor/executor.rs index 224aacd489..d6a7a3bdf1 100644 --- a/module/move/wca/src/ca/executor/executor.rs +++ b/module/move/wca/src/ca/executor/executor.rs @@ -1,14 +1,25 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; - // use wtools::error::Result; - use error::return_err; use ca::help::{ HelpGeneratorOptions, generate_help_content, LevelOfDetail }; + use verifier::VerifiedCommand; + use parser::Program; + use grammar::Dictionary; + use executor::{ Routine, Context }; // aaa : for Bohdan : how is it useful? where is it used? // aaa : `ExecutorType` has been removed + #[ derive( Debug, error::typed::Error ) ] + pub enum CommandError + { + #[ error( "Internal command: `.{}` failed with: {}", command.phrase, error ) ] + Internal { command: VerifiedCommand, error: InternalCommandError }, + #[ error( "Command: `.{}` failed with: {}", command.phrase, error ) ] + User { command: VerifiedCommand, error: error::untyped::Error }, + } /// Executor that is responsible for executing the program's commands. /// It uses the given `Context` to store and retrieve values during runtime. @@ -35,10 +46,12 @@ mod private /// # Returns /// /// A `Result` with `Ok( () )` if the execution was successful, or an `Err` containing an error message if an error occurred. - /// - // qqq : use typed error + /// # Errors + /// qqq: doc + // aaa : use typed error + // aaa : done pub fn program( &self, dictionary : &Dictionary, program : Program< VerifiedCommand > ) - -> error::untyped::Result< () > + -> Result< (), CommandError > { for command in program.commands { @@ -60,18 +73,25 @@ mod private /// # Returns /// /// Returns a Result indicating success or failure. If successful, returns `Ok(())`, otherwise returns an error. - // qqq : use typed error + /// # Errors + /// qqq: doc + /// # Panics + /// qqq: doc + // aaa : use typed error + // aaa : done pub fn command( &self, dictionary : &Dictionary, command : VerifiedCommand ) - -> error::untyped::Result< () > + -> Result< (), CommandError > { if command.internal_command { - _exec_internal_command( dictionary, command ) + _exec_internal_command( dictionary, command.clone() ) + .map_err( | error | CommandError::Internal { command, error } ) } else { let routine = dictionary.command( &command.phrase ).unwrap().routine.clone(); - _exec_command( command, routine, self.context.clone() ) + _exec_command( command.clone(), routine, self.context.clone() ) + .map_err( | error | CommandError::User { command, error } ) } } @@ -80,6 +100,7 @@ mod private } // qqq : use typed error + // aaa : should it be typed? it is user command with unknown error type fn _exec_command( command : VerifiedCommand, routine : Routine, ctx : Context ) -> error::untyped::Result< () > { @@ -90,9 +111,20 @@ mod private } } - // qqq : use typed error + #[ derive( Debug, error::typed::Error ) ] + pub enum InternalCommandError + { + #[ error( "Encountered an unrecognized internal command: `.{user_input}`." ) ] + UnknownInternalCommand { user_input: String }, + #[ error( "Not found command that starts with `.{user_input}`." ) ] + CommandNotFound { user_input: String }, + } + + // aaa : use typed error + // aaa : done + #[ allow( clippy::needless_pass_by_value ) ] fn _exec_internal_command( dictionary : &Dictionary, command : VerifiedCommand ) - -> error::untyped::Result< () > + -> Result< (), InternalCommandError > { match command.phrase.as_str() { @@ -122,7 +154,7 @@ mod private let commands = dictionary.search( name.strip_prefix( '.' ).unwrap_or( name ) ); if commands.is_empty() { - return_err!( "Not found command that starts with `.{}`.", name ); + return Err( InternalCommandError::CommandNotFound { user_input : name.into() } ); } let generator_args = HelpGeneratorOptions::former() .command_prefix( "." ) @@ -151,10 +183,10 @@ mod private } else { - return_err!( "Not found command that starts with `.{}`.", name ); + return Err( InternalCommandError::CommandNotFound { user_input : name.into() } ); } } - unexpected => return_err!( "Encountered an unrecognized internal command: `.{}`.", unexpected ), + unexpected => return Err( InternalCommandError::UnknownInternalCommand { user_input: unexpected.into() }), } Ok( () ) diff --git a/module/move/wca/src/ca/executor/routine.rs b/module/move/wca/src/ca/executor/routine.rs index 45fc96bed1..f40594af22 100644 --- a/module/move/wca/src/ca/executor/routine.rs +++ b/module/move/wca/src/ca/executor/routine.rs @@ -1,14 +1,20 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; - // qqq : group + // aaa : group + // aaa : done - use std::collections::HashMap; - // use wtools::error::Result; - - use std::{ fmt::Formatter, rc::Rc }; - // use wtools::anyhow::anyhow; + use std:: + { + collections::HashMap, + fmt::Formatter, + rc::Rc, + }; + use verifier::VerifiedCommand; + use executor::Context; /// Command Args /// @@ -17,7 +23,7 @@ mod private /// # Example: /// /// ``` - /// use wca::{ Args, Value }; + /// use wca::{ executor::Args, Value }; /// /// let args = Args( vec![ Value::String( "Hello, World!".to_string() ) ] ); /// @@ -30,7 +36,7 @@ mod private /// /// ## Use case /// ``` - /// # use wca::{ Routine, Handler, VerifiedCommand }; + /// # use wca::{ executor::{ Routine, Handler }, VerifiedCommand }; /// let routine = Routine::from( Handler::from /// ( /// | o : VerifiedCommand | @@ -47,7 +53,7 @@ mod private /// Returns owned casted value by its index /// /// ``` - /// # use wca::{ Args, Value }; + /// # use wca::{ executor::Args, Value }; /// /// let args = Args( vec![ Value::String( "Hello, World!".to_string() ) ] ); /// @@ -57,6 +63,7 @@ mod private /// let first_arg : &str = args[ 0 ].clone().into(); /// assert_eq!( "Hello, World!", first_arg ); /// ``` + #[ must_use ] pub fn get_owned< T : From< Value > >( &self, index : usize ) -> Option< T > { self.0.get( index ).map( | arg | arg.to_owned().into() ) @@ -79,7 +86,7 @@ mod private /// # Example: /// /// ``` - /// use wca::{ Props, Value }; + /// use wca::{ executor::Props, Value }; /// /// let props = Props( [ ( "hello".to_string(), Value::String( "World!".to_string() ) ) ].into() ); /// let hello_prop : &str = props.get_owned( "hello" ).unwrap(); @@ -89,7 +96,7 @@ mod private /// /// ## Use case /// ``` - /// # use wca::{ Routine, Handler, Props, VerifiedCommand }; + /// # use wca::{ executor::{ Routine, Handler, Props }, VerifiedCommand }; /// let routine = Routine::from( Handler::from /// ( /// | o : VerifiedCommand | @@ -106,7 +113,7 @@ mod private /// Returns owned casted value by its key /// /// ``` - /// # use wca::{ Props, Value }; + /// # use wca::{ executor::Props, Value }; /// /// let props = Props( [ ( "hello".to_string(), Value::String( "World!".to_string() ) ) ].into() ); /// let hello_prop : &str = props.get_owned( "hello" ).unwrap(); @@ -132,7 +139,10 @@ mod private // aaa : done. now it works with the following variants: // fn(), fn(args), fn(props), fn(args, props), fn(context), fn(context, args), fn(context, props), fn(context, args, props) - // qqq : why not public? + // aaa : why not public? // aaa : described + + // These type aliases are kept private to hide implementation details and prevent misuse. + // Exposing them would risk complicating the API and limit future refactoring flexibility. type RoutineWithoutContextFn = dyn Fn( VerifiedCommand ) -> error::untyped::Result< () >; type RoutineWithContextFn = dyn Fn( Context, VerifiedCommand ) -> error::untyped::Result< () >; @@ -140,7 +150,7 @@ mod private /// Routine handle. /// /// ``` - /// # use wca::{ Handler, Routine }; + /// # use wca::executor::{ Handler, Routine }; /// let routine = Routine::from( Handler::from /// ( /// || @@ -151,7 +161,7 @@ mod private /// ``` /// /// ``` - /// # use wca::{ Handler, Routine, VerifiedCommand }; + /// # use wca::{ executor::{ Handler, Routine }, VerifiedCommand }; /// let routine = Routine::from( Handler::from /// ( /// | o : VerifiedCommand | @@ -162,7 +172,7 @@ mod private /// ``` /// /// ``` - /// # use wca::{ Handler, Routine }; + /// # use wca::executor::{ Handler, Routine }; /// let routine = Routine::from( Handler::from /// ( /// | ctx, o | @@ -173,9 +183,9 @@ mod private pub struct Handler< I, O >( Box< dyn Fn( I ) -> O > ); - impl< I, O > std::fmt::Debug for Handler< I, O > + impl< I, O > core::fmt::Debug for Handler< I, O > { - fn fmt( &self, f : &mut Formatter< '_ > ) -> std::fmt::Result + fn fmt( &self, f : &mut Formatter< '_ > ) -> core::fmt::Result { f.debug_struct( "Handler" ).finish_non_exhaustive() } @@ -243,7 +253,7 @@ mod private /// /// - `WithoutContext`: A routine that does not require any context. /// - `WithContext`: A routine that requires a context. -// qqq : for Bohdan : instead of array of Enums, lets better have 5 different arrays of different Routine and no enum +// xxx clarification is needed : for Bohdan : instead of array of Enums, lets better have 5 different arrays of different Routine and no enum // to use statical dispatch #[ derive( Clone ) ] pub enum Routine @@ -254,9 +264,9 @@ mod private WithContext( Rc< RoutineWithContextFn > ), } - impl std::fmt::Debug for Routine + impl core::fmt::Debug for Routine { - fn fmt( &self, f : &mut Formatter< '_ > ) -> std::fmt::Result + fn fmt( &self, f : &mut Formatter< '_ > ) -> core::fmt::Result { match self { @@ -309,7 +319,7 @@ mod private { // We can't compare closures. Because every closure has a separate type, even if they're identical. // Therefore, we check that the two Rc's point to the same closure (allocation). - #[ allow( clippy::vtable_address_comparisons ) ] + #[ allow( ambiguous_wide_pointer_comparisons ) ] match ( self, other ) { ( Routine::WithContext( this ), Routine::WithContext( other ) ) => Rc::ptr_eq( this, other ), @@ -327,15 +337,25 @@ mod private } // xxx - impl IntoResult for std::convert::Infallible { fn into_result( self ) -> error::untyped::Result< () > { Ok( () ) } } + // aaa : This is an untyped error because we want to provide a common interface for all commands, while also allowing users to propagate their own specific custom errors. + impl IntoResult for core::convert::Infallible { fn into_result( self ) -> error::untyped::Result< () > { Ok( () ) } } impl IntoResult for () { fn into_result( self ) -> error::untyped::Result< () > { Ok( () ) } } - impl< E : std::fmt::Debug > IntoResult + impl< E : core::fmt::Debug + std::fmt::Display + 'static > IntoResult for error::untyped::Result< (), E > { fn into_result( self ) -> error::untyped::Result< () > { - self.map_err( | e | error::untyped::format_err!( "{e:?}" )) - // xxx : qqq : ? + use std::any::TypeId; + // if it's anyhow error we want to have full context(debug), and if it's not(this error) we want to display + if TypeId::of::< error::untyped::Error >() == TypeId::of::< E >() + { + self.map_err( | e | error::untyped::format_err!( "{e:?}" )) + } + else + { + self.map_err( | e | error::untyped::format_err!( "{e}" )) + } + // xxx : aaa : ? } } } @@ -344,8 +364,8 @@ mod private crate::mod_interface! { - exposed use Routine; - exposed use Handler; - exposed use Args; - exposed use Props; + orphan use Routine; + orphan use Handler; + orphan use Args; + orphan use Props; } diff --git a/module/move/wca/src/ca/facade.rs b/module/move/wca/src/ca/facade.rs deleted file mode 100644 index 80fca20afc..0000000000 --- a/module/move/wca/src/ca/facade.rs +++ /dev/null @@ -1,345 +0,0 @@ -// mod private -// { -// use crate::*; -// use core::fmt; -// use ca::grammar; -// -// /// Macro for parsing WCA arguments. -// /// -// /// # Examples -// /// ```rust -// /// use wca::Value; -// /// -// /// let mut args = vec![ Value::Number( 42. ), Value::String( "Rust".into() ) ].into_iter(); -// /// wca::parse_args!( args, n : f64, name : String ); -// /// -// /// assert_eq!( n, 42. ); -// /// assert_eq!( name, "Rust" ); -// /// ``` -// #[macro_export] -// macro_rules! parse_args -// { -// ( $args : ident, mut $b : ident : $ty : ident $( $rest : tt )* ) => -// { -// let mut $b : $ty = std::convert::TryFrom::try_from( $args.next().unwrap() ).unwrap(); -// $crate::parse_args!( $args $( $rest )* ) -// }; -// ( $args : ident, $b : ident : $ty : ident $( $rest : tt )* ) => -// { -// let $b : $ty = std::convert::TryFrom::try_from( $args.next().unwrap() ).unwrap(); -// $crate::parse_args!( $args $( $rest )* ) -// }; -// ( $args : ident, $b : ident $( $rest : tt )* ) => -// { -// let $b = $args.next().unwrap(); -// $crate::parse_args!( $args $( $rest )* ) -// }; -// ( $args : ident, mut $b : ident $( $rest : tt )* ) => -// { -// let mut $b = $args.next().unwrap(); -// $crate::parse_args!( $args $( $rest )* ) -// }; -// ( $args : ident ) => -// { -// assert!( $args.next().is_none() ); -// }; -// ( $args : ident, ) => -// { -// $crate::parse_args!( $args ) -// }; -// } -// -// /// Creates a command-line interface (CLI) builder with the given initial state. -// /// -// /// This function initializes a `CommandBuilder` with the provided `state` and -// /// returns it for further configuration of the CLI. -// pub fn cui< T >( state : T ) -> CommandBuilder< T > -// { -// CommandBuilder::with_state( state ) -// } -// -// /// A struct representing a property. -// #[ derive( Debug, Clone ) ] -// pub struct Property< 'a > -// { -// /// The name of the property. -// pub name : &'a str, -// /// The hint for the property. -// pub debug : &'a str, -// /// The tag representing the property's type. -// pub tag : Type, -// } -// -// impl< 'a > Property< 'a > -// { -// /// Constructor of a property. -// pub fn new( name : &'a str, hint : &'a str, tag : Type ) -> Self { Self { name, hint, tag } } -// } -// -// /// A builder struct for constructing commands. -// #[ derive( Debug ) ] -// pub struct CommandBuilder< T > -// { -// state : T, -// commands : Vec< Command >, -// handlers : std::collections::HashMap< String, Routine >, -// } -// -// impl< T > CommandBuilder< T > -// { -// /// Constructs a `CommandBuilder` with the given state. -// pub fn with_state( state : T ) -> Self -// { -// Self { state, handlers : < _ >::default(), commands : vec![] } -// } -// } -// -// #[ derive( Debug ) ] -// pub struct Builder< F > -// { -// handler : F, -// command : Command, -// } -// -// impl< F > Builder< F > -// { -// /// Creates a new instance of the command with the provided handler function. -// /// -// /// This method takes in a handler function `handler` and creates a new instance of the command. -// /// The `handler` function is used to handle the execution logic associated with the command. -// /// -// /// # Arguments -// /// -// /// * `handler` - The handler function that will be invoked when the command is executed. -// /// -// /// # Returns -// /// -// /// A new instance of the command with the specified `handler`. -// /// -// #[ inline ] -// pub fn new( handler: F ) -> Self -// { -// let name = -// { -// use iter_tools::Itertools as _; -// -// let name = std::any::type_name::< F >(); -// let name = name.split("::").last().unwrap(); -// name.split( '_' ).join( "." ) -// }; -// -// Self { handler, command : Command::former().phrase( name ).form() } -// } -// -// /// Adds an argument to the command. -// /// -// /// This method takes in the `hint` and `tag` parameters to create a `ValueDescription` object -// /// representing an argument. The `ValueDescription` object is then appended to the command's -// /// `subjects` collection. -// /// -// /// # Arguments -// /// -// /// * `hint` - The hint for the argument, represented as a string slice (`&str`). -// /// * `tag` - The type of the argument, represented by a `Type` object from the `Type` module. -// /// -// /// # Returns -// /// -// /// The modified command instance with the argument added. -// /// -// #[ inline ] -// pub fn arg( mut self, hint : &str, tag : Type ) -> Self -// { -// self.command.subjects.push( grammar::command::ValueDescription -// { -// hint : hint.into(), -// kind : tag, -// optional : false, -// }); -// -// self -// } -// -// /// Adds a property to the command. -// /// -// /// This method takes in the `name`, `hint`, and `kind` parameters to create a `ValueDescription` -// /// object representing a property. The `ValueDescription` object is then inserted into the -// /// command's properties collection using the `name` as the key. -// /// -// /// # Example -// /// ```no_rust -// /// let ca = cui(()) -// /// .command(user.property("name", "Name property", Type::String)) -// /// .build(); -// /// ``` -// /// -// /// # Arguments -// /// -// /// * `name` - The name of the property. It should implement the `ToString` trait. -// /// * `hint` - The hint for the property. It should implement the `ToString` trait. -// /// * `kind` - The type of the property, represented by a `Type` object from the `Type` module. -// /// -// /// # Returns -// /// -// /// The modified command instance with the property added. -// /// -// #[ inline ] -// pub fn property( mut self, name : impl ToString , hint : impl ToString, kind : Type ) -> Self -// { -// self.command.properties.insert -// ( -// name.to_string(), -// grammar::command::ValueDescription -// { -// hint : hint.to_string(), -// kind, -// optional : false, -// } -// ); -// -// self -// } -// -// /// Adds multiple properties to the command. -// /// -// /// This method takes in an array of `Property` objects and adds them to the command's properties. -// /// The properties are provided in the `properties` parameter as an array of length `N`. -// /// -// /// ```without_std -// /// let ca = cui(()) -// /// .properties([ -// /// Property::new("name", "Name property", Type::String), -// /// Property::new("age", "Age property", Type::Integer), -// /// ]).build(); -// /// ``` -// /// -// /// # Arguments -// /// -// /// * `properties` - An array of `Property` objects representing the properties to be added. -// /// -// /// # Returns -// /// -// /// The modified command instance with the properties added. -// /// -// #[ inline ] -// pub fn properties< const N: usize >( mut self, properties : [ Property< '_ >; N ] ) -> Self -// { -// self.command.properties.reserve( properties.len() ); -// -// for Property { name, hint, tag } in properties -// { -// self = self.property(name, hint, tag); -// } -// -// self -// } -// } -// -// impl< T: Clone + 'static > CommandBuilder< T > -// { -// /// Adds a command to the `CommandBuilder`. -// /// ```no_rust -// /// let ca = cui( () ) // Add commands using the builder pattern -// /// .command( command ) -// /// .command( command2 ) -// /// .command( echo.arg("string", Type::String ) ) // Customize your commands by chaining methods such as properties -// /// // property, and arg to add properties and arguments. -// /// .build(); -// /// -// /// ``` -// pub fn command< F, E > -// ( -// mut self, -// command : impl IntoBuilder< F, T >, -// ) -> Self -// where -// F : Fn( T, Args, Props ) -> Result< (), E > + 'static + Copy, -// E : fmt::Debug, -// { -// let Builder { handler, command } = command.into_builder(); -// let state = self.state.clone(); -// -// let closure = closure::closure!( | ( args, props ) | -// { -// handler( state.clone(), args, props ) -// .map_err( | report | BasicError::new( format!( "{report:?}" ) ).into() ) -// }); -// -// let handler = Routine::new( closure ); -// -// self.handlers.insert( command.phrase.clone(), handler ); -// self.commands.push( command ); -// -// self -// } -// -// /// Builds and returns a `wca::CommandsAggregator` instance. -// /// -// /// This method finalizes the construction of the `CommandBuilder` by -// /// creating a `wca::CommandsAggregator` instance with the accumulated -// /// commands and handlers. -// pub fn build( self ) -> CommandsAggregator -// { -// CommandsAggregator::former().grammar( self.commands ).executor( self.handlers ).perform() -// } -// } -// -// /// An extension trait for commands. -// /// -// /// This trait provides additional methods for enhancing commands, such as -// /// adding arguments and properties. -// pub trait CommandExt< T > : Sized -// { -// /// Adds an argument to the command. -// fn arg( self, hint : &str, tag : Type ) -> Builder< Self > -// { -// Builder::new( self ).arg( hint, tag ) -// } -// -// /// Adds property to the command. -// fn property< const N: usize >( self, name : impl ToString , hint : impl ToString, kind : Type ) -> Builder< Self > -// { -// Builder::new( self ).property( name, hint, kind ) -// } -// -// /// Adds properties to the command. -// fn properties< const N: usize >( self, properties: [ Property< '_ >; N ] ) -> Builder< Self > -// { -// Builder::new( self ).properties( properties ) -// } -// } -// -// impl< F: Fn( T, Args, Props ) -> Result< (), E>, T, E > CommandExt< T > for F {} -// -// /// A trait for converting a type into a `Builder`. -// pub trait IntoBuilder< F, T > : Sized -// { -// /// Converts the type into a `Builder` instance. -// fn into_builder( self ) -> Builder< F >; -// } -// -// impl< F, T > IntoBuilder< F, T > for Builder< F > -// { -// fn into_builder( self ) -> Self -// { -// self -// } -// } -// -// impl< F: Fn( T, Args, Props ) -> Result< (), E >, T, E > IntoBuilder< F, T > for F -// { -// fn into_builder( self ) -> Builder< F > -// { -// Builder::new( self ) -// } -// } -// -// } -// -// crate::mod_interface! -// { -// exposed use cui; -// exposed use CommandBuilder; -// exposed use Property; -// prelude use IntoBuilder; -// prelude use CommandExt; -// } diff --git a/module/move/wca/src/ca/formatter.rs b/module/move/wca/src/ca/formatter.rs index d528ef7f6d..1c606532d7 100644 --- a/module/move/wca/src/ca/formatter.rs +++ b/module/move/wca/src/ca/formatter.rs @@ -1,25 +1,40 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use iter_tools::Itertools; use ca::aggregator::Order; + use grammar::Dictionary; - /// - + /// Enum representing the format options for generating help content. + /// + /// `HelpFormat` defines the output format of help content, enabling the choice + /// between different styles, such as `Markdown` for structured text, or other + /// custom formats. #[ derive( Debug, Clone, PartialEq ) ] pub enum HelpFormat { + /// Generates help content in Markdown format, suitable for environments + /// that support Markdown rendering (e.g., documentation platforms, text editors). Markdown, + /// Represents an alternative format, customizable for different needs. Another, } + /// Generates Markdown-formatted help content based on a dictionary of terms and a specified order. + /// + /// The `md_generator` function takes a reference to a `Dictionary` and an `Order` to produce + /// a help document in Markdown format. This function is useful for generating structured, + /// readable help documentation suitable for Markdown-compatible platforms. + #[ must_use ] pub fn md_generator( grammar : &Dictionary, order: Order ) -> String { let text = grammar.commands() .into_iter() .map( |( name, cmd )| { - let subjects = cmd.subjects.iter().fold( String::new(), | _, _ | format!( " `[argument]`" ) ); + let subjects = cmd.subjects.iter().fold( String::new(), | _, _ | " `[argument]`".to_string() ); let properties = if cmd.properties.is_empty() { " " } else { " `[properties]` " }; format! ( @@ -35,17 +50,17 @@ mod private format!( "{acc}\n- {cmd}" ) }); - let list_of_commands = format!( "## Commands\n\n{}", text ); + let list_of_commands = format!( "## Commands\n\n{text}" ); let about_each_command = grammar.commands() .into_iter() .map( |( name, cmd )| { - let subjects = cmd.subjects.iter().fold( String::new(), | _, _ | format!( " `[Subject]`" ) ); + let subjects = cmd.subjects.iter().fold( String::new(), | _, _ | " `[Subject]`".to_string() ); let properties = if cmd.properties.is_empty() { " " } else { " `[properties]` " }; let hint = if cmd.hint.is_empty() { &cmd.long_hint } else { &cmd.hint }; - let heading = format!( "## .{}{subjects}{properties}\n__{}__\n", name, hint ); + let heading = format!( "## .{name}{subjects}{properties}\n__{hint}__\n" ); let hint = if cmd.long_hint.is_empty() { &cmd.hint } else { &cmd.long_hint }; let full_subjects = cmd @@ -73,8 +88,8 @@ mod private format! ( "{heading}\n{}{}\n\n{hint}\n", - if cmd.subjects.is_empty() { "".to_string() } else { format!( "\n\nSubjects:{}", &full_subjects ) }, - if cmd.properties.is_empty() { "".to_string() } else { format!( "\n\nProperties:{}",&full_properties ) }, + if cmd.subjects.is_empty() { String::new() } else { format!( "\n\nSubjects:{}", &full_subjects ) }, + if cmd.properties.is_empty() { String::new() } else { format!( "\n\nProperties:{}",&full_properties ) }, ) }) diff --git a/module/move/wca/src/ca/grammar/command.rs b/module/move/wca/src/ca/grammar/command.rs index ad34d5ef85..e1bc974d63 100644 --- a/module/move/wca/src/ca/grammar/command.rs +++ b/module/move/wca/src/ca/grammar/command.rs @@ -1,11 +1,14 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; - use std::collections::{ HashMap }; + use std::collections::HashMap; use indexmap::IndexMap; use former::{ Former, StoragePreform }; use iter_tools::Itertools; + use executor::{ Routine, Handler }; /// A description of a Value in a command. Used to specify the expected type and provide a hint for the Value. /// @@ -35,7 +38,7 @@ mod private pub struct PropertyDescription { name : String, - // qqq : how to re-use ValueDescriptionFormer without additional end? + // xxx : how to re-use ValueDescriptionFormer without additional end? // #[subform_scalar] // value : ValueDescription, /// providing guidance to the user for entering a valid value @@ -74,7 +77,7 @@ mod private /// # Example: /// /// ``` - /// # use wca::{ Command, Type }; + /// # use wca::{ grammar::Command, Type }; /// let command = Command::former() /// .hint( "hint" ) /// .long_hint( "long_hint" ) @@ -103,7 +106,8 @@ mod private /// Map of aliases. // Aliased key -> Original key pub properties_aliases : HashMap< String, String >, - // qqq : make it usable and remove default(?) + // aaa : make it usable and remove default(?) + // aaa : it is usable /// The type `Routine` represents the specific implementation of the routine. #[ scalar( setter = false ) ] #[ former( default = Routine::from( Handler::< _, std::convert::Infallible >::from( || { panic!( "No routine available: A handler function for the command is missing" ) } ) ) ) ] @@ -118,11 +122,11 @@ mod private { Order::Nature => { - self.properties.iter().map( | ( key, value ) | ( key, value ) ).collect() + self.properties.iter().collect() } Order::Lexicography => { - self.properties.iter().map( | ( key, value ) | ( key, value ) ).sorted_by_key( | ( k, _ ) | *k ).collect() + self.properties.iter().sorted_by_key( | ( k, _ ) | *k ).collect() } } } @@ -133,6 +137,7 @@ mod private Definition : former::FormerDefinition< Storage = < Command as former::EntityToStorage >::Storage >, { /// Setter for separate properties aliases. + #[ must_use ] pub fn property_alias< S : Into< String > >( mut self, key : S, alias : S ) -> Self { let key = key.into(); @@ -175,6 +180,7 @@ mod private /// # Returns /// /// Returns the `CommandFormer` instance with the new command routine set. + #[ must_use ] pub fn routine< I, R, F : Into< Handler< I, R > > >( mut self, f : F ) -> Self where Routine: From< Handler< I, R > >, @@ -207,6 +213,8 @@ mod private /// # Arguments /// /// * `name` - The name of the property. It should implement the `Into< String >` trait. + /// # Panics + /// qqq: doc pub fn property< IntoName >( self, name : IntoName ) -> PropertyDescriptionAsSubformer< Self, impl PropertyDescriptionAsSubformerEnd< Self > > where IntoName : Into< String >, @@ -246,8 +254,8 @@ mod private crate::mod_interface! { - exposed use Command; - exposed use CommandFormer; + orphan use Command; + orphan use CommandFormer; own use ValueDescription; own use CommandAsSubformer; @@ -256,4 +264,5 @@ crate::mod_interface! } -// qqq : use orphan instead of exposed for ALL files in the folder, dont use prelude for structs \ No newline at end of file +// aaa : use orphan instead of exposed for ALL files in the folder, dont use prelude for structs +// aaa : done. \ No newline at end of file diff --git a/module/move/wca/src/ca/grammar/dictionary.rs b/module/move/wca/src/ca/grammar/dictionary.rs index e6887aef26..3e8e0389a5 100644 --- a/module/move/wca/src/ca/grammar/dictionary.rs +++ b/module/move/wca/src/ca/grammar/dictionary.rs @@ -1,11 +1,14 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use former::Former; use indexmap::IndexMap; use iter_tools::Itertools; + use grammar::Command; - // qqq : `Former` does not handle this situation well + // xxx : `Former` does not handle this situation well // /// A collection of commands. // /// @@ -25,8 +28,6 @@ mod private pub( crate ) order : Order, } - // qqq : IDK how to integrate it into the `CommandsAggregatorFormer` - // impl DictionaryFormer { pub fn command( mut self, command : Command ) -> Self @@ -88,17 +89,18 @@ mod private } /// asd + #[ must_use ] pub fn commands( &self ) -> Vec< ( &String, &Command ) > { match self.order { Order::Nature => { - self.commands.iter().map( | ( key, value ) | ( key, value ) ).collect() + self.commands.iter().collect() } Order::Lexicography => { - self.commands.iter().map( | ( key, value ) | ( key, value ) ).sorted_by_key( | ( key, _ ) | *key ).collect() + self.commands.iter().sorted_by_key( | ( key, _ ) | *key ).collect() } } } @@ -109,5 +111,5 @@ mod private crate::mod_interface! { - exposed use Dictionary; + orphan use Dictionary; } diff --git a/module/move/wca/src/ca/grammar/types.rs b/module/move/wca/src/ca/grammar/types.rs index d5c6e971df..6bea357228 100644 --- a/module/move/wca/src/ca/grammar/types.rs +++ b/module/move/wca/src/ca/grammar/types.rs @@ -1,14 +1,13 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std::fmt:: { Display, Formatter }; - // use wtools; - // use wtools::{ error::Result, err }; - use error::err; use iter_tools::Itertools; /// Available types that can be converted to a `Value` @@ -47,6 +46,8 @@ mod private pub trait TryCast< T > { /// return casted value + /// # Errors + /// qqq: doc fn try_cast( &self, value : String ) -> error::untyped::Result< T >; } @@ -59,7 +60,7 @@ mod private /// # Example: /// /// ``` - /// # use wca::{ VerifiedCommand, Value, Args, Props }; + /// # use wca::{ VerifiedCommand, Value, executor::{ Args, Props } }; /// # use std::collections::HashMap; /// let command = VerifiedCommand /// { @@ -119,7 +120,7 @@ mod private } Value::List( list ) => { - let list = list.iter().map( | element | element.to_string() ).join( "," ); // qqq : don't hardcode ", " find way to get original separator + let list = list.iter().map( std::string::ToString::to_string ).join( "," ); write!( f, "{list}" )?; } } @@ -138,7 +139,7 @@ mod private { match value { - #[ allow( clippy::redundant_closure_call ) ] // ok because of it improve understanding what is `value` at macro call + #[ allow( clippy::redundant_closure_call, clippy::cast_possible_truncation, clippy::cast_sign_loss ) ] // ok because of it improve understanding what is `value` at macro call $value_kind( value ) => ( $cast )( value ), _ => panic!( "Unknown cast variant. Got `{value:?}` and try to cast to `{}`", stringify!( $kind ) ) } @@ -173,8 +174,8 @@ mod private { match value { - Value::List( value ) => value.into_iter().map( | x | x.into() ).collect(), - _ => panic!( "Unknown cast variant. Got `{value:?}` and try to cast to `Vec<{}>`", std::any::type_name::< T >() ) + Value::List( value ) => value.into_iter().map( std::convert::Into::into ).collect(), + _ => panic!( "Unknown cast variant. Got `{value:?}` and try to cast to `Vec<{}>`", core::any::type_name::< T >() ) } } } @@ -186,16 +187,18 @@ mod private match self { Self::String => Ok( Value::String( value ) ), - Self::Number => value.parse().map_err( | _ | err!( "Can not parse number from `{}`", value ) ).map( Value::Number ), + Self::Number => value.parse().map_err( | _ | error::untyped::format_err!( "Can not parse number from `{}`", value ) ).map( Value::Number ), Self::Path => Ok( Value::Path( value.into() ) ), - Self::Bool => Ok( Value::Bool( match value.as_str() { "1" | "true" => true, "0" | "false" => false, _ => return Err( err!( "Can not parse bool from `{}`", value ) ) } ) ), + Self::Bool => Ok( Value::Bool( match value.as_str() { "1" | "true" => true, "0" | "false" => false, _ => return Err( error::untyped::format_err!( "Can not parse bool from `{}`", value ) ) } ) ), Self::List( kind, delimeter ) => { - let values = value + let values: error::untyped::Result< Vec< Value > > = value .split( *delimeter ) .map( | val | kind.try_cast( val.into() ) ) - .collect::< error::untyped::Result< Vec< Value > > >()?; - // qqq : avoid using fish notation whenever possible. review whole crate + .collect(); + let values = values?; + // aaa : avoid using fish notation whenever possible. review whole crate + // aaa : done Ok( Value::List( values ) ) }, } diff --git a/module/move/wca/src/ca/help.rs b/module/move/wca/src/ca/help.rs index bfc8edbfe1..b48a8ed93c 100644 --- a/module/move/wca/src/ca/help.rs +++ b/module/move/wca/src/ca/help.rs @@ -1,10 +1,10 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use ca:: { - Command, - Routine, Type, formatter:: { @@ -13,20 +13,28 @@ mod private }, tool::table::format_table, }; + use verifier::VerifiedCommand; + use grammar::{ Command, Dictionary }; + use executor::Routine; use iter_tools::Itertools; use std::rc::Rc; use error::untyped::format_err; use former::Former; - // qqq : for Bohdan : it should transparent mechanist which patch list of commands, not a stand-alone mechanism + // aaa : for Bohdan : it should transparent mechanist which patch list of commands, not a stand-alone mechanism + // aaa : it is + /// Enum `LevelOfDetail` specifies the granularity of detail for rendering or processing: #[ derive( Debug, Default, Copy, Clone, PartialEq, Eq ) ] pub enum LevelOfDetail { + /// No detail (default). #[ default ] None, + /// Basic level of detail. Simple, + /// High level of detail. Detailed, } @@ -63,7 +71,18 @@ mod private pub order : Order, } - // qqq : for Barsik : make possible to change properties order + // aaa : for Barsik : make possible to change properties order + // aaa : order option + + /// Generates help content as a formatted string based on a given dictionary and options. + /// + /// This function takes a `Dictionary` of terms or commands and a `HelpGeneratorOptions` + /// struct to customize the help output, generating a user-friendly help message + /// or guide in `String` format. + /// # Panics + /// qqq: doc + #[ must_use ] + #[ allow( clippy::match_same_arms ) ] pub fn generate_help_content( dictionary : &Dictionary, o : HelpGeneratorOptions< '_ > ) -> String { struct Row @@ -88,15 +107,15 @@ mod private }; let subjects = match o.subject_detailing { - LevelOfDetail::None => "".into(), - _ if command.subjects.is_empty() => "".into(), + LevelOfDetail::None => String::new(), + _ if command.subjects.is_empty() => String::new(), LevelOfDetail::Simple => "< subjects >".into(), LevelOfDetail::Detailed => command.subjects.iter().map( | v | format!( "< {}{:?} >", if v.optional { "?" } else { "" }, v.kind ) ).collect::< Vec< _ > >().join( " " ), }; let properties = match o.property_detailing { - LevelOfDetail::None => "".into(), - _ if command.subjects.is_empty() => "".into(), + LevelOfDetail::None => String::new(), + _ if command.subjects.is_empty() => String::new(), LevelOfDetail::Simple => "< properties >".into(), LevelOfDetail::Detailed => command.properties( dictionary.order ).iter().map( |( n, v )| format!( "< {}:{}{:?} >", if v.optional { "?" } else { "" }, n, v.kind ) ).collect::< Vec< _ > >().join( " " ), }; @@ -109,10 +128,10 @@ mod private format! ( "{}{}", - if command.subjects.is_empty() { "".to_string() } else { format!( "\nSubjects:\n\t{}", &full_subjects ) }, - if command.properties.is_empty() { "".to_string() } else { format!( "\nProperties:\n\t{}",&full_properties ) } + if command.subjects.is_empty() { String::new() } else { format!( "\nSubjects:\n\t{}", &full_subjects ) }, + if command.properties.is_empty() { String::new() } else { format!( "\nProperties:\n\t{}",&full_properties ) } ) - } else { "".into() }; + } else { String::new() }; Row { @@ -165,6 +184,7 @@ mod private impl HelpVariants { /// Generates help commands + #[ allow( clippy::match_wildcard_for_single_variants ) ] pub fn generate( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Order ) { match self @@ -183,6 +203,7 @@ mod private } // .help + #[ allow( clippy::unused_self ) ] fn general_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Order ) { let phrase = "help".to_string(); @@ -247,6 +268,7 @@ mod private } // .help command_name + #[ allow( clippy::unused_self ) ] fn subject_command_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary ) { let phrase = "help".to_string(); @@ -357,7 +379,7 @@ mod private /// /// ``` /// # use wca::ca::help::{ HelpGeneratorOptions, HelpGeneratorFn }; - /// use wca::{ Command, Dictionary }; + /// use wca::grammar::{ Command, Dictionary }; /// /// fn my_help_generator( dictionary : &Dictionary, args : HelpGeneratorOptions< '_ > ) -> String /// { @@ -397,15 +419,16 @@ mod private impl HelpGeneratorFn { /// Executes the function to generate help content + #[ must_use ] pub fn exec( &self, dictionary : &Dictionary, args : HelpGeneratorOptions< '_ > ) -> String { self.0( dictionary, args ) } } - impl std::fmt::Debug for HelpGeneratorFn + impl core::fmt::Debug for HelpGeneratorFn { - fn fmt( &self, f : &mut std::fmt::Formatter< '_ > ) -> std::fmt::Result + fn fmt( &self, f : &mut core::fmt::Formatter< '_ > ) -> core::fmt::Result { f.write_str( "HelpGenerator" ) } diff --git a/module/move/wca/src/ca/input.rs b/module/move/wca/src/ca/input.rs index c2826f99ef..34d57ba2c9 100644 --- a/module/move/wca/src/ca/input.rs +++ b/module/move/wca/src/ca/input.rs @@ -1,13 +1,13 @@ mod private { - use std::io; - use std::io::Write; + use std::io::{ self, Write }; /// Ask use input from standard input. + #[ must_use ] pub fn ask( request : &str ) -> String { let mut response = String::new(); - print!( "{} : ", request ); + print!( "{request} : " ); io::stdout().flush().ok(); io::stdin().read_line( &mut response ).ok(); response.trim().to_string() @@ -78,6 +78,6 @@ mod private crate::mod_interface! { exposed use ask; - exposed use Input; - exposed use IntoInput; + orphan use Input; + orphan use IntoInput; } diff --git a/module/move/wca/src/ca/parser/command.rs b/module/move/wca/src/ca/parser/command.rs index 332c9e71f6..9d75b11655 100644 --- a/module/move/wca/src/ca/parser/command.rs +++ b/module/move/wca/src/ca/parser/command.rs @@ -25,7 +25,7 @@ mod private /// # Example: /// /// ``` - /// # use wca::ParsedCommand; + /// # use wca::parser::ParsedCommand; /// # use std::collections::HashMap; /// ParsedCommand /// { @@ -39,7 +39,7 @@ mod private /// }; /// ``` /// - /// In the above example, a `ParsedCommand` instance is created with the name "command", a single subject "subject_value", and one property "prop_name" with a raw value of "raw_prop_value". + /// In the above example, a `ParsedCommand` instance is created with the name "command", a single subject "`subject_value`", and one property "`prop_name`" with a raw value of "`raw_prop_value`". /// #[ derive( Default, Debug, Clone, PartialEq, Eq ) ] pub struct ParsedCommand @@ -57,6 +57,6 @@ mod private crate::mod_interface! { - exposed use Program; - exposed use ParsedCommand; + orphan use Program; + orphan use ParsedCommand; } diff --git a/module/move/wca/src/ca/parser/parser.rs b/module/move/wca/src/ca/parser/parser.rs index 1efe959495..4bee7321d0 100644 --- a/module/move/wca/src/ca/parser/parser.rs +++ b/module/move/wca/src/ca/parser/parser.rs @@ -1,10 +1,22 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std::collections::HashMap; + use parser::{ Program, ParsedCommand }; - use error::{ return_err }; + // use error::{ return_err }; + + #[ allow( missing_docs ) ] + #[ derive( Debug, error::typed::Error ) ] + pub enum ParserError + { + #[ error( "Internal Error: {details}" ) ] + InternalError { details: String }, + #[ error( "Unexpected input. Expected: {expected}, found {input}" ) ] + UnexpectedInput { expected: String, input: String }, + } /// `Parser` is a struct used for parsing data. #[ derive( Debug ) ] @@ -21,13 +33,16 @@ mod private /// # Returns /// /// Returns a `Result` with a `Program` containing the parsed commands if successful, or an error if parsing fails. - // qqq : use typed error - pub fn parse< As, A >( &self, args : As ) -> error::untyped::Result< Program< ParsedCommand > > + /// # Errors + /// qqq: doc + // aaa : use typed error + // aaa : done. + pub fn parse< As, A >( &self, args : As ) -> Result< Program< ParsedCommand >, ParserError > where As : IntoIterator< Item = A >, A : Into< String >, { - let args = args.into_iter().map( Into::into ).collect::< Vec< _ > >(); + let args: Vec< _ > = args.into_iter().map( Into::into ).collect(); let mut commands = vec![]; let mut i = 0; while i < args.len() @@ -45,7 +60,7 @@ mod private { if let Some( name ) = input.strip_prefix( '.' ) { - name.is_empty() || name.starts_with( '?' ) || name.chars().next().is_some_and( | c | c.is_alphanumeric() ) + name.is_empty() || name.starts_with( '?' ) || name.chars().next().is_some_and( char::is_alphanumeric ) } else { @@ -54,18 +69,18 @@ mod private } // returns ParsedCommand and relative position of the last parsed item - // qqq : use typed error - fn parse_command( args : &[ String ] ) -> error::untyped::Result< ( ParsedCommand, usize ) > + // aaa : use typed error + fn parse_command( args : &[ String ] ) -> Result< ( ParsedCommand, usize ), ParserError > { if args.is_empty() { - return_err!( "Unexpected behaviour: Try to parse command without input" ); + return Err( ParserError::InternalError { details: "Try to parse command without input".into() } ); } let mut i = 0; if !Self::valid_command_name( &args[ i ] ) { - return_err!( "Unexpected input: Expected a command, found: `{}`", args[ i ] ); + return Err( ParserError::UnexpectedInput { expected: "command".into(), input: args[ i ].clone() } ); } let name = match args[ i ].strip_prefix( '.' ).unwrap() { @@ -78,7 +93,7 @@ mod private i += relative_pos; - return Ok( + Ok( ( ParsedCommand { @@ -91,8 +106,9 @@ mod private } // returns ( subjects, properties, relative_end_pos ) - // qqq : use typed error - fn parse_command_args( args : &[ String ] ) -> error::untyped::Result< ( Vec< String >, HashMap< String, String >, usize ) > + // aaa : use typed error + // aaa : done + fn parse_command_args( args : &[ String ] ) -> Result< ( Vec< String >, HashMap< String, String >, usize ), ParserError > { let mut i = 0; @@ -125,7 +141,7 @@ mod private // prop: else { - return_err!( "Unexpected input '{}': Detected a possible property key preceding the ':' character. However, no corresponding value was found.", item ); + return Err( ParserError::UnexpectedInput { expected: "property value".into(), input: "end of input".into() } ); } } // prop : value | prop :value @@ -146,13 +162,18 @@ mod private // : else { - return_err!( "Unexpected input '{} :': Detected a possible property key preceding the ':' character. However, no corresponding value was found.", item ); + return Err( ParserError::UnexpectedInput { expected: "property value".into(), input: "end of input".into() } ); } } - else if !properties_turn { subjects.push( item.to_string() ); } - - else { return_err!( "Unexpected input: Expected `command` or `property`, found: `{}`", item ); } + else if !properties_turn + { + subjects.push( item.to_string() ); + } + else + { + return Err( ParserError::UnexpectedInput { expected: "`command` or `property`".into(), input: item.into() } ); + } i += 1; } @@ -165,5 +186,6 @@ mod private crate::mod_interface! { - exposed use Parser; + orphan use Parser; + orphan use ParserError; } diff --git a/module/move/wca/src/ca/tool/mod.rs b/module/move/wca/src/ca/tool/mod.rs index 91290592a7..3f400c96a9 100644 --- a/module/move/wca/src/ca/tool/mod.rs +++ b/module/move/wca/src/ca/tool/mod.rs @@ -7,7 +7,10 @@ crate::mod_interface! layer table; orphan use super::super::tool; - orphan use ::error_tools as error; + + // orphan use ::error_tools as error; + use ::error_tools; + orphan use ::iter_tools; // use ::strs_tools as string; // xxx : check diff --git a/module/move/wca/src/ca/tool/table.rs b/module/move/wca/src/ca/tool/table.rs index 192caa0396..b3bce748d5 100644 --- a/module/move/wca/src/ca/tool/table.rs +++ b/module/move/wca/src/ca/tool/table.rs @@ -1,9 +1,10 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; // use wtools::error::{ Result, err }; - use error::err; + // use error::err; /// Represents a table composed of multiple rows. /// @@ -69,7 +70,7 @@ mod private fn max_column_lengths( table : &Table ) -> Vec< usize > { - let num_columns = table.0.get( 0 ).map_or( 0, | row | row.0.len() ); + let num_columns = table.0.first().map_or( 0, | row | row.0.len() ); ( 0 .. num_columns ) .map( | column_index | { @@ -81,6 +82,10 @@ mod private .collect() } + #[ derive( Debug, error::typed::Error ) ] + #[ error( "Invalid table" ) ] + pub struct FormatTableError; + /// Formats a table into a readable string representation. /// /// # Arguments @@ -90,15 +95,18 @@ mod private /// # Returns /// /// * `error::untyped::Result` - A `error::untyped::Result` containing the formatted table as a `String`, or an `Error` if the table is invalid. - // qqq : use typed error - pub fn format_table< IntoTable >( table : IntoTable ) -> error::untyped::Result< String > + /// # Errors + /// qqq: doc + // aaa : use typed error + // aaa : done + pub fn format_table< IntoTable >( table : IntoTable ) -> Result< String, FormatTableError > where IntoTable : Into< Table >, { let table = table.into(); if !table.validate() { - return Err( err!( "Invalid table" ) ); + return Err( FormatTableError ); } let max_lengths = max_column_lengths( &table ); diff --git a/module/move/wca/src/ca/verifier/command.rs b/module/move/wca/src/ca/verifier/command.rs index ef8c2824b9..f52d54c897 100644 --- a/module/move/wca/src/ca/verifier/command.rs +++ b/module/move/wca/src/ca/verifier/command.rs @@ -1,13 +1,15 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; + use executor::{ Args, Props }; /// Represents a grammatically correct command with a phrase descriptor, a list of command subjects, and a set of command options. /// /// # Example: /// /// ``` - /// # use wca::{ VerifiedCommand, Value, Args, Props }; + /// # use wca::{ VerifiedCommand, Value, executor::{ Args, Props } }; /// # use std::collections::HashMap; /// VerifiedCommand /// { @@ -22,7 +24,7 @@ mod private /// }; /// ``` /// - /// In the above example, a `VerifiedCommand` instance is created with the name "command", a single subject "subject_value", and one property "prop_name" with a typed values. + /// In the above example, a `VerifiedCommand` instance is created with the name "command", a single subject "`subject_value`", and one property "`prop_name`" with a typed values. /// #[ derive( Debug, Clone ) ] pub struct VerifiedCommand @@ -46,4 +48,5 @@ crate::mod_interface! exposed use VerifiedCommand; } -// qqq : use orphan instead of exposed for ALL files in the folder, dont use prelude for structs \ No newline at end of file +// aaa : use orphan instead of exposed for ALL files in the folder, dont use prelude for structs +// aaa : done. \ No newline at end of file diff --git a/module/move/wca/src/ca/verifier/verifier.rs b/module/move/wca/src/ca/verifier/verifier.rs index a595521755..db3de37923 100644 --- a/module/move/wca/src/ca/verifier/verifier.rs +++ b/module/move/wca/src/ca/verifier/verifier.rs @@ -1,20 +1,57 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; - use ca::grammar::command::ValueDescription; - // use former::Former; + use help::{ HelpGeneratorOptions, LevelOfDetail, generate_help_content }; + use grammar::{ Dictionary, Command, command::ValueDescription }; + use executor::{ Args, Props }; use std::collections::HashMap; use indexmap::IndexMap; - // use wtools::{ error, error::Result, err }; - use error::err; - use ca::help::{ HelpGeneratorOptions, LevelOfDetail, generate_help_content }; + use verifier::VerifiedCommand; + use parser::{ Program, ParsedCommand }; + + #[ allow( missing_docs ) ] + #[ derive( Debug, error::typed::Error ) ] + pub enum VerificationError + { + #[ error + ( + "Command not found. {} {}", + if let Some( phrase ) = name_suggestion { format!( "Maybe you mean `.{phrase}`?" ) } else { "Please use `.` command to see the list of available commands.".into() }, + if let Some( info ) = command_info { format!( "Command info: `{info}`" ) } else { "".into() } + )] + CommandNotFound { name_suggestion: Option< String >, command_info: Option< String > }, + #[ error( "Fail in command `.{command_name}` while processing subjects. {error}" ) ] + Subject { command_name: String, error: SubjectError }, + #[ error( "Fail in command `.{command_name}` while processing properties. {error}" ) ] + Property { command_name: String, error: PropertyError }, + } + + #[ allow( missing_docs ) ] + #[ derive( Debug, error::typed::Error ) ] + pub enum SubjectError + { + #[ error( "Missing not optional subject" ) ] + MissingNotOptional, + #[ error( "Can not identify a subject: `{value}`" ) ] + CanNotIdentify { value: String }, + } + + #[ allow( missing_docs ) ] + #[ derive( Debug, error::typed::Error ) ] + pub enum PropertyError + { + #[ error( "Expected: {description:?}. Found: {input}" ) ] + Cast { description: ValueDescription, input: String }, + } + // xxx /// Converts a `ParsedCommand` to a `VerifiedCommand` by performing validation and type casting on values. /// /// ``` - /// # use wca::{ Command, Type, Verifier, Dictionary, ParsedCommand }; + /// # use wca::{ Type, verifier::Verifier, grammar::{ Dictionary, Command }, parser::ParsedCommand }; /// # use std::collections::HashMap; /// # fn main() -> Result< (), Box< dyn std::error::Error > > /// # { @@ -42,19 +79,23 @@ mod private /// Converts raw program to grammatically correct /// /// Converts all namespaces into it with `to_namespace` method. + /// # Errors + /// qqq: doc pub fn to_program ( &self, dictionary : &Dictionary, raw_program : Program< ParsedCommand > ) - -> error::untyped::Result< Program< VerifiedCommand > > - // qqq : use typed error + -> Result< Program< VerifiedCommand >, VerificationError > + // aaa : use typed error + // aaa : done { - let commands = raw_program.commands + let commands: Result< Vec< VerifiedCommand >, VerificationError > = raw_program.commands .into_iter() .map( | n | self.to_command( dictionary, n ) ) - .collect::< error::untyped::Result< Vec< VerifiedCommand > > >()?; + .collect(); + let commands = commands?; Ok( Program { commands } ) } @@ -109,14 +150,15 @@ mod private if Self::is_valid_command_variant( expected_subjects_count, raw_subjects_count, possible_subjects_count ) { Some( variant ) } else { None } } - // qqq : use typed error + // aaa : use typed error + // aaa : done. fn extract_subjects( command : &Command, raw_command : &ParsedCommand, used_properties : &[ &String ] ) -> - error::untyped::Result< Vec< Value > > + Result< Vec< Value >, SubjectError > { let mut subjects = vec![]; - let all_subjects = raw_command + let all_subjects: Vec< _ > = raw_command .subjects.clone().into_iter() .chain ( @@ -124,7 +166,7 @@ mod private .filter( |( key, _ )| !used_properties.contains( key ) ) .map( |( key, value )| format!( "{key}:{value}" ) ) ) - .collect::< Vec< _ > >(); + .collect(); let mut rc_subjects_iter = all_subjects.iter(); let mut current = rc_subjects_iter.next(); @@ -134,20 +176,22 @@ mod private { Some( v ) => v, None if *optional => continue, - _ => return Err( err!( "Missing not optional subject" ) ), + _ => return Err( SubjectError::MissingNotOptional ), }; subjects.push( value ); current = rc_subjects_iter.next(); } - if let Some( value ) = current { return Err( err!( "Can not identify a subject: `{}`", value ) ) } + if let Some( value ) = current { return Err( SubjectError::CanNotIdentify { value: value.clone() } ) } Ok( subjects ) } - // qqq : use typed error + // aaa : use typed error + // aaa : done. + #[ allow( clippy::manual_map ) ] fn extract_properties( command: &Command, raw_command : HashMap< String, String > ) -> - error::untyped::Result< HashMap< String, Value > > + Result< HashMap< String, Value >, PropertyError > { raw_command.into_iter() .filter_map @@ -163,9 +207,9 @@ mod private .map ( |( value_description, key, value )| - value_description.kind.try_cast( value ).map( | v | ( key.clone(), v ) ) + value_description.kind.try_cast( value.clone() ).map( | v | ( key.clone(), v ) ).map_err( | _ | PropertyError::Cast { description: value_description.clone(), input: format!( "{key}: {value}" ) } ) ) - .collect::< error::untyped::Result< HashMap< _, _ > > >() + .collect() } fn group_properties_and_their_aliases< 'a, Ks >( aliases : &'a HashMap< String, String >, used_keys : Ks ) -> Vec< &String > @@ -184,18 +228,23 @@ mod private used_keys.flat_map( | key | { - reverse_aliases.get( key ).into_iter().flatten().map( | k | *k ).chain( Some( key ) ) + reverse_aliases.get( key ).into_iter().flatten().copied().chain( Some( key ) ) }) - .collect::< Vec< _ > >() + .collect() } /// Converts raw command to grammatically correct /// /// Make sure that this command is described in the grammar and matches it(command itself and all it options too). - // qqq : use typed error + /// # Errors + /// qqq: doc + /// # Panics + /// qqq: doc + // aaa : use typed error + // aaa : done. pub fn to_command( &self, dictionary : &Dictionary, raw_command : ParsedCommand ) -> - error::untyped::Result< VerifiedCommand > + Result< VerifiedCommand, VerificationError > { if raw_command.name.ends_with( '.' ) | raw_command.name.ends_with( ".?" ) { @@ -208,34 +257,35 @@ mod private }); } let command = dictionary.command( &raw_command.name ) - .ok_or_else::< error::untyped::Error, _ > + .ok_or_else::< VerificationError, _ > ( || { #[ cfg( feature = "on_unknown_suggest" ) ] if let Some( phrase ) = Self::suggest_command( dictionary, &raw_command.name ) - { return err!( "Command not found. Maybe you mean `.{}`?", phrase ) } - err!( "Command not found. Please use `.` command to see the list of available commands." ) + { + return VerificationError::CommandNotFound { name_suggestion: Some( phrase ), command_info: None }; + } + VerificationError::CommandNotFound { name_suggestion: None, command_info: None } } )?; let Some( cmd ) = Self::check_command( command, &raw_command ) else { - error::untyped::bail! - ( - "`{}` command with specified subjects not found. Command info: `{}`", - &raw_command.name, - generate_help_content( dictionary, HelpGeneratorOptions::former().for_commands([ dictionary.command( &raw_command.name ).unwrap() ]).command_prefix( "." ).subject_detailing( LevelOfDetail::Detailed ).form() ).strip_suffix( " " ).unwrap() - ); + return Err( VerificationError::CommandNotFound + { + name_suggestion: Some( command.phrase.clone() ), + command_info: Some( generate_help_content( dictionary, HelpGeneratorOptions::former().for_commands([ dictionary.command( &raw_command.name ).unwrap() ]).command_prefix( "." ).subject_detailing( LevelOfDetail::Detailed ).form() ).strip_suffix( " " ).unwrap().into() ), + } ); }; - let properties = Self::extract_properties( cmd, raw_command.properties.clone() )?; + let properties = Self::extract_properties( cmd, raw_command.properties.clone() ).map_err( | e | VerificationError::Property { command_name: cmd.phrase.clone(), error: e } )?; let used_properties_with_their_aliases = Self::group_properties_and_their_aliases( &cmd.properties_aliases, properties.keys() ); - let subjects = Self::extract_subjects( cmd, &raw_command, &used_properties_with_their_aliases )?; + let subjects = Self::extract_subjects( cmd, &raw_command, &used_properties_with_their_aliases ).map_err( | e | VerificationError::Subject { command_name: cmd.phrase.clone(), error: e } )?; Ok( VerifiedCommand { - phrase : cmd.phrase.to_owned(), + phrase : cmd.phrase.clone(), internal_command : false, args : Args( subjects ), props : Props( properties ), @@ -248,7 +298,8 @@ mod private crate::mod_interface! { - exposed use Verifier; + orphan use Verifier; + orphan use VerificationError; // own use LevelOfDetail; // own use generate_help_content; diff --git a/module/move/wca/src/lib.rs b/module/move/wca/src/lib.rs index 7f42a20e14..2fcb2a8409 100644 --- a/module/move/wca/src/lib.rs +++ b/module/move/wca/src/lib.rs @@ -4,9 +4,6 @@ #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "doc/", "wca.md" ) ) ] -#![ allow( where_clauses_object_safety ) ] // https://github.com/chris-morgan/anymap/issues/31 -// qqq : xxx : is it neccessary? - use mod_interface::mod_interface; pub mod ca; diff --git a/module/move/wca/tests/inc/adapter.rs b/module/move/wca/tests/inc/adapter.rs deleted file mode 100644 index 33d5cd7e61..0000000000 --- a/module/move/wca/tests/inc/adapter.rs +++ /dev/null @@ -1,44 +0,0 @@ -use super::*; -use the_module::exposed::*; - -tests_impls! -{ - fn simple() - { - fn command( () : (), args : Args, props : Props) -> Result< (), () > - { - Ok( () ) - } - - fn command2( () : (), args : Args, props : Props ) -> Result< (), () > - { - Ok( () ) - } - - fn echo( () : (), args : Args, props : Props ) -> Result< (), () > - { - Ok( () ) - } - - let ca = the_module::cui( () ).command( command ).command( command2 ).command( echo.arg( "string", Type::String ) ).build(); - - a_id!( (), ca.perform( ".command2 .help" ).unwrap() ); - - a_id!( (), ca.perform( ".help command" ).unwrap() ); - a_id!( (), ca.perform( ".help command2" ).unwrap() ); - a_id!( (), ca.perform( ".help help" ).unwrap() ); - - a_id!( (), ca.perform( ".help.command" ).unwrap() ); - a_id!( (), ca.perform( ".help.command2" ).unwrap() ); - a_id!( (), ca.perform( ".help.help" ).unwrap() ); - - a_true!( ca.perform( ".help.help.help" ).is_err() ); - a_true!( ca.perform( ".echo 34" ).is_ok() ); - a_true!( ca.perform( ".echo" ).is_err() ); - } -} - -tests_index! -{ - simple -} diff --git a/module/move/wca/tests/inc/commands_aggregator/basic.rs b/module/move/wca/tests/inc/commands_aggregator/basic.rs index f7019bebf6..6c9ba72c09 100644 --- a/module/move/wca/tests/inc/commands_aggregator/basic.rs +++ b/module/move/wca/tests/inc/commands_aggregator/basic.rs @@ -1,5 +1,14 @@ use super::*; -use the_module::VerifiedCommand; +use the_module:: +{ + parser::Parser, + VerifiedCommand, + CommandsAggregator, + HelpVariants, + Type, + Error, + ValidationError, +}; // @@ -52,8 +61,7 @@ tests_impls! .perform(); a_id!( (), ca.perform( "." ).unwrap() ); - // qqq : this use case is disabled - // a_id!( (), ca.perform( ".cmd." ).unwrap() ); + a_id!( (), ca.perform( ".cmd." ).unwrap() ); } fn error_types() @@ -136,10 +144,10 @@ tests_impls! fn string_subject_with_colon() { - let dictionary = &the_module::Dictionary::former() + let dictionary = &the_module::grammar::Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -150,7 +158,7 @@ tests_impls! ) .perform(); let parser = Parser; - let grammar = the_module::Verifier; + let grammar = the_module::verifier::Verifier; let executor = the_module::Executor::former().form(); let raw_command = parser.parse( [ ".command", "qwe:rty", "nightly:true" ] ).unwrap().commands.remove( 0 ); @@ -163,10 +171,10 @@ tests_impls! fn no_prop_subject_with_colon() { - let dictionary = &the_module::Dictionary::former() + let dictionary = &the_module::grammar::Dictionary::former() .command ( - the_module::Command::former() + the_module::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -177,7 +185,7 @@ tests_impls! .form(); let parser = Parser; - let grammar = the_module::Verifier; + let grammar = the_module::verifier::Verifier; let executor = the_module::Executor::former().form(); let raw_command = parser.parse( [ ".command", "qwe:rty" ] ).unwrap().commands.remove( 0 ); @@ -190,10 +198,10 @@ tests_impls! fn optional_prop_subject_with_colon() { - let dictionary = &the_module::Dictionary::former() + let dictionary = &the_module::grammar::Dictionary::former() .command ( - the_module::Command::former() + the_module::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -205,7 +213,7 @@ tests_impls! .form(); let parser = Parser; - let grammar = the_module::Verifier; + let grammar = the_module::verifier::Verifier; let executor = the_module::Executor::former().form(); let raw_command = parser.parse( [ ".command", "qwe:rty" ] ).unwrap().commands.remove( 0 ); @@ -216,7 +224,8 @@ tests_impls! a_id!( (), executor.command( dictionary, grammar_command ).unwrap() ); } - // qqq : make the following test work + // aaa : make the following test work + // aaa : works fn subject_with_spaces() { let query = "SELECT title, links, MIN( published ) FROM Frames"; diff --git a/module/move/wca/tests/inc/commands_aggregator/callback.rs b/module/move/wca/tests/inc/commands_aggregator/callback.rs index 834426c32d..21910a6560 100644 --- a/module/move/wca/tests/inc/commands_aggregator/callback.rs +++ b/module/move/wca/tests/inc/commands_aggregator/callback.rs @@ -1,5 +1,6 @@ use super::*; use std::sync::{ Arc, Mutex }; +use the_module::CommandsAggregator; #[ test ] fn changes_state_of_local_variable_on_perform() diff --git a/module/move/wca/tests/inc/commands_aggregator/help.rs b/module/move/wca/tests/inc/commands_aggregator/help.rs index 1df2be062e..2ce5a0bca5 100644 --- a/module/move/wca/tests/inc/commands_aggregator/help.rs +++ b/module/move/wca/tests/inc/commands_aggregator/help.rs @@ -1,7 +1,10 @@ -use std::fs::{DirBuilder, File}; -use std::io::Write; -use std::path::Path; -use std::process::{Command, Stdio}; +use std:: +{ + io::Write, + path::Path, + fs::{ DirBuilder, File }, + process::{ Command, Stdio }, +}; pub fn start_sync< AP, Args, Arg, P > ( @@ -11,9 +14,14 @@ pub fn start_sync< AP, Args, Arg, P > ) -> String where AP : AsRef< Path >, Args : IntoIterator< Item = Arg >, Arg : AsRef< std::ffi::OsStr >, P : AsRef< Path >, { let ( application, path ) = ( application.as_ref(), path.as_ref() ); - let args = args.into_iter().map( | a | a.as_ref().into() ).collect::< Vec< std::ffi::OsString > >(); + let args: Vec< std::ffi::OsString > = args.into_iter().map( | a | a.as_ref().into() ).collect(); let child = Command::new( application ).args( &args ).stdout( Stdio::piped() ).stderr( Stdio::piped() ).current_dir( path ).spawn().unwrap(); let output = child.wait_with_output().unwrap(); + + if !output.status.success() + { + println!( "{}", String::from_utf8( output.stderr ).unwrap() ); + } String::from_utf8( output.stdout ).unwrap() } diff --git a/module/move/wca/tests/inc/commands_aggregator/mod.rs b/module/move/wca/tests/inc/commands_aggregator/mod.rs index ca0cdc4b5a..fedda3d681 100644 --- a/module/move/wca/tests/inc/commands_aggregator/mod.rs +++ b/module/move/wca/tests/inc/commands_aggregator/mod.rs @@ -1,16 +1,5 @@ use super::*; -use the_module:: -{ - Parser, - - CommandsAggregator, - HelpVariants, - Type, - Error, - ValidationError, -}; - mod basic; mod callback; mod help; diff --git a/module/move/wca/tests/inc/executor/command.rs b/module/move/wca/tests/inc/executor/command.rs index b1dcf7ac12..e489b90764 100644 --- a/module/move/wca/tests/inc/executor/command.rs +++ b/module/move/wca/tests/inc/executor/command.rs @@ -1,5 +1,15 @@ use super::*; -use the_module::VerifiedCommand; +use the_module:: +{ + parser::Parser, + VerifiedCommand, + executor::Context, Type, + grammar::Dictionary, + verifier::Verifier, + + Executor, + // wtools +}; // @@ -14,7 +24,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -42,7 +52,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -78,7 +88,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -121,7 +131,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "check" ) @@ -137,7 +147,7 @@ tests_impls! ) .form(); let verifier = Verifier; - let mut ctx = wca::Context::new( Mutex::new( 1 ) ); + let mut ctx = wca::executor::Context::new( Mutex::new( 1 ) ); // init executor let executor = Executor::former() .context( ctx ) @@ -160,7 +170,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) diff --git a/module/move/wca/tests/inc/executor/mod.rs b/module/move/wca/tests/inc/executor/mod.rs index 7c84cbf8a3..617cf69b75 100644 --- a/module/move/wca/tests/inc/executor/mod.rs +++ b/module/move/wca/tests/inc/executor/mod.rs @@ -1,17 +1,4 @@ use super::*; -// qqq : rid of global uses in tests -use the_module:: -{ - Parser, - - Context, Type, - Dictionary, - Verifier, - - Executor, - // wtools -}; - mod command; mod program; diff --git a/module/move/wca/tests/inc/executor/program.rs b/module/move/wca/tests/inc/executor/program.rs index de33330259..ef0f63940a 100644 --- a/module/move/wca/tests/inc/executor/program.rs +++ b/module/move/wca/tests/inc/executor/program.rs @@ -1,5 +1,15 @@ use super::*; -use the_module::VerifiedCommand; +use the_module:: +{ + parser::Parser, + VerifiedCommand, + executor::Context, Type, + grammar::Dictionary, + verifier::Verifier, + + Executor, + // wtools +}; // @@ -14,7 +24,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -47,7 +57,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "inc" ) @@ -63,7 +73,7 @@ tests_impls! ) .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "eq" ) @@ -91,7 +101,7 @@ tests_impls! let verifier = Verifier; // starts with 0 - let ctx = wca::Context::new( Mutex::new( 0 ) ); + let ctx = wca::executor::Context::new( Mutex::new( 0 ) ); // init simple executor let executor = Executor::former() .context( ctx ) diff --git a/module/move/wca/tests/inc/grammar/from_command.rs b/module/move/wca/tests/inc/grammar/from_command.rs index 9823236c0c..343cde7ffb 100644 --- a/module/move/wca/tests/inc/grammar/from_command.rs +++ b/module/move/wca/tests/inc/grammar/from_command.rs @@ -1,5 +1,14 @@ use super::*; +use the_module:: +{ + parser::Parser, + + Type, Value, + grammar::Dictionary, + verifier::Verifier, +}; + // tests_impls! @@ -13,7 +22,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -45,7 +54,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -92,7 +101,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -121,7 +130,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -156,7 +165,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -184,7 +193,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -223,7 +232,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -268,7 +277,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -297,7 +306,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -328,7 +337,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) @@ -369,7 +378,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command" ) diff --git a/module/move/wca/tests/inc/grammar/from_program.rs b/module/move/wca/tests/inc/grammar/from_program.rs index 670eaf178c..256fd6dcd9 100644 --- a/module/move/wca/tests/inc/grammar/from_program.rs +++ b/module/move/wca/tests/inc/grammar/from_program.rs @@ -1,5 +1,14 @@ use super::*; +use the_module:: +{ + parser::Parser, + + Type, Value, + grammar::Dictionary, + verifier::Verifier, +}; + // tests_impls! @@ -12,7 +21,7 @@ tests_impls! let dictionary = &Dictionary::former() .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command1" ) @@ -21,7 +30,7 @@ tests_impls! ) .command ( - wca::Command::former() + wca::grammar::Command::former() .hint( "hint" ) .long_hint( "long_hint" ) .phrase( "command2" ) diff --git a/module/move/wca/tests/inc/grammar/mod.rs b/module/move/wca/tests/inc/grammar/mod.rs index 38c94dc114..454495c496 100644 --- a/module/move/wca/tests/inc/grammar/mod.rs +++ b/module/move/wca/tests/inc/grammar/mod.rs @@ -1,12 +1,4 @@ use super::*; -use the_module:: -{ - Parser, - - Type, Value, - Dictionary, - Verifier, -}; mod from_command; mod from_program; diff --git a/module/move/wca/tests/inc/grammar/types.rs b/module/move/wca/tests/inc/grammar/types.rs index 7421fce48f..b04ab6c346 100644 --- a/module/move/wca/tests/inc/grammar/types.rs +++ b/module/move/wca/tests/inc/grammar/types.rs @@ -1,5 +1,5 @@ use super::*; -use wca::TryCast; +use the_module::{ TryCast, Type, Value }; // @@ -134,7 +134,7 @@ tests_impls! let string = Type::List( Type::String.into(), ',' ).try_cast( origin_string.into() ).unwrap(); a_id!( origin_string, string.to_string() ); - // xxx : qqq : that fails now. suggest solution + // xxx clarification is needed : qqq : that fails now. suggest solution // let origin_string = "100;3.14"; // let string = Type::List( Type::Number.into(), ';' ).try_cast( origin_string.into() ).unwrap(); // a_id!( origin_string, string.to_string() ); diff --git a/module/move/wca/tests/inc/mod.rs b/module/move/wca/tests/inc/mod.rs index c2617e9035..b51887947e 100644 --- a/module/move/wca/tests/inc/mod.rs +++ b/module/move/wca/tests/inc/mod.rs @@ -1,10 +1,6 @@ #[ allow( unused_imports ) ] use super::*; -#[ allow( unused_imports ) ] -use the_module::tool::*; -#[ allow( unused_imports ) ] -use std::collections::HashMap; #[ cfg( not( feature = "no_std" ) ) ] mod parser; @@ -15,6 +11,5 @@ mod executor; #[ cfg( not( feature = "no_std" ) ) ] mod commands_aggregator; -// qqq : for Bohdan : why commented out? resolve -// #[ cfg( not( feature = "no_std" ) ) ] -// mod adapter; +// aaa : for Bohdan : why commented out? resolve +// aaa : no longer relevant, so removed diff --git a/module/move/wca/tests/inc/parser/command.rs b/module/move/wca/tests/inc/parser/command.rs index 986ab1d0c0..7f5c1aecf4 100644 --- a/module/move/wca/tests/inc/parser/command.rs +++ b/module/move/wca/tests/inc/parser/command.rs @@ -1,4 +1,5 @@ use super::*; +use the_module::parser::{ ParsedCommand, Parser }; // diff --git a/module/move/wca/tests/inc/parser/mod.rs b/module/move/wca/tests/inc/parser/mod.rs index 456679d11a..617cf69b75 100644 --- a/module/move/wca/tests/inc/parser/mod.rs +++ b/module/move/wca/tests/inc/parser/mod.rs @@ -1,10 +1,4 @@ use super::*; -use wca:: -{ - Program, ParsedCommand, - - Parser, -}; mod command; mod program; diff --git a/module/move/wca/tests/inc/parser/program.rs b/module/move/wca/tests/inc/parser/program.rs index 081f8cc3e8..04b07c322f 100644 --- a/module/move/wca/tests/inc/parser/program.rs +++ b/module/move/wca/tests/inc/parser/program.rs @@ -1,4 +1,5 @@ use super::*; +use the_module::parser::{ Program, ParsedCommand, Parser }; // diff --git a/module/move/willbe/Cargo.toml b/module/move/willbe/Cargo.toml index 4f16918129..e647b11d88 100644 --- a/module/move/willbe/Cargo.toml +++ b/module/move/willbe/Cargo.toml @@ -61,12 +61,12 @@ flate2 = "~1.0" globwalk = "~0.8" toml_edit = "~0.14" petgraph = "~0.6" -ptree = "~0.4" +#ptree = "~0.4" rayon = "1.8.0" semver = "~1.0.0" similar = "~2.4" regex = "1.10.2" -sha-1 = "~0.10" +#sha-1 = "~0.10" tar = "~0.4" handlebars = "4.5.0" ureq = "~2.9" diff --git a/module/move/willbe/Readme.md b/module/move/willbe/Readme.md index b387b877c6..c7d2a441b9 100644 --- a/module/move/willbe/Readme.md +++ b/module/move/willbe/Readme.md @@ -1,6 +1,6 @@ -# Module:: willbe +# `Module`:: willbe [![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_willbe_push.yml/badge.svg)](https://github.com/Wandalen/wTools/actions/workflows/module_willbe_push.yml) [![docs.rs](https://img.shields.io/docsrs/willbe?color=e3e8f0&logo=docs.rs)](https://docs.rs/willbe) [![discord](https://img.shields.io/discord/872391416519737405?color=eee&logo=discord&logoColor=eee&label=ask)](https://discord.gg/m3YfbXpUUY) diff --git a/module/move/willbe/src/action/cicd_renew.rs b/module/move/willbe/src/action/cicd_renew.rs index fdf14a1216..ca46b77549 100644 --- a/module/move/willbe/src/action/cicd_renew.rs +++ b/module/move/willbe/src/action/cicd_renew.rs @@ -1,5 +1,6 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: @@ -19,7 +20,7 @@ mod private use error:: { typed::Error, - err, + // err, }; #[ derive( Debug, Error ) ] @@ -42,7 +43,13 @@ mod private // qqq : for Petro : should return Report and typed error in Result /// Generate workflows for modules in .github/workflows directory. - pub fn cicd_renew( base_path : &Path ) -> Result< (), CiCdGenerateError > + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc + #[ allow( clippy::too_many_lines, clippy::result_large_err ) ] + pub fn action( base_path : &Path ) -> Result< (), CiCdGenerateError > { let workspace_cache = Workspace::try_from( CrateDir::try_from( base_path )? )?; let packages = workspace_cache.packages(); @@ -131,13 +138,13 @@ mod private data.insert( "name", name.as_str() ); data.insert( "username_and_repository", username_and_repository.0.as_str() ); data.insert( "branch", "alpha" ); - let manifest_file = manifest_file.to_string_lossy().replace( "\\", "/" ); + let manifest_file = manifest_file.to_string_lossy().replace( '\\', "/" ); let manifest_file = manifest_file.trim_start_matches( '/' ); data.insert( "manifest_path", manifest_file ); let content = handlebars.render( "module_push", &data )?; file_write( &workflow_file_name, &content )?; - println!( "file_write : {:?}", &workflow_file_name ) + println!( "file_write : {:?}", &workflow_file_name ); } dbg!( &workflow_root ); @@ -306,7 +313,7 @@ mod private Ok( () ) } - /// Prepare params for render appropriative_branch_for template. + /// Prepare params for render `appropriative_branch_for` template. fn map_prepare_for_appropriative_branch< 'a > ( branches : &'a str, @@ -333,7 +340,7 @@ mod private { match std::fs::create_dir_all( folder ) { - Ok( _ ) => {}, + Ok( () ) => {}, Err( e ) if e.kind() == std::io::ErrorKind::AlreadyExists => {}, Err( e ) => return Err( e.into() ), } @@ -372,10 +379,10 @@ mod private .map( String::from ); if let Some( url ) = url { - return url::repo_url_extract( &url ) + url::repo_url_extract( &url ) .and_then( | url | url::git_info_extract( &url ).ok() ) .map( UsernameAndRepository ) - .ok_or_else( || err!( "Fail to parse repository url from workspace Cargo.toml")) + .ok_or_else( || error::untyped::format_err!( "Fail to parse repository url from workspace Cargo.toml")) } else { @@ -389,11 +396,11 @@ mod private break; } } - return url + url .and_then( | url | url::repo_url_extract( &url ) ) .and_then( | url | url::git_info_extract( &url ).ok() ) .map( UsernameAndRepository ) - .ok_or_else( || err!( "Fail to extract repository url") ) + .ok_or_else( || error::untyped::format_err!( "Fail to extract repository url") ) } } @@ -401,5 +408,5 @@ mod private crate::mod_interface! { - exposed use cicd_renew; + own use action; } diff --git a/module/move/willbe/src/action/deploy_renew.rs b/module/move/willbe/src/action/deploy_renew.rs index 0f1c965332..c0681cc6c7 100644 --- a/module/move/willbe/src/action/deploy_renew.rs +++ b/module/move/willbe/src/action/deploy_renew.rs @@ -1,8 +1,10 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std::path::Path; use error::{ untyped::Context }; + #[ allow( clippy::wildcard_imports ) ] use tool::template::*; /// Template for creating deploy files. @@ -17,6 +19,8 @@ mod private /// Creates am instance of `[TemplateHolder]` for deployment template. /// /// Used for properly initializing a template + #[ must_use ] + #[ allow( clippy::should_implement_trait ) ] pub fn default() -> TemplateHolder { let parameters = TemplateParameters::former() @@ -30,7 +34,7 @@ mod private { files : get_deploy_template_files(), parameters, - values : Default::default(), + values : TemplateValues::default(), parameter_storage : "./.deploy_template.toml".as_ref(), template_name : "deploy", } @@ -79,12 +83,13 @@ mod private fn dir_name_to_formatted( dir_name : &str, separator : &str ) -> String { dir_name - .replace( ' ', separator ) - .replace( '_', separator ) + .replace( [ ' ', '_' ], separator ) .to_lowercase() } /// Creates deploy template + /// # Errors + /// qqq: doc pub fn deploy_renew ( path : &Path, @@ -93,7 +98,7 @@ mod private -> error::untyped::Result< () > // qqq : typed error { - if let None = template.load_existing_params( path ) + if template.load_existing_params( path ).is_none() { let current_dir = std::env::current_dir()?; // qqq : for Petro : use file_name diff --git a/module/move/willbe/src/action/features.rs b/module/move/willbe/src/action/features.rs index 26b8701cc2..2d46a8a882 100644 --- a/module/move/willbe/src/action/features.rs +++ b/module/move/willbe/src/action/features.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: @@ -39,12 +41,13 @@ mod private impl fmt::Display for FeaturesReport { + #[ allow( clippy::match_bool ) ] fn fmt( &self, f : &mut fmt::Formatter< '_ >) -> Result< (), fmt::Error > { self.inner.iter().try_for_each ( | ( package, features ) | { - writeln!(f, "Package {}:", package)?; + writeln!(f, "Package {package}:")?; features.iter().try_for_each ( | ( feature, dependencies ) | { @@ -67,6 +70,8 @@ mod private } /// List features + /// # Errors + /// qqq: doc pub fn features( FeaturesOptions { crate_dir, with_features_deps } : FeaturesOptions ) -> error::untyped::Result< FeaturesReport > // qqq : typed error @@ -112,3 +117,4 @@ crate::mod_interface! orphan use FeaturesOptions; orphan use FeaturesReport; } +// qqq : don't use orphan here \ No newline at end of file diff --git a/module/move/willbe/src/action/list.rs b/module/move/willbe/src/action/list.rs index 6f2708217b..5bd66e940c 100644 --- a/module/move/willbe/src/action/list.rs +++ b/module/move/willbe/src/action/list.rs @@ -1,6 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std::{ fmt, str }; @@ -13,7 +15,7 @@ mod private }; use error:: { - ErrWith, err, + ErrWith, untyped::{ Context, format_err }, }; use tool::{ TreePrinter, ListNodeReport }; @@ -39,7 +41,7 @@ mod private { "tree" => ListFormat::Tree, "toposort" => ListFormat::Topological, - e => return Err( err!( "Unknown format '{}'. Available values : [tree, toposort]", e )) + e => return Err( error::untyped::format_err!( "Unknown format '{}'. Available values : [tree, toposort]", e )) }; Ok( value ) @@ -105,7 +107,7 @@ mod private { "nothing" => ListFilter::Nothing, "local" => ListFilter::Local, - e => return Err( err!( "Unknown filter '{}'. Available values : [nothing, local]", e ) ) + e => return Err( error::untyped::format_err!( "Unknown filter '{}'. Available values : [nothing, local]", e ) ) }; Ok( value ) @@ -285,7 +287,7 @@ mod private ( f, "{}", - v.iter().map( | l | l.to_string() ).collect::< Vec< _ > >().join( "\n" ) + v.iter().map( std::string::ToString::to_string ).collect::< Vec< _ > >().join( "\n" ) ), Self::List( v ) => @@ -321,6 +323,7 @@ mod private pub path : Option< ManifestFile >, } + #[ allow( clippy::trivially_copy_pass_by_ref, clippy::needless_lifetimes ) ] fn process_package_dependency< 'a > ( workspace : &Workspace, @@ -347,7 +350,7 @@ mod private name : dependency.name(), // unwrap should be safe because of `semver::VersionReq` version : dependency.req(), - path : dependency.crate_dir().map( | p | p.manifest_file() ), + path : dependency.crate_dir().map( CrateDir::manifest_file ), }; // format!( "{}+{}+{}", dependency.name(), dependency.req(), dependency.crate_dir().unwrap().manifest_file() ); // let dep_id = format!( "{}+{}+{}", dependency.name(), dependency.req(), dependency.path().as_ref().map( | p | p.join( "Cargo.toml" ) ).unwrap_or_default() ); @@ -402,7 +405,7 @@ mod private name : dep.name(), // unwrap should be safe because of `semver::VersionReq` version : dep.req(), - path : dep.crate_dir().map( | p | p.manifest_file() ), + path : dep.crate_dir().map( CrateDir::manifest_file ), }; // if this is a cycle (we have visited this node before) if visited.contains( &dep_id ) @@ -436,7 +439,7 @@ mod private /// - `Result` - A result containing the list report if successful, /// or a tuple containing the list report and error if not successful. #[ cfg_attr( feature = "tracing", tracing::instrument ) ] - pub fn list( args : ListOptions ) + pub fn list_all( args : ListOptions ) -> ResultWithReport< ListReport, error::untyped::Error > // qqq : should be specific error // qqq : use typed error @@ -462,17 +465,32 @@ mod private .package_find_by_manifest( manifest_file ) .ok_or_else( || format_err!( "Package not found in the workspace" ) ) .err_with_report( report )?; + let version = if args.info.contains( &PackageAdditionalInfo::Version ) + { + Some( package.version().to_string() ) + } + else + { + None + }; + let crate_dir = if args.info.contains( &PackageAdditionalInfo::Path ) + { + Some( package.crate_dir() ).transpose() + } + else + { + Ok( None ) + } + .err_with_report( report )?; let mut package_report = tool::ListNodeReport { name : package.name().to_string(), - // qqq : for Bohdan : too long lines - version : if args.info.contains( &PackageAdditionalInfo::Version ) { Some( package.version().to_string() ) } else { None }, - // qqq : for Bohdan : don't put multiline if into struct constructor - crate_dir : if args.info.contains( &PackageAdditionalInfo::Path ) - { Some( package.crate_dir() ).transpose() } - else - { Ok( None ) } - .err_with_report( report )?, + // aaa : for Bohdan : too long lines + // aaa : moved out + version, + // aaa : for Bohdan : don't put multiline if into struct constructor + // aaa : moved out + crate_dir, duplicate : false, normal_dependencies : vec![], dev_dependencies : vec![], @@ -527,7 +545,7 @@ mod private .collect(); for package in packages { - tree_package_report( package.manifest_file().unwrap(), &mut report, &mut visited )? + tree_package_report( package.manifest_file().unwrap(), &mut report, &mut visited )?; } let ListReport::Tree( tree ) = report else { unreachable!() }; let printer = merge_build_dependencies( tree ); @@ -611,12 +629,12 @@ mod private { if args.info.contains( &PackageAdditionalInfo::Version ) { - name.push_str( " " ); + name.push( ' ' ); name.push_str( &p.version().to_string() ); } if args.info.contains( &PackageAdditionalInfo::Path ) { - name.push_str( " " ); + name.push( ' ' ); name.push_str( &p.manifest_file()?.to_string() ); // aaa : is it safe to use unwrap here? // aaa : should be safe, but now returns an error } @@ -664,12 +682,12 @@ mod private { if args.info.contains( &PackageAdditionalInfo::Version ) { - name.push_str( " " ); + name.push( ' ' ); name.push_str( &p.version().to_string() ); } if args.info.contains( &PackageAdditionalInfo::Path ) { - name.push_str( " " ); + name.push( ' ' ); name.push_str( &p.manifest_file().unwrap().to_string() ); } } @@ -742,7 +760,7 @@ mod private } let printer : Vec< TreePrinter > = report .iter() - .map( | rep | TreePrinter::new( rep ) ) + .map( TreePrinter::new ) .collect(); printer } @@ -774,15 +792,15 @@ mod private fn rearrange_duplicates( mut report : Vec< tool::ListNodeReport > ) -> Vec< tool::TreePrinter > { let mut required_normal : collection::HashMap< usize, Vec< tool::ListNodeReport > > = collection::HashMap::new(); - for i in 0 .. report.len() + for (i, report) in report.iter_mut().enumerate() { let ( required, exist ) : ( Vec< _ >, Vec< _ > ) = std::mem::take ( - &mut report[ i ].normal_dependencies + &mut report.normal_dependencies ) .into_iter() .partition( | d | d.duplicate ); - report[ i ].normal_dependencies = exist; + report.normal_dependencies = exist; required_normal.insert( i, required ); } @@ -794,7 +812,7 @@ mod private let printer : Vec< TreePrinter > = report .iter() - .map( | rep | TreePrinter::new( rep ) ) + .map( TreePrinter::new ) .collect(); printer @@ -849,5 +867,5 @@ crate::mod_interface! /// Contains output of a single node of the action. // own use ListNodeReport; /// List packages in workspace. - orphan use list; + orphan use list_all; } diff --git a/module/move/willbe/src/action/main_header.rs b/module/move/willbe/src/action/main_header.rs index 7c1b5af526..41241c2ffb 100644 --- a/module/move/willbe/src/action/main_header.rs +++ b/module/move/willbe/src/action/main_header.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std::fmt::{ Display, Formatter }; use std::fs:: @@ -16,10 +18,11 @@ mod private use std::path::PathBuf; use regex::Regex; use entity::{ PathError, WorkspaceInitError }; + #[ allow( unused_imports ) ] use error:: { - err, - untyped::Error, + // err, + // untyped::Error, }; use workspace_md_extension::WorkspaceMdExtension; @@ -48,6 +51,7 @@ mod private impl Display for MainHeaderRenewReport { + #[ allow( clippy::collapsible_else_if ) ] fn fmt( &self, f : &mut Formatter< '_ > ) -> std::fmt::Result { if self.success @@ -86,7 +90,7 @@ mod private { /// Represents a common error. #[ error( "Common error: {0}" ) ] - Common(#[ from ] Error ), + Common( #[ from ] error::untyped::Error ), // qqq : rid of /// Represents an I/O error. #[ error( "I/O error: {0}" ) ] IO( #[ from ] std::io::Error ), @@ -116,14 +120,14 @@ mod private // aaa : done let repository_url = workspace .repository_url() - .ok_or_else::< Error, _ > - ( || err!( "repo_url not found in workspace Cargo.toml" ) )?; + .ok_or_else::< error::untyped::Error, _ > + ( || error::untyped::format_err!( "repo_url not found in workspace Cargo.toml" ) )?; let master_branch = workspace.master_branch().unwrap_or( "master".into() ); let workspace_name = workspace .workspace_name() - .ok_or_else::< Error, _ > - ( || err!( "workspace_name not found in workspace Cargo.toml" ) )?; + .ok_or_else::< error::untyped::Error, _ > + ( || error::untyped::format_err!( "workspace_name not found in workspace Cargo.toml" ) )?; let discord_url = workspace.discord_url(); @@ -140,6 +144,7 @@ mod private } /// Convert `Self`to header. + #[ allow( clippy::uninlined_format_args, clippy::wrong_self_convention ) ] fn to_header( self ) -> Result< String, MainHeaderRenewError > { let discord = self.discord_url @@ -193,7 +198,14 @@ mod private /// [![docs.rs](https://raster.shields.io/static/v1?label=docs&message=online&color=eee&logo=docsdotrs&logoColor=eee)](https://docs.rs/wtools) /// /// ``` - pub fn readme_header_renew( crate_dir : CrateDir ) + /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc + #[ allow( clippy::uninlined_format_args ) ] + pub fn action( crate_dir : CrateDir ) // -> Result< MainHeaderRenewReport, ( MainHeaderRenewReport, MainHeaderRenewError ) > -> ResultWithReport< MainHeaderRenewReport, MainHeaderRenewError > { @@ -265,7 +277,7 @@ mod private crate::mod_interface! { /// Generate header. - orphan use readme_header_renew; + own use action; /// Report. orphan use MainHeaderRenewReport; /// Error. diff --git a/module/move/willbe/src/action/publish.rs b/module/move/willbe/src/action/publish.rs index 58412a2d7a..ed6a6c90f2 100644 --- a/module/move/willbe/src/action/publish.rs +++ b/module/move/willbe/src/action/publish.rs @@ -1,6 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std::{ env, fmt, fs }; @@ -34,10 +36,10 @@ mod private writeln!( f, "Actions :" )?; for ( path, report ) in &self.packages { - let report = report.to_string().replace("\n", "\n "); + let report = report.to_string().replace('\n', "\n "); let path = if let Some( wrd ) = &self.workspace_root_dir { - path.as_ref().strip_prefix( &wrd.as_ref() ).unwrap() + path.as_ref().strip_prefix( wrd.as_ref() ).unwrap() } else { @@ -109,6 +111,7 @@ mod private /// /// # Arguments /// * `patterns` - A vector of patterns specifying the folders to search for packages. + /// * `exclude_dev_dependencies` - A boolean value indicating whether to exclude dev dependencies from manifest before publish. /// * `dry` - A boolean value indicating whether to perform a dry run. /// * `temp` - A boolean value indicating whether to use a temporary directory. /// @@ -119,6 +122,8 @@ mod private ( patterns : Vec< String >, channel : channel::Channel, + exclude_dev_dependencies : bool, + commit_changes : bool, dry : bool, temp : bool ) @@ -155,7 +160,7 @@ mod private let workspace_root_dir : AbsolutePath = workspace .workspace_root() - .try_into()?; + .into(); let packages = workspace.packages(); let packages_to_publish : Vec< String > = packages @@ -233,6 +238,8 @@ mod private .channel( channel ) .workspace_dir( CrateDir::try_from( workspace_root_dir ).unwrap() ) .option_base_temp_dir( dir.clone() ) + .exclude_dev_dependencies( exclude_dev_dependencies ) + .commit_changes( commit_changes ) .dry( dry ) .roots( roots ) .packages( queue ) diff --git a/module/move/willbe/src/action/publish_diff.rs b/module/move/willbe/src/action/publish_diff.rs index d27920c7bc..69b98be647 100644 --- a/module/move/willbe/src/action/publish_diff.rs +++ b/module/move/willbe/src/action/publish_diff.rs @@ -1,6 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use path::PathBuf; @@ -22,6 +24,7 @@ mod private pub struct PublishDiffOptions { path : PathBuf, + exclude_dev_dependencies : bool, keep_archive : Option< PathBuf >, } @@ -42,6 +45,7 @@ mod private let root_name = tree.name.clone(); let root_version = tree.version.as_ref().unwrap().clone(); + #[ allow( clippy::items_after_statements, clippy::option_map_unit_fn ) ] fn modify( diffs : &HashMap< AbsolutePath, DiffReport >, tree : &mut ListNodeReport ) { let path = tree.crate_dir.take().unwrap(); @@ -74,7 +78,7 @@ mod private for dep in &mut tree.normal_dependencies { - modify( diffs, dep ) + modify( diffs, dep ); } } modify( &self.diffs, &mut tree ); @@ -82,7 +86,7 @@ mod private let root = AbsolutePath::from( root_path ); let diff = self.diffs.get( &root ).unwrap(); let printer = TreePrinter::new( &tree ); - writeln!( f, "Tree:\n{}", printer )?; + writeln!( f, "Tree:\n{printer}" )?; if diff.has_changes() { writeln!( f, "Changes detected in `{root_name} {root_version}`:" )?; @@ -91,7 +95,7 @@ mod private { writeln!( f, "No changes found in `{root_name} {root_version}`. Files:" )?; } - write!( f, "{}", diff )?; + write!( f, "{diff}" )?; Ok( () ) } @@ -105,7 +109,7 @@ mod private let path = AbsolutePath::try_from( o.path )?; let dir = CrateDir::try_from( path.clone() )?; - let list = action::list + let list = action::list_all ( action::list::ListOptions::former() .path_to_manifest( dir ) @@ -141,21 +145,22 @@ mod private let name = &package.name()?; let version = &package.version()?; - _ = cargo::pack - ( - cargo::PackOptions::former() - .path( dir.as_ref() ) - .allow_dirty( true ) - .checking_consistency( false ) - .dry( false ).form() - )?; - let l = CrateArchive::read( packed_crate::local_path( name, version, dir )? )?; - let r = CrateArchive::download_crates_io( name, version ).unwrap(); + _ = cargo::pack + ( + cargo::PackOptions::former() + .path( dir.as_ref() ) + .allow_dirty( true ) + .checking_consistency( false ) + .exclude_dev_dependencies( o.exclude_dev_dependencies) + .dry( false ).form() + )?; + let l = CrateArchive::read( packed_crate::local_path( name, version, dir )? )?; + let r = CrateArchive::download_crates_io( name, version ).unwrap(); if let Some( out_path ) = &o.keep_archive { - _ = std::fs::create_dir_all( &out_path ); + _ = std::fs::create_dir_all( out_path ); for path in r.list() { let local_path = out_path.join( path ); @@ -171,7 +176,7 @@ mod private let report = tasks[ current_idx ].info.normal_dependencies.clone(); let printer : Vec< TreePrinter > = report .iter() - .map( | rep | TreePrinter::new( rep ) ) + .map( TreePrinter::new ) .collect(); tasks.extend( printer ); diff --git a/module/move/willbe/src/action/readme_health_table_renew.rs b/module/move/willbe/src/action/readme_health_table_renew.rs index 438c44dcd8..dff994b1d9 100644 --- a/module/move/willbe/src/action/readme_health_table_renew.rs +++ b/module/move/willbe/src/action/readme_health_table_renew.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: @@ -37,14 +39,14 @@ mod private ( regex::bytes::Regex::new ( - r#""# + r"" ).unwrap() ).ok(); CLOSE_TAG.set ( regex::bytes::Regex::new ( - r#""# + r"" ).unwrap() ).ok(); } @@ -131,6 +133,7 @@ mod private /// Structure that holds the parameters for generating a table. #[ derive( Debug ) ] + #[ allow( clippy::struct_excessive_bools ) ] struct TableOptions { // Relative path from workspace root to directory with modules @@ -151,23 +154,19 @@ mod private { let include_branches = value .get( "with_branches" ) - .map( | v | bool::from( v ) ) - .unwrap_or( true ); + .map_or( true, bool::from ); let include_stability = value .get( "with_stability" ) - .map( | v | bool::from( v ) ) - .unwrap_or( true ); + .map_or( true, bool::from ); let include_docs = value .get( "with_docs" ) - .map( | v | bool::from( v ) ) - .unwrap_or( true ); + .map_or( true, bool::from ); let include = value .get( "with_gitpod" ) - .map( | v | bool::from( v ) ) - .unwrap_or( true ); + .map_or( true, bool::from ); let b_p = value.get( "1" ); let base_path = if let Some( query::Value::String( path ) ) = value.get( "path" ).or( b_p ) @@ -200,51 +199,49 @@ mod private { return Err( HealthTableRenewError::Common( error::untyped::Error::msg( "Cannot find Cargo.toml" ))) } - else + + let mut contents = String::new(); + File::open( cargo_toml_path )?.read_to_string( &mut contents )?; + let doc = contents.parse::< Document >()?; + + let core_url = + doc + .get( "workspace" ) + .and_then( | workspace | workspace.get( "metadata" ) ) + .and_then( | metadata | metadata.get( "repo_url" ) ) + .and_then( | url | url.as_str() ) + .map( String::from ); + + let branches = + doc + .get( "workspace" ) + .and_then( | workspace | workspace.get( "metadata" ) ) + .and_then( | metadata | metadata.get( "branches" ) ) + .and_then( | branches | branches.as_array()) + .map + ( + | array | + array + .iter() + .filter_map( | value | value.as_str() ) + .map( String::from ) + .collect::< Vec< String > >() + ); + let mut user_and_repo = String::new(); + if let Some( core_url ) = &core_url { - let mut contents = String::new(); - File::open( cargo_toml_path )?.read_to_string( &mut contents )?; - let doc = contents.parse::< Document >()?; - - let core_url = - doc - .get( "workspace" ) - .and_then( | workspace | workspace.get( "metadata" ) ) - .and_then( | metadata | metadata.get( "repo_url" ) ) - .and_then( | url | url.as_str() ) - .map( String::from ); - - let branches = - doc - .get( "workspace" ) - .and_then( | workspace | workspace.get( "metadata" ) ) - .and_then( | metadata | metadata.get( "branches" ) ) - .and_then( | branches | branches.as_array()) - .map - ( - | array | - array - .iter() - .filter_map( | value | value.as_str() ) - .map( String::from ) - .collect::< Vec< String > >() - ); - let mut user_and_repo = "".to_string(); - if let Some( core_url ) = &core_url + user_and_repo = url::git_info_extract( core_url )?; + } + Ok + ( + Self { - user_and_repo = url::git_info_extract( core_url )?; + core_url : core_url.unwrap_or_default(), + user_and_repo, + branches, + workspace_root : path.to_path_buf() } - Ok - ( - Self - { - core_url : core_url.unwrap_or_default(), - user_and_repo, - branches, - workspace_root : path.to_path_buf() - } - ) - } + ) } } @@ -259,6 +256,12 @@ mod private /// will mean that at this place the table with modules located in the directory module/core will be generated. /// The tags do not disappear after generation. /// Anything between the opening and closing tag will be destroyed. + /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc // aaa : for Petro : typed errors // aaa : done pub fn readme_health_table_renew( path : &Path ) -> Result< (), HealthTableRenewError > @@ -284,8 +287,8 @@ mod private let mut tags_closures = vec![]; let mut tables = vec![]; - let open_caps = TAG_TEMPLATE.get().unwrap().captures_iter( &*contents ); - let close_caps = CLOSE_TAG.get().unwrap().captures_iter( &*contents ); + let open_caps = TAG_TEMPLATE.get().unwrap().captures_iter( &contents ); + let close_caps = CLOSE_TAG.get().unwrap().captures_iter( &contents ); // iterate by regex matches and generate table content for each dir which taken from open-tag for ( open_captures, close_captures ) in open_caps.zip( close_caps ) { @@ -324,6 +327,7 @@ mod private } /// Writes tables into a file at specified positions. + #[ allow( clippy::needless_pass_by_value ) ] fn tables_write_into_file ( tags_closures : Vec< ( usize, usize ) >, @@ -341,11 +345,11 @@ mod private ) in tags_closures.iter().zip( tables.iter() ) { - range_to_target_copy( &*contents, &mut buffer, start, *end_of_start_tag )?; + range_to_target_copy( &contents, &mut buffer, start, *end_of_start_tag )?; range_to_target_copy( con.as_bytes(), &mut buffer, 0,con.len() - 1 )?; start = *start_of_end_tag; } - range_to_target_copy( &*contents,&mut buffer,start,contents.len() - 1 )?; + range_to_target_copy( &contents,&mut buffer,start,contents.len() - 1 )?; file.set_len( 0 )?; file.seek( SeekFrom::Start( 0 ) )?; file.write_all( &buffer )?; @@ -353,7 +357,7 @@ mod private } /// Generate table from `table_parameters`. - /// Generate header, iterate over all modules in package (from table_parameters) and append row. + /// Generate header, iterate over all modules in package (from `table_parameters`) and append row. fn package_readme_health_table_generate ( workspace : &Workspace, @@ -369,7 +373,7 @@ mod private workspace .packages() )?; - let mut table = table_header_generate( parameters, &table_parameters ); + let mut table = table_header_generate( parameters, table_parameters ); for package_name in directory_names { let stability = if table_parameters.include_stability @@ -388,7 +392,7 @@ mod private { None }; - if parameters.core_url == "" + if parameters.core_url.is_empty() { let module_path = workspace .workspace_root() @@ -420,7 +424,7 @@ ensure that at least one remotest is present in git. ", &package_name, stability.as_ref(), parameters, - &table_parameters + table_parameters ) ); } @@ -429,6 +433,7 @@ ensure that at least one remotest is present in git. ", /// Return topologically sorted modules name, from packages list, in specified directory. // fn directory_names( path : PathBuf, packages : &[ WorkspacePackageRef< '_ > ] ) -> Result< Vec< String > > + #[ allow( clippy::type_complexity, clippy::unnecessary_wraps ) ] fn directory_names< 'a > ( path : PathBuf, @@ -478,7 +483,7 @@ ensure that at least one remotest is present in git. ", let module_graph = graph::construct( &module_packages_map ); let names : Vec< String > = graph::topological_sort_with_grouping( module_graph ) .into_iter() - .map + .flat_map ( | mut group | { @@ -486,7 +491,6 @@ ensure that at least one remotest is present in git. ", group } ) - .flatten() .map( | n | n.to_string() ) .collect(); @@ -511,13 +515,13 @@ ensure that at least one remotest is present in git. ", ); if table_parameters.include_stability { - let mut stability = stability_generate( &stability.as_ref().unwrap() ); + let mut stability = stability_generate( stability.as_ref().unwrap() ); stability.push_str( " |" ); rou.push_str( &stability ); } if parameters.branches.is_some() && table_parameters.include_branches { - rou.push_str( &branch_cells_generate( ¶meters, &module_name ) ); + rou.push_str( &branch_cells_generate( parameters, module_name ) ); } if table_parameters.include_docs { @@ -532,12 +536,12 @@ ensure that at least one remotest is present in git. ", } if table_parameters.include { - let path = Path::new( table_parameters.base_path.as_str() ).join( &module_name ); + let path = Path::new( table_parameters.base_path.as_str() ).join( module_name ); let p = Path::new( ¶meters.workspace_root ).join( &path ); // let path = table_parameters.base_path. - let example = if let Some( name ) = find_example_file( p.as_path(), &module_name ) + let example = if let Some( name ) = find_example_file( p.as_path(), module_name ) { - let path = path.to_string_lossy().replace( '\\', "/" ).replace( "/", "%2F" ); + let path = path.to_string_lossy().replace( '\\', "/" ).replace( '/', "%2F" ); let tmp = name.to_string_lossy().replace( '\\', "/" ); let file_name = tmp.split( '/' ).last().unwrap(); let name = file_name.strip_suffix( ".rs" ).unwrap(); @@ -552,14 +556,15 @@ ensure that at least one remotest is present in git. ", } else { - "".into() + String::new() }; - rou.push_str( &format!( " {} |", example ) ); + rou.push_str( &format!( " {example} |" ) ); } format!( "{rou}\n" ) } /// todo + #[ must_use ] pub fn find_example_file( base_path : &Path, module_name : &str ) -> Option< PathBuf > { let examples_dir = base_path.join("examples" ); @@ -568,19 +573,18 @@ ensure that at least one remotest is present in git. ", { if let Ok( entries ) = std::fs::read_dir( &examples_dir ) { - for entry in entries + for entry in entries.flatten() { - if let Ok( entry ) = entry + + let file_name = entry.file_name(); + if let Some( file_name_str ) = file_name.to_str() { - let file_name = entry.file_name(); - if let Some( file_name_str ) = file_name.to_str() + if file_name_str == format!( "{module_name}_trivial.rs" ) { - if file_name_str == format!( "{module_name}_trivial.rs" ) - { - return Some( entry.path() ) - } + return Some( entry.path() ) } } + } } } @@ -588,19 +592,20 @@ ensure that at least one remotest is present in git. ", // If module_trivial.rs doesn't exist, return any other file in the examples directory if let Ok( entries ) = std::fs::read_dir( &examples_dir ) { - for entry in entries + for entry in entries.flatten() { - if let Ok( entry ) = entry + + let file_name = entry.file_name(); + if let Some( file_name_str ) = file_name.to_str() { - let file_name = entry.file_name(); - if let Some( file_name_str ) = file_name.to_str() + if std::path::Path::new( file_name_str ) + .extension() + .map_or( false, | ext | ext.eq_ignore_ascii_case( "rs" ) ) { - if file_name_str.ends_with( ".rs" ) - { - return Some( entry.path() ) - } + return Some( entry.path() ) } } + } } @@ -608,6 +613,7 @@ ensure that at least one remotest is present in git. ", } /// Generate stability cell based on stability + #[ must_use ] pub fn stability_generate( stability : &Stability ) -> String { match stability @@ -642,7 +648,7 @@ ensure that at least one remotest is present in git. ", { for branch in branches { - header.push_str( format!( " {} |", branch ).as_str() ); + header.push_str( format!( " {branch} |" ).as_str() ); separator.push_str( "--------|" ); } } @@ -660,7 +666,7 @@ ensure that at least one remotest is present in git. ", separator.push_str( ":------:|" ); } - format!( "{}\n{}\n", header, separator ) + format!( "{header}\n{separator}\n" ) } /// Generate cells for each branch @@ -703,10 +709,7 @@ ensure that at least one remotest is present in git. ", target.extend_from_slice( &source[ from..= to ] ); return Ok( () ) } - else - { - Err( HealthTableRenewError::Common( error::untyped::Error::msg( "Incorrect indexes" ))) - } + Err( HealthTableRenewError::Common( error::untyped::Error::msg( "Incorrect indexes" ))) } } diff --git a/module/move/willbe/src/action/readme_modules_headers_renew.rs b/module/move/willbe/src/action/readme_modules_headers_renew.rs index 9b613d97fa..33b12bc29b 100644 --- a/module/move/willbe/src/action/readme_modules_headers_renew.rs +++ b/module/move/willbe/src/action/readme_modules_headers_renew.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: { @@ -20,11 +22,11 @@ mod private use package::Package; use error:: { - err, + // err, untyped:: { // Result, - Error as wError, + // Error as wError, Context, }, }; @@ -101,7 +103,7 @@ mod private { /// Represents a common error. #[ error( "Common error: {0}" ) ] - Common(#[ from ] wError ), + Common(#[ from ] error::untyped::Error ), // qqq : rid of /// Represents an I/O error. #[ error( "I/O error: {0}" ) ] IO( #[ from ] std::io::Error ), @@ -130,9 +132,10 @@ mod private { /// Create `ModuleHeader` instance from the folder where Cargo.toml is stored. - fn from_cargo_toml< 'a > + #[ allow( clippy::needless_pass_by_value ) ] + fn from_cargo_toml ( - package : Package< 'a >, + package : Package< '_ >, default_discord_url : &Option< String >, ) -> Result< Self, ModulesHeadersRenewError > @@ -140,7 +143,7 @@ mod private let stability = package.stability()?; let module_name = package.name()?; let repository_url = package.repository()? - .ok_or_else::< wError, _ >( || err!( "Fail to find repository_url in module`s Cargo.toml" ) )?; + .ok_or_else::< error::untyped::Error, _ >( || error::untyped::format_err!( "Fail to find repository_url in module`s Cargo.toml" ) )?; let discord_url = package .discord_url()? @@ -159,6 +162,7 @@ mod private } /// Convert `ModuleHeader`to header. + #[ allow( clippy::uninlined_format_args, clippy::wrong_self_convention ) ] fn to_header( self, workspace_path : &str ) -> Result< String, ModulesHeadersRenewError > { let discord = self.discord_url.map( | discord_url | @@ -172,7 +176,7 @@ mod private let repo_url = url::repo_url_extract( &self.repository_url ) .and_then( | r | url::git_info_extract( &r ).ok() ) - .ok_or_else::< wError, _ >( || err!( "Fail to parse repository url" ) )?; + .ok_or_else::< error::untyped::Error, _ >( || error::untyped::format_err!( "Fail to parse repository url" ) )?; let example= if let Some( name ) = find_example_file ( self.module_path.as_path(), @@ -181,7 +185,7 @@ mod private { let relative_path = pth::path::path_relative ( - workspace_path.try_into().unwrap(), + workspace_path.into(), name ) .to_string_lossy() @@ -190,7 +194,7 @@ mod private let relative_path = relative_path.replace( "\\", "/" ); // aaa : for Petro : use path_toools // aaa : used - let p = relative_path.replace( "/","%2F" ); + let p = relative_path.replace( '/',"%2F" ); format! ( " [![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={},RUN_POSTFIX=--example%20{}/https://github.com/{})", @@ -201,7 +205,7 @@ mod private } else { - "".into() + String::new() }; Ok( format! ( @@ -239,6 +243,12 @@ mod private /// [![experimental](https://raster.shields.io/static/v1?label=&message=experimental&color=orange)](https://github.com/emersion/stability-badges#experimental) | [![rust-status](https://github.com/Username/test/actions/workflows/ModuleChainOfPackagesAPush.yml/badge.svg)](https://github.com/Username/test/actions/workflows/ModuleChainOfPackagesAPush.yml)[![docs.rs](https://img.shields.io/docsrs/_chain_of_packages_a?color=e3e8f0&logo=docs.rs)](https://docs.rs/_chain_of_packages_a)[![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=sample%2Frust%2F_chain_of_packages_a_trivial%2Fsrc%2Fmain.rs,RUN_POSTFIX=--example%20_chain_of_packages_a_trivial/https://github.com/Username/test) /// /// ``` + /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc pub fn readme_modules_headers_renew( crate_dir : CrateDir ) -> ResultWithReport< ModulesHeadersRenewReport, ModulesHeadersRenewError > // -> Result< ModulesHeadersRenewReport, ( ModulesHeadersRenewReport, ModulesHeadersRenewError ) > @@ -253,7 +263,7 @@ mod private let paths : Vec< AbsolutePath > = workspace .packages() - .filter_map( | p | p.manifest_file().ok().and_then( | a | Some( a.inner() ) ) ) + .filter_map( | p | p.manifest_file().ok().map( crate::entity::files::ManifestFile::inner ) ) .collect(); report.found_files = paths @@ -269,7 +279,7 @@ mod private .join ( repository::readme_path( path.parent().unwrap().as_ref() ) - // .ok_or_else::< wError, _ >( || err!( "Fail to find README.md at {}", &path ) ) + // .ok_or_else::< error::untyped::Error, _ >( || error::untyped::format_err!( "Fail to find README.md at {}", &path ) ) .err_with_report( &report )? ); @@ -285,7 +295,7 @@ mod private ) .err_with_report( &report )?; - let header = ModuleHeader::from_cargo_toml( pakage.into(), &discord_url ) + let header = ModuleHeader::from_cargo_toml( pakage, &discord_url ) .err_with_report( &report )?; let mut file = OpenOptions::new() @@ -324,6 +334,7 @@ mod private Ok( report ) } + #[ allow( clippy::uninlined_format_args ) ] fn header_content_generate< 'a > ( content : &'a str, @@ -340,7 +351,7 @@ mod private .unwrap() .replace ( - &content, + content, &format! ( "\n{}\n", diff --git a/module/move/willbe/src/action/test.rs b/module/move/willbe/src/action/test.rs index be0b90405c..2e23df5108 100644 --- a/module/move/willbe/src/action/test.rs +++ b/module/move/willbe/src/action/test.rs @@ -1,6 +1,7 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use entity::test::{ TestPlan, TestOptions, TestsReport, tests_run }; @@ -31,6 +32,7 @@ mod private /// - The `exclude_features` field is a vector of strings representing the names of features to exclude when running tests. /// - The `include_features` field is a vector of strings representing the names of features to include when running tests. #[ derive( Debug, Former ) ] + #[ allow( clippy::struct_excessive_bools ) ] pub struct TestsCommandOptions { dir : AbsolutePath, @@ -63,15 +65,21 @@ mod private /// It is possible to enable and disable various features of the crate. /// The function also has the ability to run tests in parallel using `Rayon` crate. /// The result of the tests is written to the structure `TestsReport` and returned as a result of the function execution. + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc // zzz : it probably should not be here // xxx : use newtype + #[ allow( clippy::too_many_lines ) ] pub fn test( o : TestsCommandOptions, dry : bool ) -> ResultWithReport< TestsReport, Error > // qqq : for Petro : typed error // -> Result< TestsReport, ( TestsReport, Error ) > { - // qqq : incapsulate progress bar logic into some function of struct. don't keep it here + // aaa : incapsulate progress bar logic into some function of struct. don't keep it here // aaa : done let mut report = TestsReport::default(); @@ -123,6 +131,7 @@ Try to install it with `rustup install {}` command(-s)", data_type::Either::Right( manifest ) => CrateDir::from( manifest ) }; + #[ allow( clippy::useless_conversion ) ] let workspace = Workspace ::try_from( CrateDir::try_from( path.clone() ).err_with_report( &report )? ) .err_with_report( &report )? @@ -164,7 +173,7 @@ Try to install it with `rustup install {}` command(-s)", ).err_with_report( &report )?; println!( "{plan}" ); - // aaa : split on two functions for create plan and for execute + // aaa : split on two functions for create plan and for execute // aaa : it's already separated, look line: 203 : let result = tests_run( &options ); let temp_path = if temp diff --git a/module/move/willbe/src/action/workspace_renew.rs b/module/move/willbe/src/action/workspace_renew.rs index 58e4ad61ea..ee27334708 100644 --- a/module/move/willbe/src/action/workspace_renew.rs +++ b/module/move/willbe/src/action/workspace_renew.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std::fs; use std::path::Path; @@ -24,6 +26,7 @@ mod private impl WorkspaceTemplate { /// Returns template parameters + #[ must_use ] pub fn get_parameters( &self ) -> &TemplateParameters { &self.parameters @@ -41,9 +44,9 @@ mod private .form(); Self { - files : Default::default(), + files : WorkspaceTemplateFiles::default(), parameters, - values : Default::default(), + values : TemplateValues::default(), } } } @@ -134,7 +137,11 @@ mod private // qqq : for Petro : should return report // qqq : for Petro : should have typed error /// Creates workspace template - pub fn workspace_renew + /// # Errors + /// qqq: doc + /// # Panics + /// qqq: doc + pub fn action ( path : &Path, mut template : WorkspaceTemplate, @@ -162,7 +169,7 @@ mod private "branches", wca::Value::String ( - branches.into_iter().map( | b | format!( r#""{}""#, b ) ).join( ", " ) + branches.into_iter().map( | b | format!( r#""{b}""# ) ).join( ", " ) ) ); template.files.create_all( path, &template.values )?; @@ -172,6 +179,6 @@ mod private crate::mod_interface! { - exposed use workspace_renew; + own use action; orphan use WorkspaceTemplate; } diff --git a/module/move/willbe/src/bin/cargo-will.rs b/module/move/willbe/src/bin/cargo-will.rs index 53aa39e51e..00c223060d 100644 --- a/module/move/willbe/src/bin/cargo-will.rs +++ b/module/move/willbe/src/bin/cargo-will.rs @@ -3,11 +3,11 @@ #![ doc( html_root_url = "https://docs.rs/willbe/" ) ] #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] -#[ allow( unused_imports ) ] +#[ allow( unused_imports, clippy::wildcard_imports ) ] use::willbe::*; fn main() -> Result< (), error::untyped::Error > { let args = std::env::args().skip( 1 ).collect(); - Ok( willbe::run( args )? ) + willbe::run( args ) } diff --git a/module/move/willbe/src/bin/will.rs b/module/move/willbe/src/bin/will.rs index cbaad31299..b4c1df035a 100644 --- a/module/move/willbe/src/bin/will.rs +++ b/module/move/willbe/src/bin/will.rs @@ -6,12 +6,12 @@ #![ doc( html_root_url = "https://docs.rs/willbe/" ) ] #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] -#[ allow( unused_imports ) ] +#[ allow( unused_imports, clippy::wildcard_imports ) ] use::willbe::*; fn main() -> Result< (), error::untyped::Error > { - Ok( willbe::run( std::env::args().collect() )? ) + willbe::run( std::env::args().collect() ) } // cargo_subcommand_metadata::description!( "xxx" ); diff --git a/module/move/willbe/src/bin/willbe.rs b/module/move/willbe/src/bin/willbe.rs index 5943573a67..1ad0cfeab7 100644 --- a/module/move/willbe/src/bin/willbe.rs +++ b/module/move/willbe/src/bin/willbe.rs @@ -3,10 +3,10 @@ #![ doc( html_root_url = "https://docs.rs/willbe/" ) ] #![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/", "Readme.md" ) ) ] -#[ allow( unused_imports ) ] +#[ allow( unused_imports, clippy::wildcard_imports ) ] use::willbe::*; fn main() -> Result< (), error::untyped::Error > { - Ok( willbe::run( std::env::args().collect() )? ) + willbe::run( std::env::args().collect() ) } diff --git a/module/move/willbe/src/command/cicd_renew.rs b/module/move/willbe/src/command/cicd_renew.rs index 50b1a8de91..07f7f53d24 100644 --- a/module/move/willbe/src/command/cicd_renew.rs +++ b/module/move/willbe/src/command/cicd_renew.rs @@ -1,5 +1,6 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use error::{ untyped::Context }; @@ -7,10 +8,12 @@ mod private /// /// Generate table. /// + /// # Errors + /// qqq: doc // qqq : typed error pub fn cicd_renew() -> error::untyped::Result< () > { - action::cicd_renew + action::cicd_renew::action ( &std::env::current_dir()? ) diff --git a/module/move/willbe/src/command/deploy_renew.rs b/module/move/willbe/src/command/deploy_renew.rs index 7e1e68e476..36a90cdfe0 100644 --- a/module/move/willbe/src/command/deploy_renew.rs +++ b/module/move/willbe/src/command/deploy_renew.rs @@ -1,16 +1,21 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use wca::VerifiedCommand; use error::{ untyped::Context }; + #[ allow( clippy::wildcard_imports ) ] use action::deploy_renew::*; /// /// Create new deploy. /// + /// # Errors + /// qqq: doc // xxx : qqq : typed error + #[ allow( clippy::needless_pass_by_value ) ] pub fn deploy_renew( o : VerifiedCommand ) -> error::untyped::Result< () > { let current_dir = std::env::current_dir()?; diff --git a/module/move/willbe/src/command/features.rs b/module/move/willbe/src/command/features.rs index d57a8a7dc0..9fa2ec7596 100644 --- a/module/move/willbe/src/command/features.rs +++ b/module/move/willbe/src/command/features.rs @@ -1,5 +1,6 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use action::features::FeaturesOptions; @@ -13,7 +14,10 @@ mod private /// /// List features of a package. /// + /// # Errors + /// qqq: doc + #[ allow( clippy::needless_pass_by_value ) ] pub fn features( o : VerifiedCommand ) -> error::untyped::Result< () > // qqq : use typed error { let path : PathBuf = o.args.get_owned( 0 ).unwrap_or_else( || "./".into() ); diff --git a/module/move/willbe/src/command/list.rs b/module/move/willbe/src/command/list.rs index c1bb086099..d474c313b1 100644 --- a/module/move/willbe/src/command/list.rs +++ b/module/move/willbe/src/command/list.rs @@ -1,6 +1,8 @@ /// Internal namespace. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: @@ -20,6 +22,7 @@ mod private use former::Former; #[ derive( Former ) ] + #[ allow( clippy::struct_excessive_bools ) ] struct ListProperties { #[ former( default = ListFormat::Tree ) ] @@ -46,6 +49,8 @@ mod private /// /// List workspace packages. /// + /// # Errors + /// qqq: doc // qqq : typed error pub fn list( o : VerifiedCommand ) -> error::untyped::Result< () > @@ -80,7 +85,7 @@ mod private .dependency_categories( categories ) .form(); - match action::list( o ) + match action::list_all( o ) { Ok( report ) => { @@ -97,10 +102,10 @@ mod private Ok( () ) } - impl TryFrom< wca::Props > for ListProperties + impl TryFrom< wca::executor::Props > for ListProperties { type Error = error::untyped::Error; - fn try_from( value : wca::Props ) -> Result< Self, Self::Error > + fn try_from( value : wca::executor::Props ) -> Result< Self, Self::Error > { let mut this = Self::former(); diff --git a/module/move/willbe/src/command/main_header.rs b/module/move/willbe/src/command/main_header.rs index efd23e67c4..2e850208bc 100644 --- a/module/move/willbe/src/command/main_header.rs +++ b/module/move/willbe/src/command/main_header.rs @@ -1,14 +1,18 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; - use action; + // use action; use error::untyped::{ Error }; /// Generates header to main Readme.md file. + /// + /// # Errors + /// qqq: doc // qqq : typed error pub fn readme_header_renew() -> error::untyped::Result< () > { - match action::readme_header_renew + match crate::action::main_header::action ( CrateDir::transitive_try_from::< AbsolutePath >( CurrentPath )? ) diff --git a/module/move/willbe/src/command/mod.rs b/module/move/willbe/src/command/mod.rs index bae53834e1..5550a9233b 100644 --- a/module/move/willbe/src/command/mod.rs +++ b/module/move/willbe/src/command/mod.rs @@ -1,6 +1,7 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use wca::{ Type, CommandsAggregator, CommandsAggregatorFormer }; @@ -8,6 +9,7 @@ mod private /// Form CA commands grammar. /// + #[ allow( clippy::too_many_lines ) ] pub fn ca() -> CommandsAggregatorFormer { CommandsAggregator::former() @@ -25,6 +27,16 @@ mod private .kind( Type::String ) .optional( true ) .end() + .property( "exclude_dev_dependencies" ) + .hint( "Setting this option to true will temporarily remove development dependencies before executing the command, then restore them afterward. Default is `true`." ) + .kind( Type::Bool ) + .optional( true ) + .end() + .property( "commit_changes" ) + .hint( "Indicates whether changes should be committed. Default is `false`." ) + .kind( Type::Bool ) + .optional( true ) + .end() .property( "dry" ) .hint( "Enables 'dry run'. Does not publish, only simulates. Default is `true`." ) .kind( Type::Bool ) @@ -47,6 +59,11 @@ mod private .kind( Type::Path ) .optional( true ) .end() + .property( "exclude_dev_dependencies" ) + .hint( "Setting this option to true will temporarily remove development dependencies before executing the command, then restore them afterward. Default is `true`." ) + .kind( Type::Bool ) + .optional( true ) + .end() .property( "keep_archive" ) .hint( "Save remote package version to the specified path" ) .kind( Type::Path ) diff --git a/module/move/willbe/src/command/publish.rs b/module/move/willbe/src/command/publish.rs index a70af4265d..5b3afd8930 100644 --- a/module/move/willbe/src/command/publish.rs +++ b/module/move/willbe/src/command/publish.rs @@ -1,6 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use colored::Colorize; @@ -11,10 +13,15 @@ mod private use channel::Channel; #[ derive( Former ) ] + #[ allow( clippy::struct_excessive_bools ) ] struct PublishProperties { #[ former( default = Channel::Stable ) ] channel : Channel, + #[ former( default = false ) ] + exclude_dev_dependencies : bool, + #[ former( default = false ) ] + commit_changes : bool, #[ former( default = true ) ] dry : bool, #[ former( default = true ) ] @@ -24,6 +31,8 @@ mod private /// /// Publish package. /// + /// # Errors + /// qqq: doc pub fn publish( o : VerifiedCommand ) -> error::untyped::Result< () > // qqq : use typed error { @@ -35,14 +44,11 @@ mod private .get_owned( 0 ) .unwrap_or( std::path::PathBuf::from( "" ) ).display() ); - let prop_line = format! - ( - "{}", - o - .props - .iter() - .map( | p | format!( "{}:{}", p.0, p.1.to_string() ) ) - .collect::< Vec< _ > >().join(" ") ); + let prop_line = o + .props + .iter() + .map( | p | format!( "{}:{}", p.0, p.1 ) ) + .collect::< Vec< _ > >().join(" "); let patterns : Vec< _ > = o .args @@ -52,10 +58,12 @@ mod private let PublishProperties { channel, + exclude_dev_dependencies, + commit_changes, dry, temp } = o.props.try_into()?; - let plan = action::publish_plan( patterns, channel, dry, temp ) + let plan = action::publish_plan( patterns, channel, exclude_dev_dependencies, commit_changes, dry, temp ) .context( "Failed to plan the publication process" )?; let mut formatted_plan = String::new(); @@ -77,9 +85,9 @@ mod private if dry && !report.packages.is_empty() { - let args = if args_line.is_empty() { String::new() } else { format!(" {}", args_line) }; - let prop = if prop_line.is_empty() { String::new() } else { format!(" {}", prop_line) }; - let line = format!("will .publish{}{} dry:0", args, prop ); + let args = if args_line.is_empty() { String::new() } else { format!(" {args_line}" ) }; + let prop = if prop_line.is_empty() { String::new() } else { format!(" {prop_line}" ) }; + let line = format!("will .publish{args}{prop} dry:0" ); println!("To apply plan, call the command `{}`", line.blue() ); // aaa : for Petro : for Bohdan : bad. should be exact command with exact parameters // aaa : it`s already works @@ -95,10 +103,10 @@ mod private } } - impl TryFrom< wca::Props > for PublishProperties + impl TryFrom< wca::executor::Props > for PublishProperties { type Error = error::untyped::Error; - fn try_from( value : wca::Props ) -> Result< Self, Self::Error > + fn try_from( value : wca::executor::Props ) -> Result< Self, Self::Error > { let mut this = Self::former(); @@ -110,6 +118,10 @@ mod private else { this }; + this = if let Some( v ) = value + .get_owned( "exclude_dev_dependencies" ) { this.exclude_dev_dependencies::< bool >( v ) } else { this }; + this = if let Some( v ) = value + .get_owned( "commit_changes" ) { this.commit_changes::< bool >( v ) } else { this }; this = if let Some( v ) = value .get_owned( "dry" ) { this.dry::< bool >( v ) } else { this }; this = if let Some( v ) = value diff --git a/module/move/willbe/src/command/publish_diff.rs b/module/move/willbe/src/command/publish_diff.rs index 4691331866..a35b453b2e 100644 --- a/module/move/willbe/src/command/publish_diff.rs +++ b/module/move/willbe/src/command/publish_diff.rs @@ -1,5 +1,6 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std::fs; @@ -13,6 +14,8 @@ mod private #[ derive( former::Former ) ] struct PublishDiffProperties { + #[ former( default = false ) ] + exclude_dev_dependencies : bool, keep_archive : Option< PathBuf >, } @@ -29,14 +32,18 @@ mod private /// # Errors /// /// Returns an error if there is an issue with the command. + /// + /// # Panics + /// qqq: doc pub fn publish_diff( o : VerifiedCommand ) -> error::untyped::Result< () > // qqq : use typed error { let path : PathBuf = o.args.get_owned( 0 ).unwrap_or( std::env::current_dir()? ); - let PublishDiffProperties { keep_archive } = o.props.try_into()?; + let PublishDiffProperties { keep_archive, exclude_dev_dependencies } = o.props.try_into()?; let mut o = action::PublishDiffOptions::former() - .path( path ); + .path( path ) + .exclude_dev_dependencies( exclude_dev_dependencies ); if let Some( k ) = keep_archive.clone() { o = o.keep_archive( k ); } let o = o.form(); @@ -50,13 +57,19 @@ mod private Ok( () ) } - impl TryFrom< wca::Props > for PublishDiffProperties + impl TryFrom< wca::executor::Props > for PublishDiffProperties { type Error = error::untyped::Error; - fn try_from( value : wca::Props ) -> Result< Self, Self::Error > + fn try_from( value : wca::executor::Props ) -> Result< Self, Self::Error > { let mut this = Self::former(); + this = if let Some( v ) = value + .get_owned( "exclude_dev_dependencies" ) + { this.exclude_dev_dependencies::< bool >( v ) } + else + { this }; + this = if let Some( v ) = value .get_owned( "keep_archive" ) { this.keep_archive::< PathBuf >( v ) } diff --git a/module/move/willbe/src/command/readme_headers_renew.rs b/module/move/willbe/src/command/readme_headers_renew.rs index 9a79a2b144..86f46c5588 100644 --- a/module/move/willbe/src/command/readme_headers_renew.rs +++ b/module/move/willbe/src/command/readme_headers_renew.rs @@ -1,8 +1,10 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; - use action; - use error::{ err }; + // use action; + // use error::{ err }; use std::fmt::{ Display, Formatter }; #[ derive( Debug, Default ) ] @@ -64,8 +66,9 @@ mod private } } - /// Aggregates two commands: `generate_modules_headers` & `generate_main_header` + /// # Errors + /// qqq: doc pub fn readme_headers_renew() -> error::untyped::Result< () > // qqq : use typed error { let mut report = ReadmeHeadersRenewReport::default(); @@ -73,7 +76,7 @@ mod private let crate_dir = CrateDir::transitive_try_from::< AbsolutePath >( CurrentPath )?; let mut fail = false; - match action::readme_header_renew( crate_dir.clone() ) + match crate::action::main_header::action( crate_dir.clone() ) { Ok( r ) => { @@ -103,7 +106,7 @@ mod private if fail { eprintln!( "{report}" ); - Err( err!( "Something went wrong" ) ) + Err( error::untyped::format_err!( "Something went wrong" ) ) } else { diff --git a/module/move/willbe/src/command/readme_health_table_renew.rs b/module/move/willbe/src/command/readme_health_table_renew.rs index c91b5b6357..c569a0a1b8 100644 --- a/module/move/willbe/src/command/readme_health_table_renew.rs +++ b/module/move/willbe/src/command/readme_health_table_renew.rs @@ -1,5 +1,6 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use error::{ untyped::Context }; @@ -7,6 +8,8 @@ mod private /// /// Generate table. /// + /// # Errors + /// qqq: doc // qqq : typed error pub fn readme_health_table_renew() -> error::untyped::Result< () > { diff --git a/module/move/willbe/src/command/readme_modules_headers_renew.rs b/module/move/willbe/src/command/readme_modules_headers_renew.rs index 391205210e..bfd5ed7db1 100644 --- a/module/move/willbe/src/command/readme_modules_headers_renew.rs +++ b/module/move/willbe/src/command/readme_modules_headers_renew.rs @@ -1,10 +1,14 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; // use path::AbsolutePath; // use error::{ untyped::Error }; /// Generate headers for workspace members + /// + /// # Errors + /// qqq: doc // qqq : typed error pub fn readme_modules_headers_renew() -> error::untyped::Result< () > { diff --git a/module/move/willbe/src/command/test.rs b/module/move/willbe/src/command/test.rs index 9a05c92c89..118f44f8d6 100644 --- a/module/move/willbe/src/command/test.rs +++ b/module/move/willbe/src/command/test.rs @@ -1,6 +1,7 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use collection::HashSet; @@ -17,6 +18,7 @@ mod private use optimization::Optimization; #[ derive( Former, Debug ) ] + #[ allow( clippy::struct_excessive_bools ) ] struct TestsProperties { #[ former( default = true ) ] @@ -48,6 +50,8 @@ mod private } /// run tests in specified crate + /// # Errors + /// qqq: doc // qqq : don't use 1-prameter Result pub fn test( o : VerifiedCommand ) -> error::untyped::Result< () > // qqq : use typed error { @@ -60,15 +64,11 @@ mod private .unwrap_or( std::path::PathBuf::from( "" ) ) .display() ); - let prop_line = format! - ( - "{}", - o - .props - .iter() - .map( | p | format!( "{}:{}", p.0, p.1.to_string() ) ) - .collect::< Vec< _ > >().join(" ") - ); + let prop_line = o + .props + .iter() + .map( | p | format!( "{}:{}", p.0, p.1 ) ) + .collect::< Vec< _ > >().join(" "); let path : PathBuf = o.args.get_owned( 0 ).unwrap_or_else( || "./".into() ); let path = AbsolutePath::try_from( fs::canonicalize( path )? )?; @@ -127,9 +127,9 @@ Set at least one of them to true." ); { if dry { - let args = if args_line.is_empty() { String::new() } else { format!(" {}", args_line) }; - let prop = if prop_line.is_empty() { String::new() } else { format!(" {}", prop_line) }; - let line = format!("will .publish{}{} dry:0", args, prop); + let args = if args_line.is_empty() { String::new() } else { format!(" {args_line}" ) }; + let prop = if prop_line.is_empty() { String::new() } else { format!(" {prop_line}" ) }; + let line = format!( "will .publish{args}{prop} dry:0" ); println!("To apply plan, call the command `{}`", line.blue()); } else @@ -147,10 +147,10 @@ Set at least one of them to true." ); } } - impl TryFrom< wca::Props > for TestsProperties + impl TryFrom< wca::executor::Props > for TestsProperties { type Error = error::untyped::Error; - fn try_from( value : wca::Props ) -> Result< Self, Self::Error > + fn try_from( value : wca::executor::Props ) -> Result< Self, Self::Error > { let mut this = Self::former(); @@ -192,4 +192,4 @@ crate::mod_interface! { /// run tests in specified crate exposed use test; -} \ No newline at end of file +} diff --git a/module/move/willbe/src/command/workspace_renew.rs b/module/move/willbe/src/command/workspace_renew.rs index 7baa1515f6..a77254accd 100644 --- a/module/move/willbe/src/command/workspace_renew.rs +++ b/module/move/willbe/src/command/workspace_renew.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use former::Former; @@ -17,13 +19,15 @@ mod private /// /// Create new workspace. /// + /// # Errors + /// qqq: doc // qqq : typed error pub fn workspace_renew( o : VerifiedCommand ) -> error::untyped::Result< () > // qqq : use typed error { let WorkspaceNewProperties { repository_url, branches } = o.props.try_into()?; let template = WorkspaceTemplate::default(); - action::workspace_renew + action::workspace_renew::action ( &std::env::current_dir()?, template, @@ -33,11 +37,11 @@ mod private .context( "Fail to create workspace" ) } - impl TryFrom< wca::Props > for WorkspaceNewProperties + impl TryFrom< wca::executor::Props > for WorkspaceNewProperties { type Error = error::untyped::Error; - fn try_from( value : wca::Props ) -> std::result::Result< Self, Self::Error > + fn try_from( value : wca::executor::Props ) -> std::result::Result< Self, Self::Error > { let mut this = Self::former(); diff --git a/module/move/willbe/src/entity/channel.rs b/module/move/willbe/src/entity/channel.rs index cb45418c06..92aa9f95d7 100644 --- a/module/move/willbe/src/entity/channel.rs +++ b/module/move/willbe/src/entity/channel.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: { @@ -9,6 +11,7 @@ mod private use path::Path; use collection::HashSet; use error::untyped::{ Error }; + #[ allow( clippy::wildcard_imports ) ] use process_tools::process::*; /// The `Channel` enum represents different release channels for rust. @@ -51,6 +54,9 @@ mod private /// Retrieves a list of available channels. /// /// This function takes a path and returns a `Result` with a vector of strings representing the available channels. + /// + /// # Errors + /// qqq: doc // qqq : typed error pub fn available_channels< P >( path : P ) -> error::untyped::Result< HashSet< Channel > > where @@ -61,7 +67,7 @@ mod private .bin_path( program ) .args( options.into_iter().map( OsString::from ).collect::< Vec< _ > >() ) .current_path( path.as_ref().to_path_buf() ) - .run().map_err::< Error, _ >( | report | err!( report.to_string() ) )?; + .run().map_err::< Error, _ >( | report | error::untyped::format_err!( report.to_string() ) )?; let list = report .out diff --git a/module/move/willbe/src/entity/code.rs b/module/move/willbe/src/entity/code.rs index 5c8418bad8..0faf0cdf27 100644 --- a/module/move/willbe/src/entity/code.rs +++ b/module/move/willbe/src/entity/code.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: @@ -17,7 +19,9 @@ mod private pub trait AsCode { /// Converts the object to its code representation. - fn as_code< 'a >( &'a self ) -> std::io::Result< Cow< 'a, str > >; + /// # Errors + /// qqq: doc + fn as_code( &self ) -> std::io::Result< Cow< '_, str > >; } /// A trait for retrieving an iterator over items of a source file. diff --git a/module/move/willbe/src/entity/dependency.rs b/module/move/willbe/src/entity/dependency.rs index 337ecb01a2..128a946061 100644 --- a/module/move/willbe/src/entity/dependency.rs +++ b/module/move/willbe/src/entity/dependency.rs @@ -1,6 +1,7 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; // use crates_tools::CrateArchive; @@ -25,6 +26,7 @@ mod private /// The file system path for a local path dependency. /// Only produced on cargo 1.51+ + #[ must_use ] pub fn crate_dir( &self ) -> Option< CrateDir > { match &self.inner.path @@ -35,12 +37,14 @@ mod private } /// Name as given in the Cargo.toml. + #[ must_use ] pub fn name( &self ) -> String { self.inner.name.clone() } /// The kind of dependency this is. + #[ must_use ] pub fn kind( &self ) -> DependencyKind { match self.inner.kind @@ -53,6 +57,7 @@ mod private } /// Required version + #[ must_use ] pub fn req( &self ) -> semver::VersionReq { self.inner.req.clone() @@ -114,7 +119,7 @@ mod private { Self { - name : value.name().into(), + name : value.name(), crate_dir : value.crate_dir(), // path : value.path().clone().map( | path | AbsolutePath::try_from( path ).unwrap() ), } @@ -161,10 +166,16 @@ mod private // qqq : for Bohdan : poor description /// Recursive implementation of the `list` function - pub fn _list< 'a > + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc + #[ allow( clippy::needless_pass_by_value, clippy::implicit_hasher ) ] + pub fn _list ( workspace : &Workspace, // aaa : for Bohdan : no mut // aaa : no mut - package : &Package< 'a >, + package : &Package< '_ >, graph : &mut collection::HashMap< CrateId, collection::HashSet< CrateId > >, opts : DependenciesOptions ) @@ -183,7 +194,7 @@ mod private let manifest_file = &package.manifest_file(); let package = workspace - .package_find_by_manifest( &manifest_file ) + .package_find_by_manifest( manifest_file ) .ok_or( format_err!( "Package not found in the workspace with path : `{}`", manifest_file.as_ref().display() ) )?; let deps : collection::HashSet< _ > = package @@ -229,11 +240,14 @@ mod private /// # Returns /// /// If the operation is successful, returns a vector of `PathBuf` objects, where each `PathBuf` represents the path to a local dependency of the specified package. + /// # Errors + /// qqq: doc // qqq : typed error? - pub fn list< 'a > + #[ allow( clippy::needless_pass_by_value ) ] + pub fn list ( workspace : &mut Workspace, - package : &Package< 'a >, + package : &Package< '_ >, opts : DependenciesOptions ) // qqq : use typed error @@ -260,8 +274,13 @@ mod private } DependenciesSort::Topological => { - // qqq : too long line - graph::toposort( graph::construct( &graph ) ).map_err( | err | format_err!( "{}", err ) )?.into_iter().filter( | x | x != &root ).collect() + // aaa : too long line + // aaa : splited + graph::toposort( graph::construct( &graph ) ) + .map_err( | err | format_err!( "{}", err ) )? + .into_iter() + .filter( | x | x != &root ) + .collect() }, }; diff --git a/module/move/willbe/src/entity/diff.rs b/module/move/willbe/src/entity/diff.rs index 08b0638b77..9f6f4b7709 100644 --- a/module/move/willbe/src/entity/diff.rs +++ b/module/move/willbe/src/entity/diff.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: @@ -73,6 +75,9 @@ mod private /// # Returns /// /// Returns a new instance of the struct with the excluded items removed from the internal report. + /// # Panics + /// qqq: doc + #[ must_use ] pub fn exclude< Is, I >( mut self, items : Is ) -> Self where Is : Into< HashSet< I > >, @@ -89,11 +94,12 @@ mod private Self( map ) } - /// Checks if there are any changes in the DiffItems. + /// Checks if there are any changes in the `DiffItems`. /// /// # Returns - /// * `true` if there are changes in any of the DiffItems. - /// * `false` if all DiffItems are the same. + /// * `true` if there are changes in any of the `DiffItems`. + /// * `false` if all `DiffItems` are the same. + #[ must_use ] pub fn has_changes( &self ) -> bool { !self.0.iter().all( |( _, item )| matches!( item, DiffItem::File( Diff::Same( () ) ) )) @@ -112,9 +118,9 @@ mod private { match item { - Diff::Same( _ ) => writeln!( f, " {}", path.display() )?, - Diff::Add( _ ) => writeln!( f, "+ {} NEW", path.to_string_lossy().green() )?, - Diff::Rem( _ ) => writeln!( f, "- {} REMOVED", path.to_string_lossy().red() )?, + Diff::Same( () ) => writeln!( f, " {}", path.display() )?, + Diff::Add( () ) => writeln!( f, "+ {} NEW", path.to_string_lossy().green() )?, + Diff::Rem( () ) => writeln!( f, "- {} REMOVED", path.to_string_lossy().red() )?, }; } DiffItem::Content( items ) => @@ -127,7 +133,7 @@ mod private { match item { - Diff::Same( t ) => write!( f, "| {}", t )?, + Diff::Same( t ) => write!( f, "| {t}" )?, Diff::Add( t ) => write!( f, "| + {}", t.green() )?, Diff::Rem( t ) => write!( f, "| - {}", t.red() )?, }; @@ -156,6 +162,9 @@ mod private /// # Returns /// /// A `DiffReport` struct, representing the unique and shared attributes of the two crate archives. + /// # Panics + /// qqq: doc + #[ must_use ] pub fn crate_diff( left : &CrateArchive, right : &CrateArchive ) -> DiffReport { let mut report = DiffReport::default(); diff --git a/module/move/willbe/src/entity/features.rs b/module/move/willbe/src/entity/features.rs index 300fa7ca2f..8212fdef42 100644 --- a/module/move/willbe/src/entity/features.rs +++ b/module/move/willbe/src/entity/features.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use collection::{ BTreeSet, HashSet }; use error::untyped::{ bail }; // xxx @@ -38,7 +40,10 @@ mod private /// let feature_combinations = features_powerset( &package, power, &exclude_features, &include_features, enabled_features, false, false ); /// // Use `feature_combinations` as needed. /// ``` - + /// + /// # Errors + /// qqq: doc + #[ allow( clippy::too_many_arguments ) ] pub fn features_powerset ( package : WorkspacePackageRef< '_ >, @@ -96,6 +101,7 @@ mod private } /// Calculate estimate for `features_powerset.length` + #[ must_use ] pub fn estimate_with ( n : usize, diff --git a/module/move/willbe/src/entity/files.rs b/module/move/willbe/src/entity/files.rs index 8385e87167..b6cc1ac89a 100644 --- a/module/move/willbe/src/entity/files.rs +++ b/module/move/willbe/src/entity/files.rs @@ -1,6 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: diff --git a/module/move/willbe/src/entity/files/crate_dir.rs b/module/move/willbe/src/entity/files/crate_dir.rs index 7ea3424e56..7bbf133bfc 100644 --- a/module/move/willbe/src/entity/files/crate_dir.rs +++ b/module/move/willbe/src/entity/files/crate_dir.rs @@ -1,3 +1,7 @@ +#![ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] + + +#[ allow( clippy::wildcard_imports ) ] use crate::*; use entity:: @@ -34,6 +38,7 @@ impl CrateDir /// Returns inner type which is an absolute path. #[ inline( always ) ] + #[ must_use ] pub fn absolute_path( self ) -> AbsolutePath { self.0 @@ -41,6 +46,7 @@ impl CrateDir /// Returns path to manifest aka cargo file. #[ inline( always ) ] + #[ must_use ] pub fn manifest_file( self ) -> ManifestFile { self.into() diff --git a/module/move/willbe/src/entity/files/either.rs b/module/move/willbe/src/entity/files/either.rs index aa7fdb5863..0caa927f4f 100644 --- a/module/move/willbe/src/entity/files/either.rs +++ b/module/move/willbe/src/entity/files/either.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::wildcard_imports ) ] use crate::*; use core:: { @@ -16,13 +17,14 @@ use std:: // Result, // }; -/// Wrapper over `data_type::Either< CrateDir, ManifestFile >` with utils methods. +/// Wrapper over `data_type::Either< CrateDir, ManifestFile >` with util methods. #[ derive( Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug ) ] pub struct EitherDirOrFile( data_type::Either< CrateDir, ManifestFile > ); impl EitherDirOrFile { - /// Returns inner type which is an data_type::Either< CrateDir, ManifestFile >. + /// Returns inner type which is an `data_type::Either`< `CrateDir`, `ManifestFile` >. + #[ must_use ] pub fn inner( self ) -> data_type::Either< CrateDir, ManifestFile > { self.0 @@ -75,6 +77,7 @@ impl Deref for EitherDirOrFile { type Target = Path; + #[ allow( clippy::explicit_deref_methods ) ] fn deref( &self ) -> &Self::Target { self.0.deref() @@ -83,6 +86,7 @@ impl Deref for EitherDirOrFile impl DerefMut for EitherDirOrFile { + #[ allow( clippy::explicit_deref_methods ) ] fn deref_mut( &mut self ) -> &mut Self::Target { self.0.deref_mut() diff --git a/module/move/willbe/src/entity/files/manifest_file.rs b/module/move/willbe/src/entity/files/manifest_file.rs index 78af49e41b..149b50a365 100644 --- a/module/move/willbe/src/entity/files/manifest_file.rs +++ b/module/move/willbe/src/entity/files/manifest_file.rs @@ -1,3 +1,6 @@ +#![ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] + +#[ allow( clippy::wildcard_imports ) ] use crate::*; use entity:: @@ -42,6 +45,7 @@ impl ManifestFile /// Returns inner type whicj is an absolute path. #[ inline( always ) ] + #[ must_use ] pub fn inner( self ) -> AbsolutePath { self.0 @@ -49,6 +53,7 @@ impl ManifestFile /// Returns path to crate dir. #[ inline( always ) ] + #[ must_use ] pub fn crate_dir( self ) -> CrateDir { self.into() diff --git a/module/move/willbe/src/entity/files/source_file.rs b/module/move/willbe/src/entity/files/source_file.rs index b895d3eec2..630f434006 100644 --- a/module/move/willbe/src/entity/files/source_file.rs +++ b/module/move/willbe/src/entity/files/source_file.rs @@ -1,3 +1,7 @@ +#![ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] + + +#[ allow( clippy::wildcard_imports ) ] use crate::*; use entity:: @@ -35,6 +39,7 @@ impl SourceFile /// Returns inner type which is an absolute path. #[ inline( always ) ] + #[ must_use ] pub fn inner( self ) -> AbsolutePath { self.0 @@ -229,15 +234,15 @@ impl CodeItems for SourceFile fn items( &self ) -> impl IterTrait< '_, syn::Item > { // xxx : use closures instead of expect - let content = fs::read_to_string( self.as_ref() ).expect( &format!( "Failed to parse file {self}" ) ); - let parsed : syn::File = syn::parse_file( &content ).expect( &format!( "Failed to parse file {self}" ) ); + let content = fs::read_to_string( self.as_ref() ).unwrap_or_else( | _ | panic!( "Failed to parse file {self}" ) ); + let parsed : syn::File = syn::parse_file( &content ).unwrap_or_else( | _ | panic!( "Failed to parse file {self}" ) ); parsed.items.into_iter() } } impl AsCode for SourceFile { - fn as_code< 'a >( &'a self ) -> std::io::Result< Cow< 'a, str > > + fn as_code( &self ) -> std::io::Result< Cow< '_, str > > { Ok( Cow::Owned( std::fs::read_to_string( self.as_ref() )? ) ) } diff --git a/module/move/willbe/src/entity/git.rs b/module/move/willbe/src/entity/git.rs index eeeddfd5a4..00ba0d6b2f 100644 --- a/module/move/willbe/src/entity/git.rs +++ b/module/move/willbe/src/entity/git.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std::fmt; @@ -53,6 +55,9 @@ mod private } /// Performs a Git commit operation using the provided options + /// # Errors + /// qqq: doc + #[ allow( clippy::needless_pass_by_value ) ] pub fn perform_git_commit( o : GitOptions ) -> error::untyped::Result< ExtendedGitReport > // qqq : use typed error { diff --git a/module/move/willbe/src/entity/manifest.rs b/module/move/willbe/src/entity/manifest.rs index 4df6ead08d..89c688be5f 100644 --- a/module/move/willbe/src/entity/manifest.rs +++ b/module/move/willbe/src/entity/manifest.rs @@ -1,6 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: @@ -100,12 +102,16 @@ mod private } /// Returns path to `Cargo.toml`. + #[ must_use ] pub fn manifest_file( &self ) -> &AbsolutePath { &self.manifest_file } /// Path to directory where `Cargo.toml` located. + /// # Panics + /// qqq: doc + #[ must_use ] pub fn crate_dir( &self ) -> CrateDir { self.manifest_file.parent().unwrap().try_into().unwrap() @@ -113,6 +119,8 @@ mod private } /// Store manifest. + /// # Errors + /// qqq: doc pub fn store( &self ) -> io::Result< () > { fs::write( &self.manifest_file, self.data.to_string() )?; @@ -121,6 +129,7 @@ mod private } /// Check that the current manifest is the manifest of the package (can also be a virtual workspace). + #[ must_use ] pub fn package_is( &self ) -> bool { // let data = self.data.as_ref().ok_or_else( || ManifestError::EmptyManifestData )?; @@ -129,7 +138,8 @@ mod private } /// Check that module is local. - /// The package is defined as local if the `publish` field is set to `false' or the registers are specified. + /// The package is defined as local if the `publish` field is set to `false` or the registers are specified. + #[ must_use ] pub fn local_is( &self ) -> bool { // let data = self.data.as_ref().ok_or_else( || ManifestError::EmptyManifestData )?; @@ -137,7 +147,7 @@ mod private if data.get( "package" ).is_some() && data[ "package" ].get( "name" ).is_some() { let remote = data[ "package" ].get( "publish" ).is_none() - || data[ "package" ][ "publish" ].as_bool().or( Some( true ) ).unwrap(); + || data[ "package" ][ "publish" ].as_bool().unwrap_or( true ); return !remote; } @@ -146,6 +156,8 @@ mod private } /// Retrieves the repository URL of a package from its `Cargo.toml` file. + /// # Errors + /// qqq: doc // qqq : use typed error pub fn repo_url( crate_dir : &CrateDir ) -> error::untyped::Result< String > { @@ -168,7 +180,7 @@ mod private else { let report = tool::git::ls_remote_url( crate_dir.clone().absolute_path() )?; - url::repo_url_extract( &report.out.trim() ).ok_or_else( || format_err!( "Fail to extract repository url from git remote.") ) + url::repo_url_extract( report.out.trim() ).ok_or_else( || format_err!( "Fail to extract repository url from git remote.") ) } } else diff --git a/module/move/willbe/src/entity/package.rs b/module/move/willbe/src/entity/package.rs index 5e53b6ea19..4c5e3cd3e8 100644 --- a/module/move/willbe/src/entity/package.rs +++ b/module/move/willbe/src/entity/package.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: @@ -121,6 +123,9 @@ mod private { /// Path to `Cargo.toml` + /// # Panics + /// qqq: doc + #[ must_use ] pub fn manifest_file( &self ) -> ManifestFile { match self @@ -131,6 +136,9 @@ mod private } /// Path to folder with `Cargo.toml` + /// # Panics + /// qqq: doc + #[ must_use ] pub fn crate_dir( &self ) -> CrateDir { match self @@ -141,6 +149,10 @@ mod private } /// Package version + /// # Errors + /// qqq: doc + /// # Panics + /// qqq: doc pub fn version( &self ) -> Result< String, PackageError > { match self @@ -161,6 +173,7 @@ mod private } /// Check that module is local. + #[ must_use ] pub fn local_is( &self ) -> bool { match self @@ -179,6 +192,8 @@ mod private } /// Returns the `Manifest` + /// # Errors + /// qqq: doc pub fn manifest( &self ) -> Result< Manifest, PackageError > { match self @@ -205,14 +220,16 @@ mod private /// - `false` if there is no need to publish the package. /// /// Panics if the package is not loaded or local package is not packed. + /// # Errors + /// qqq: doc - pub fn publish_need< 'a >( package : &Package< 'a >, path : Option< path::PathBuf > ) -> Result< bool, PackageError > + pub fn publish_need( package : &Package< '_ >, path : Option< path::PathBuf > ) -> Result< bool, PackageError > { let name = package.name()?; let version = package.version()?; let local_package_path = path - .map( | p | p.join( format!( "package/{0}-{1}.crate", name, version ) ) ) - .unwrap_or( packed_crate::local_path( &name, &version, package.crate_dir() ).map_err( | _ | PackageError::LocalPath )? ); + .map( | p | p.join( format!( "package/{name}-{version}.crate" ) ) ) + .unwrap_or( packed_crate::local_path( name, &version, package.crate_dir() ).map_err( | _ | PackageError::LocalPath )? ); let local_package = CrateArchive::read( local_package_path ).map_err( | _ | PackageError::ReadArchive )?; let remote_package = match CrateArchive::download_crates_io( name, version ) diff --git a/module/move/willbe/src/entity/package_md_extension.rs b/module/move/willbe/src/entity/package_md_extension.rs index 76ffdbac88..ab31564b83 100644 --- a/module/move/willbe/src/entity/package_md_extension.rs +++ b/module/move/willbe/src/entity/package_md_extension.rs @@ -1,27 +1,42 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// Md's extension for workspace pub trait PackageMdExtension { /// Package name + /// # Errors + /// qqq: doc fn name( &self ) -> Result< &str, package::PackageError >; /// Stability + /// # Errors + /// qqq: doc fn stability( &self ) -> Result< action::readme_health_table_renew::Stability, package::PackageError >; /// Repository + /// # Errors + /// qqq: doc fn repository( &self ) -> Result< Option< String >, package::PackageError >; /// Discord url + /// # Errors + /// qqq: doc fn discord_url( &self ) -> Result< Option< String >, package::PackageError >; } impl < 'a > package::Package< 'a > { /// Package name + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc pub fn name( &self ) -> Result< &str, package::PackageError > { match self @@ -43,6 +58,9 @@ mod private } /// Stability + /// + /// # Errors + /// qqq: doc pub fn stability( &self ) -> Result< action::readme_health_table_renew::Stability, package::PackageError > { // aaa : for Petro : bad : first of all it should be in trait. also there is duplicated code @@ -78,6 +96,9 @@ mod private } /// Repository + /// + /// # Errors + /// qqq: doc pub fn repository( &self ) -> Result< Option< String >, package::PackageError > { match self @@ -93,7 +114,7 @@ mod private data[ "package" ] .get( "repository" ) .and_then( | r | r.as_str() ) - .map( | r | r.to_string()) + .map( std::string::ToString::to_string ) ) } Self::WorkspacePackageRef( package ) => @@ -104,6 +125,9 @@ mod private } /// Discord url + /// + /// # Errors + /// qqq: doc pub fn discord_url( &self ) -> Result< Option< String >, package::PackageError > { match self @@ -116,12 +140,12 @@ mod private self.package_metadata() .and_then( | m | m.get( "discord_url" ) ) .and_then( | url | url.as_str() ) - .map( | r | r.to_string() ) + .map( std::string::ToString::to_string ) ) } Self::WorkspacePackageRef( package ) => { - Ok( package.metadata()[ "discord_url" ].as_str().map( | url | url.to_string() ) ) + Ok( package.metadata()[ "discord_url" ].as_str().map( std::string::ToString::to_string ) ) } } } diff --git a/module/move/willbe/src/entity/packages.rs b/module/move/willbe/src/entity/packages.rs index 6dd4006db3..5525c8a99d 100644 --- a/module/move/willbe/src/entity/packages.rs +++ b/module/move/willbe/src/entity/packages.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: { @@ -16,6 +18,7 @@ mod private /// A configuration struct for specifying optional filters when using the /// `filter` function. It allows users to provide custom filtering /// functions for packages and dependencies. + #[ allow( clippy::type_complexity ) ] #[ derive( Default ) ] pub struct FilterMapOptions { diff --git a/module/move/willbe/src/entity/packed_crate.rs b/module/move/willbe/src/entity/packed_crate.rs index 77da22b98e..1cd95c7097 100644 --- a/module/move/willbe/src/entity/packed_crate.rs +++ b/module/move/willbe/src/entity/packed_crate.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: @@ -21,10 +23,13 @@ mod private /// /// # Returns : /// The local packed `.crate` file of the package + /// + /// # Errors + /// qqq: doc // qqq : typed error pub fn local_path< 'a >( name : &'a str, version : &'a str, crate_dir : CrateDir ) -> error::untyped::Result< PathBuf > { - let buf = format!( "package/{0}-{1}.crate", name, version ); + let buf = format!( "package/{name}-{version}.crate" ); let workspace = Workspace::try_from( crate_dir )?; let mut local_package_path = PathBuf::new(); @@ -37,6 +42,11 @@ mod private /// /// Get data of remote package from crates.io. /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc // qqq : typed error pub fn download< 'a >( name : &'a str, version : &'a str ) -> error::untyped::Result< Vec< u8 > > { @@ -45,7 +55,7 @@ mod private .timeout_write( Duration::from_secs( 5 ) ) .build(); let mut buf = String::new(); - write!( &mut buf, "https://static.crates.io/crates/{0}/{0}-{1}.crate", name, version )?; + write!( &mut buf, "https://static.crates.io/crates/{name}/{name}-{version}.crate" )?; let resp = agent.get( &buf[ .. ] ).call().context( "Get data of remote package" )?; diff --git a/module/move/willbe/src/entity/progress_bar.rs b/module/move/willbe/src/entity/progress_bar.rs index c9fef4cf07..db61b1f078 100644 --- a/module/move/willbe/src/entity/progress_bar.rs +++ b/module/move/willbe/src/entity/progress_bar.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { /// The `ProgressBar` structure is used to display progress indicators in the terminal. @@ -52,7 +53,8 @@ mod private /// # Returns /// /// A `ProgressBar` instance that can be used to update and display progress. - pub fn progress_bar< 'a >( &'a self, variants_len : u64 ) -> ProgressBar< 'a > + #[ must_use ] + pub fn progress_bar( &self, variants_len : u64 ) -> ProgressBar< '_ > { let progress_bar = { diff --git a/module/move/willbe/src/entity/publish.rs b/module/move/willbe/src/entity/publish.rs index ed1e336129..93af0e97fc 100644 --- a/module/move/willbe/src/entity/publish.rs +++ b/module/move/willbe/src/entity/publish.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std::fmt; @@ -26,7 +28,7 @@ mod private /// Options for bumping the package version. pub bump : version::BumpOptions, /// Git options related to the package. - pub git_options : entity::git::GitOptions, + pub git_options : Option< entity::git::GitOptions >, /// Options for publishing the package using Cargo. pub publish : cargo::PublishOptions, /// Indicates whether the process should be dry-run (no actual publishing). @@ -42,6 +44,9 @@ mod private package : package::Package< 'a >, channel : channel::Channel, base_temp_dir : Option< path::PathBuf >, + exclude_dev_dependencies : bool, + #[ former( default = true ) ] + commit_changes : bool, #[ former( default = true ) ] dry : bool, } @@ -58,6 +63,7 @@ mod private channel : self.channel, allow_dirty : self.dry, checking_consistency : !self.dry, + exclude_dev_dependencies : self.exclude_dev_dependencies, temp_path : self.base_temp_dir.clone(), dry : self.dry, }; @@ -73,17 +79,21 @@ mod private dependencies : dependencies.clone(), dry : self.dry, }; - let git_options = entity::git::GitOptions + let git_options = if self.commit_changes { - git_root : workspace_root, - items : dependencies.iter().chain([ &crate_dir ]).map( | d | d.clone().absolute_path().join( "Cargo.toml" ) ).collect(), - message : format!( "{}-v{}", self.package.name().unwrap(), new_version ), - dry : self.dry, - }; + Some( entity::git::GitOptions + { + git_root : workspace_root, + items : dependencies.iter().chain([ &crate_dir ]).map( | d | d.clone().absolute_path().join( "Cargo.toml" ) ).collect(), + message : format!( "{}-v{}", self.package.name().unwrap(), new_version ), + dry : self.dry, + }) + } else { None }; let publish = cargo::PublishOptions { path : crate_dir.clone().absolute_path().inner(), temp_path : self.base_temp_dir.clone(), + exclude_dev_dependencies : self.exclude_dev_dependencies, retry_count : 2, dry : self.dry, }; @@ -121,6 +131,14 @@ mod private /// Release channels for rust. pub channel : channel::Channel, + /// Setting this option to true will temporarily remove development dependencies before executing the command, then restore them afterward. + #[ allow( dead_code ) ] // former related + pub exclude_dev_dependencies : bool, + + /// Indicates whether changes should be committed. + #[ former( default = true ) ] + pub commit_changes : bool, + /// `dry` - A boolean value indicating whether to do a dry run. If set to `true`, the application performs /// a simulated run without making any actual changes. If set to `false`, the operations are actually executed. /// This property is optional and defaults to `true`. @@ -161,7 +179,7 @@ mod private .collect(); for wanted in &self.roots { - let list = action::list + let list = action::list_all ( action::list::ListOptions::former() .path_to_manifest( wanted.clone() ) @@ -173,6 +191,7 @@ mod private .map_err( |( _, _e )| fmt::Error )?; let action::list::ListReport::Tree( list ) = list else { unreachable!() }; + #[ allow( clippy::items_after_statements ) ] fn callback( name_bump_report : &collection::HashMap< &String, ( String, String ) >, mut r : tool::ListNodeReport ) -> tool::ListNodeReport { if let Some(( old, new )) = name_bump_report.get( &r.name ) @@ -188,10 +207,10 @@ mod private let printer = list; let rep : Vec< tool::ListNodeReport > = printer.iter().map( | printer | printer.info.clone() ).collect(); let list: Vec< tool::ListNodeReport > = rep.into_iter().map( | r | callback( &name_bump_report, r ) ).collect(); - let printer : Vec< tool::TreePrinter > = list.iter().map( | rep | tool::TreePrinter::new( rep ) ).collect(); + let printer : Vec< tool::TreePrinter > = list.iter().map( tool::TreePrinter::new ).collect(); let list = action::list::ListReport::Tree( printer ); - writeln!( f, "{}", list )?; + writeln!( f, "{list}" )?; } Ok( () ) @@ -246,6 +265,14 @@ mod private { plan = plan.dry( dry ); } + if let Some( exclude_dev_dependencies ) = &self.storage.exclude_dev_dependencies + { + plan = plan.exclude_dev_dependencies( *exclude_dev_dependencies ); + } + if let Some( commit_changes ) = &self.storage.commit_changes + { + plan = plan.commit_changes( *commit_changes ); + } let plan = plan .channel( channel ) .package( package ) @@ -311,11 +338,11 @@ mod private return Ok( () ) } let info = get_info.as_ref().unwrap(); - write!( f, "{}", info )?; + write!( f, "{info}" )?; if let Some( bump ) = bump { - writeln!( f, "{}", bump )?; + writeln!( f, "{bump}" )?; } if let Some( add ) = add { @@ -347,7 +374,10 @@ mod private /// # Returns /// /// * `Result` - The result of the publishing operation, including information about the publish, version bump, and git operations. - + /// + /// # Errors + /// qqq: doc + #[ allow( clippy::option_map_unit_fn ) ] pub fn perform_package_publish( instruction : PackagePublishInstruction ) -> ResultWithReport< PublishReport, Error > { let mut report = PublishReport::default(); @@ -362,45 +392,55 @@ mod private } = instruction; pack.dry = dry; bump.dry = dry; - git_options.dry = dry; + git_options.as_mut().map( | d | d.dry = dry ); publish.dry = dry; report.get_info = Some( cargo::pack( pack ).err_with_report( &report )? ); // aaa : redundant field? // aaa : removed let bump_report = version::bump( bump ).err_with_report( &report )?; report.bump = Some( bump_report.clone() ); - let git_root = git_options.git_root.clone(); - let git = match entity::git::perform_git_commit( git_options ) + + let git_root = git_options.as_ref().map( | g | g.git_root.clone() ); + if let Some( git_options ) = git_options { - Ok( git ) => git, - Err( e ) => + let git = match entity::git::perform_git_commit( git_options ) { - version::revert( &bump_report ) - .map_err( | le | format_err!( "Base error:\n{}\nRevert error:\n{}", e.to_string().replace( '\n', "\n\t" ), le.to_string().replace( '\n', "\n\t" ) ) ) - .err_with_report( &report )?; - return Err(( report, e )); - } - }; - report.add = git.add; - report.commit = git.commit; + Ok( git ) => git, + Err( e ) => + { + version::revert( &bump_report ) + .map_err( | le | format_err!( "Base error:\n{}\nRevert error:\n{}", e.to_string().replace( '\n', "\n\t" ), le.to_string().replace( '\n', "\n\t" ) ) ) + .err_with_report( &report )?; + return Err(( report, e )); + } + }; + report.add = git.add; + report.commit = git.commit; + } report.publish = match cargo::publish( publish ) { Ok( publish ) => Some( publish ), Err( e ) => { - tool::git::reset( git_root.as_ref(), true, 1, false ) - .map_err - ( - | le | - format_err!( "Base error:\n{}\nRevert error:\n{}", e.to_string().replace( '\n', "\n\t" ), le.to_string().replace( '\n', "\n\t" ) ) - ) - .err_with_report( &report )?; + if let Some( git_root ) = git_root.as_ref() + { + tool::git::reset( git_root.as_ref(), true, 1, false ) + .map_err + ( + | le | + format_err!( "Base error:\n{}\nRevert error:\n{}", e.to_string().replace( '\n', "\n\t" ), le.to_string().replace( '\n', "\n\t" ) ) + ) + .err_with_report( &report )?; + } return Err(( report, e )); } }; - let res = tool::git::push( &git_root, dry ).err_with_report( &report )?; - report.push = Some( res ); + if let Some( git_root ) = git_root.as_ref() + { + let res = tool::git::push( git_root, dry ).err_with_report( &report )?; + report.push = Some( res ); + } Ok( report ) } @@ -414,6 +454,9 @@ mod private /// # Returns /// /// Returns a `Result` containing a vector of `PublishReport` if successful, else an error. + /// + /// # Errors + /// qqq: doc pub fn perform_packages_publish( plan : PublishPlan ) -> error::untyped::Result< Vec< PublishReport > > // qqq : use typed error { diff --git a/module/move/willbe/src/entity/table.rs b/module/move/willbe/src/entity/table.rs index 38e789686c..a49acf6350 100644 --- a/module/move/willbe/src/entity/table.rs +++ b/module/move/willbe/src/entity/table.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { use std::fmt::{Display, Formatter}; @@ -13,13 +14,14 @@ mod private { fn fmt( &self, f : &mut Formatter< '_ > ) -> std::fmt::Result { - writeln!( f, "{}", self.inner.to_string() ) + writeln!( f, "{}", self.inner ) } } impl Table { /// Create an empty table. + #[ must_use ] pub fn new() -> Self { Self @@ -57,7 +59,7 @@ mod private fn default_format() -> prettytable::format::TableFormat { - let format = prettytable::format::FormatBuilder::new() + prettytable::format::FormatBuilder::new() .column_separator( ' ' ) .borders( ' ' ) .separators @@ -66,8 +68,7 @@ mod private prettytable::format::LineSeparator::new( '-', '+', '+', '+' ) ) .padding( 1, 1 ) - .build(); - format + .build() } /// Represent a table row made of cells. @@ -89,9 +90,11 @@ mod private } } + #[ allow( clippy::new_without_default ) ] impl Row { /// Create an row of length size, with empty strings stored. + #[ must_use ] pub fn new() -> Self { Self diff --git a/module/move/willbe/src/entity/test.rs b/module/move/willbe/src/entity/test.rs index 938c5ca415..4ec5fe190d 100644 --- a/module/move/willbe/src/entity/test.rs +++ b/module/move/willbe/src/entity/test.rs @@ -1,7 +1,10 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; + #[ allow( clippy::wildcard_imports ) ] use table::*; // qqq : for Bohdan no asterisk imports, but in special cases use std:: @@ -10,6 +13,7 @@ mod private sync, }; use colored::Colorize as _; + #[ allow( clippy::wildcard_imports ) ] use process_tools::process::*; use error:: { @@ -36,12 +40,12 @@ mod private /// Represents the optimization setting for the test variant. optimization : optimization::Optimization, /// Contains additional features or characteristics of the test variant. - features : collection::BTreeSet, + features : collection::BTreeSet< String >, } impl fmt::Display for TestVariant { - fn fmt( &self, f : &mut fmt::Formatter< '_ >) -> fmt::Result + fn fmt( &self, f : &mut fmt::Formatter< '_ > ) -> fmt::Result { let features = if self.features.is_empty() { " ".to_string() } else { self.features.iter().join( " " ) }; writeln!( f, "{} {} {}", self.optimization, self.channel, features )?; @@ -58,7 +62,7 @@ mod private impl fmt::Display for TestPlan { - fn fmt( &self, f : &mut fmt::Formatter< '_ >) -> std::fmt::Result + fn fmt( &self, f : &mut fmt::Formatter< '_ > ) -> std::fmt::Result { writeln!( f, "Plan: " )?; for plan in &self.packages_plan @@ -82,6 +86,10 @@ mod private /// `with_all_features` - If it's true - add to powerset one subset which contains all features. /// `with_none_features` - If it's true - add to powerset one empty subset. /// `variants_cap` - Maximum of subset in powerset + /// + /// # Errors + /// qqq: doc + #[ allow( clippy::needless_pass_by_value, clippy::too_many_arguments ) ] pub fn try_from< 'a > ( packages : impl core::iter::Iterator< Item = WorkspacePackageRef< 'a > >, @@ -148,7 +156,7 @@ mod private } all_features.extend( features ); } - let mut ff = Vec::from_iter( self.enabled_features.iter().cloned() ); + let mut ff: Vec< _ > = self.enabled_features.iter().cloned().collect(); for feature in all_features { if !ff.contains( &feature ) @@ -184,7 +192,7 @@ mod private } // aaa : for Petro : bad, DRY // aaa : replace with method - writeln!( f, "{}", table )?; + writeln!( f, "{table}" )?; Ok( () ) } } @@ -202,9 +210,10 @@ mod private /// `with_all_features` - If it's true - add to powerset one subset which contains all features. /// `with_none_features` - If it's true - add to powerset one empty subset. /// `variants_cap` - Maximum of subset in powerset - fn try_from< 'a > + #[ allow( clippy::too_many_arguments ) ] + fn try_from ( - package : WorkspacePackageRef< 'a >, + package : WorkspacePackageRef< '_ >, channels : &collection::HashSet< channel::Channel >, power : u32, include_features : &[ String ], @@ -241,8 +250,8 @@ mod private ( TestVariant { - channel : channel.clone(), - optimization : optimization.clone(), + channel : *channel, + optimization : *optimization, features : feature.clone(), } ); @@ -314,10 +323,11 @@ mod private /// Represents the options for the test. #[ derive( Debug, former::Former, Clone ) ] + #[ allow( clippy::struct_excessive_bools ) ] pub struct SingleTestOptions { /// Specifies the release channels for rust. - /// More details : https://rust-lang.github.io/rustup/concepts/channels.html#:~:text=Rust%20is%20released%20to%20three,releases%20are%20made%20every%20night. + /// More details : . channel : channel::Channel, /// Specifies the optimization for rust. optimization : optimization::Optimization, @@ -335,7 +345,7 @@ mod private temp_directory_path : Option< path::PathBuf >, /// A boolean indicating whether to perform a dry run or not. dry : bool, - /// RUST_BACKTRACE + /// `RUST_BACKTRACE` #[ former( default = true ) ] backtrace : bool, } @@ -373,6 +383,10 @@ mod private /// /// Returns a `Result` containing a `Report` if the command is executed successfully, /// or an error if the command fails to execute. + /// + /// # Errors + /// qqq: doc + #[ allow( clippy::needless_pass_by_value ) ] pub fn _run< P >( path : P, options : SingleTestOptions ) -> Result< Report, Report > // xxx where @@ -414,7 +428,7 @@ mod private /// Plan for testing pub plan : TestPlan, - /// `concurrent` - A usize value indicating how much test`s can be run at the same time. + /// `concurrent` - A usize value indicating how much test's can be run at the same time. pub concurrent : u32, /// `temp_path` - path to temp directory. @@ -430,6 +444,7 @@ mod private // aaa : for Petro : remove after Former fix // aaa : done + #[ allow( clippy::missing_fields_in_debug ) ] impl fmt::Debug for TestOptions { fn fmt( &self, f : &mut fmt::Formatter< '_ > ) -> std::fmt::Result @@ -499,7 +514,7 @@ mod private } all_features.extend( features ); } - let mut ff = Vec::from_iter( self.enabled_features.iter().cloned() ); + let mut ff: Vec< _ > = self.enabled_features.iter().cloned().collect(); for feature in all_features { if !ff.contains( &feature ) @@ -537,8 +552,8 @@ mod private Err( report ) => { failed += 1; - let mut out = report.out.replace( "\n", "\n " ); - out.push_str( "\n" ); + let mut out = report.out.replace( '\n', "\n " ); + out.push( '\n' ); write!( f, " ❌ > {}\n\n{out}", report.command )?; "❌" }, @@ -555,7 +570,7 @@ mod private } // aaa : for Petro : bad, DRY // aaa : replace with method - writeln!( f, "{}", table )?; + writeln!( f, "{table}" )?; writeln!( f, " {}", generate_summary_message( failed, success ) )?; Ok( () ) @@ -617,7 +632,7 @@ mod private writeln!( f, "Successful :" )?; for report in &self.success_reports { - writeln!( f, "{}", report )?; + writeln!( f, "{report}" )?; } } if !self.failure_reports.is_empty() @@ -625,10 +640,11 @@ mod private writeln!( f, "Failure :" )?; for report in &self.failure_reports { - writeln!( f, "{}", report )?; + writeln!( f, "{report}" )?; } } writeln!( f, "Global report" )?; + #[ allow( clippy::cast_possible_wrap, clippy::cast_possible_truncation ) ] writeln!( f, " {}", generate_summary_message( self.failure_reports.len() as i32, self.success_reports.len() as i32 ) )?; Ok( () ) @@ -637,13 +653,17 @@ mod private /// `tests_run` is a function that runs tests on a given package with specified arguments. /// It returns a `TestReport` on success, or a `TestReport` and an `Error` on failure. + /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc pub fn run( options : &PackageTestOptions< '_ > ) -> ResultWithReport< TestReport, TestError > // -> Result< TestReport, ( TestReport, TestError ) > { - let mut report = TestReport::default(); - report.dry = options.dry; - report.enabled_features = options.plan.enabled_features.clone(); + let report = TestReport { dry: options.dry, enabled_features: options.plan.enabled_features.clone(), ..Default::default() }; let report = sync::Arc::new( sync::Mutex::new( report ) ); let crate_dir = options.plan.crate_dir.clone(); @@ -678,7 +698,7 @@ mod private { let _s = { - let s = options.progress_bar.multi_progress.add( indicatif::ProgressBar::new_spinner().with_message( format!( "{}", variant ) ) ); + let s = options.progress_bar.multi_progress.add( indicatif::ProgressBar::new_spinner().with_message( format!( "{variant}" ) ) ); s.enable_steady_tick( std::time::Duration::from_millis( 100 ) ); s }; @@ -712,6 +732,11 @@ mod private } /// Run tests for given packages. + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc pub fn tests_run( args : &TestOptions ) -> ResultWithReport< TestsReport, TestError > // -> Result< TestsReport, ( TestsReport, TestError ) > @@ -720,8 +745,7 @@ mod private let multi_progress = progress_bar::MultiProgress::default(); #[ cfg( feature = "progress_bar" ) ] let mm = &multi_progress; - let mut report = TestsReport::default(); - report.dry = args.dry; + let report = TestsReport { dry: args.dry, ..Default::default() }; let report = sync::Arc::new( sync::Mutex::new( report ) ); let pool = rayon::ThreadPoolBuilder::new().use_current_thread().num_threads( args.concurrent as usize ).build().unwrap(); pool.scope diff --git a/module/move/willbe/src/entity/version.rs b/module/move/willbe/src/entity/version.rs index 0722b8a59c..085b7494ee 100644 --- a/module/move/willbe/src/entity/version.rs +++ b/module/move/willbe/src/entity/version.rs @@ -1,6 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use std:: @@ -17,7 +19,7 @@ mod private use package::Package; use { error::untyped::format_err, iter::Itertools }; - /// Wrapper for a SemVer structure + /// Wrapper for a `SemVer` structure #[ derive( Debug, Clone, Eq, PartialEq, Ord, PartialOrd ) ] pub struct Version( SemVersion ); @@ -55,7 +57,7 @@ mod private { fn fmt( &self, f : &mut fmt::Formatter< '_ > ) -> fmt::Result { - write!( f, "{}", self.0.to_string() ) + write!( f, "{}", self.0 ) } } @@ -64,6 +66,7 @@ mod private /// Bump a version with default strategy /// /// This function increases first not 0 number + #[ must_use ] pub fn bump( self ) -> Self { let mut ver = self.0; @@ -187,6 +190,9 @@ mod private /// /// Returns a result containing the extended bump report if successful. /// + /// + /// # Errors + /// qqq: doc // qqq : should be typed error, apply err_with // qqq : don't use 1-prameter Result pub fn bump( o : BumpOptions ) -> Result< ExtendedBumpReport > @@ -211,7 +217,7 @@ mod private { // let data = package_manifest.data.as_mut().unwrap(); let data = &mut package_manifest.data; - data[ "package" ][ "version" ] = value( &o.new_version.to_string() ); + data[ "package" ][ "version" ] = value( o.new_version.to_string() ); package_manifest.store()?; } report.changed_files = vec![ manifest_file ]; @@ -226,9 +232,9 @@ mod private let item = if let Some( item ) = data.get_mut( "package" ) { item } else if let Some( item ) = data.get_mut( "workspace" ) { item } else { return Err( format_err!( "{report:?}\nThe manifest nor the package and nor the workspace" ) ); }; - if let Some( dependency ) = item.get_mut( "dependencies" ).and_then( | ds | ds.get_mut( &name ) ) + if let Some( dependency ) = item.get_mut( "dependencies" ).and_then( | ds | ds.get_mut( name ) ) { - if let Some( previous_version ) = dependency.get( "version" ).and_then( | v | v.as_str() ).map( | v | v.to_string() ) + if let Some( previous_version ) = dependency.get( "version" ).and_then( | v | v.as_str() ).map( std::string::ToString::to_string ) { if previous_version.starts_with('~') { @@ -256,6 +262,12 @@ mod private /// # Returns /// /// Returns `Ok(())` if the version is reverted successfully. Returns `Err` with an error message if there is any issue with reverting the version. + /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc // qqq : don't use 1-prameter Result pub fn revert( report : &ExtendedBumpReport ) -> error::untyped::Result< () > // qqq : use typed error { @@ -267,13 +279,13 @@ mod private { if let Some( dependency ) = item_maybe_with_dependencies.get_mut( "dependencies" ).and_then( | ds | ds.get_mut( name ) ) { - if let Some( current_version ) = dependency.get( "version" ).and_then( | v | v.as_str() ).map( | v | v.to_string() ) + if let Some( current_version ) = dependency.get( "version" ).and_then( | v | v.as_str() ).map( std::string::ToString::to_string ) { let version = &mut dependency[ "version" ]; if let Some( current_version ) = current_version.strip_prefix( '~' ) { if current_version != new_version { return Err( format_err!( "The current version of the package does not match the expected one. Expected: `{new_version}` Current: `{}`", version.as_str().unwrap_or_default() ) ); } - *version = value( format!( "~{}", old_version ) ); + *version = value( format!( "~{old_version}" ) ); } else { @@ -327,6 +339,12 @@ mod private /// # Returns : /// - `Ok` - the new version number as a string; /// - `Err` - if the manifest file cannot be read, written, parsed. + /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc pub fn manifest_bump( manifest : &mut Manifest, dry : bool ) -> Result< BumpReport, manifest::ManifestError > { let mut report = BumpReport::default(); diff --git a/module/move/willbe/src/entity/workspace.rs b/module/move/willbe/src/entity/workspace.rs index 3fc37828fd..945e70ba23 100644 --- a/module/move/willbe/src/entity/workspace.rs +++ b/module/move/willbe/src/entity/workspace.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; // qqq : for Bohdan : bad @@ -97,6 +99,10 @@ mod private } /// Returns the path to workspace root + /// + /// # Panics + /// qqq: doc + #[ must_use ] pub fn workspace_root( &self ) -> CrateDir { // Safe because workspace_root.as_std_path() is always a path to a directory @@ -104,13 +110,17 @@ mod private } /// Returns the path to target directory + #[ must_use ] pub fn target_directory( &self ) -> &std::path::Path { self.metadata.target_directory.as_std_path() } /// Find a package by its manifest file path - pub fn package_find_by_manifest< 'a, P >( &'a self, manifest_file : P ) -> Option< WorkspacePackageRef< 'a > > + /// + /// # Panics + /// qqq: doc + pub fn package_find_by_manifest< P >( &self, manifest_file : P ) -> Option< WorkspacePackageRef< '_ > > where P : AsRef< std::path::Path >, { @@ -120,7 +130,8 @@ mod private } /// Filter of packages. - pub fn packages_which< 'a >( &'a self ) -> PackagesFilterFormer< 'a > + #[ must_use ] + pub fn packages_which( &self ) -> PackagesFilterFormer< '_ > { // PackagesFilter::new( self ) PackagesFilter::former().workspace( self ) @@ -208,12 +219,13 @@ mod private Self { workspace, - crate_dir : Default::default(), - manifest_file : Default::default(), + crate_dir : Box::default(), + manifest_file : Box::default(), } } #[ inline( always ) ] + #[ allow( clippy::unused_self ) ] pub fn iter( &'a self ) -> impl Iterator< Item = WorkspacePackageRef< 'a > > + Clone { @@ -247,9 +259,8 @@ mod private { if !formed.crate_dir.include( p ) { return false }; if !formed.manifest_file.include( p ) { return false }; - return true; + true }) - .clone() // .unwrap() // let filter_crate_dir = if Some( crate_dir ) = self.crate_dir diff --git a/module/move/willbe/src/entity/workspace_graph.rs b/module/move/willbe/src/entity/workspace_graph.rs index 9d129fdf07..11b592520f 100644 --- a/module/move/willbe/src/entity/workspace_graph.rs +++ b/module/move/willbe/src/entity/workspace_graph.rs @@ -1,8 +1,11 @@ mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// Returns a graph of packages. + #[ allow( clippy::type_complexity ) ] + #[ must_use ] pub fn graph( workspace : &Workspace ) -> petgraph::Graph< String, String > { let packages = workspace.packages(); diff --git a/module/move/willbe/src/entity/workspace_md_extension.rs b/module/move/willbe/src/entity/workspace_md_extension.rs index f463d4cf60..afbc2442a9 100644 --- a/module/move/willbe/src/entity/workspace_md_extension.rs +++ b/module/move/willbe/src/entity/workspace_md_extension.rs @@ -1,6 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// Md's extension for workspace @@ -15,7 +17,7 @@ mod private /// Return the repository url fn repository_url( &self ) -> Option< String >; - /// Return the workspace_name + /// Return the `workspace_name` fn workspace_name( &self ) -> Option< String >; } @@ -27,7 +29,7 @@ mod private .metadata .workspace_metadata[ "discord_url" ] .as_str() - .map( | url | url.to_string() ) + .map( std::string::ToString::to_string ) } fn master_branch( &self ) -> Option< String > @@ -37,7 +39,7 @@ mod private .workspace_metadata .get( "master_branch" ) .and_then( | b | b.as_str() ) - .map( | b | b.to_string() ) + .map( std::string::ToString::to_string ) } fn repository_url( &self ) -> Option< String > @@ -47,7 +49,7 @@ mod private .workspace_metadata .get( "repo_url" ) .and_then( | b | b.as_str() ) - .map( | b | b.to_string() ) + .map( std::string::ToString::to_string ) } fn workspace_name( &self ) -> Option< String > @@ -57,7 +59,7 @@ mod private .workspace_metadata .get( "workspace_name" ) .and_then( | b | b.as_str() ) - .map( | b | b.to_string() ) + .map( std::string::ToString::to_string ) } } diff --git a/module/move/willbe/src/entity/workspace_package.rs b/module/move/willbe/src/entity/workspace_package.rs index 6ecada7108..0cbb271103 100644 --- a/module/move/willbe/src/entity/workspace_package.rs +++ b/module/move/willbe/src/entity/workspace_package.rs @@ -1,5 +1,7 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; use macros::kw; use collection::BTreeMap; @@ -12,7 +14,7 @@ mod private // xxx : qqq : Deref, DerefMut, AsRef, AsMut - /// Facade for cargo_metadata::Package + /// Facade for `cargo_metadata::Package` #[ derive( Debug, Clone, Copy ) ] #[ repr( transparent ) ] pub struct WorkspacePackageRef< 'a > @@ -35,6 +37,7 @@ mod private impl< 'a > WorkspacePackageRef< 'a > { /// The name field as given in the Cargo.toml + #[ must_use ] pub fn name( &'a self ) -> &'a str { &self.inner.name @@ -56,12 +59,21 @@ mod private } /// Path to the manifest Cargo.toml + /// + /// # Errors + /// qqq: doc pub fn manifest_file( &self ) -> Result< ManifestFile, PathError > { self.inner.manifest_path.as_path().try_into() } /// Path to the directory with manifest Cargo.toml. + /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: docs pub fn crate_dir( &self ) -> Result< CrateDir, PathError > { // SAFE because `manifest_path containing the Cargo.toml` @@ -69,6 +81,7 @@ mod private } /// The version field as specified in the Cargo.toml + #[ must_use ] pub fn version( &self ) -> semver::Version { self.inner.version.clone() @@ -77,6 +90,7 @@ mod private /// List of registries to which this package may be published (derived from the publish field). /// Publishing is unrestricted if None, and forbidden if the Vec is empty. /// This is always None if running with a version of Cargo older than 1.39. + #[ must_use ] pub fn publish( &self ) -> Option< &Vec< String > > { self.inner.publish.as_ref() @@ -105,18 +119,21 @@ mod private /// assert_eq!( package_metadata.some_value, 42 ); /// } /// ``` + #[ must_use ] pub fn metadata( &self ) -> &Value { &self.inner.metadata } /// The repository URL as specified in the Cargo.toml + #[ must_use ] pub fn repository( &self ) -> Option< &String > { self.inner.repository.as_ref() } /// Features provided by the crate, mapped to the features required by that feature. + #[ must_use ] pub fn features( &self ) -> &BTreeMap< String, Vec< String > > { &self.inner.features @@ -130,7 +147,7 @@ mod private self.inner.targets.iter().map( | target | { let src_path = &target.src_path; - let source : SourceFile = src_path.try_into().expect( &format!( "Illformed path to source file {src_path}" ) ); + let source : SourceFile = src_path.try_into().unwrap_or_else( | _ | panic!( "Illformed path to source file {src_path}" ) ); // println!( " -- {:?} {:?}", source, target.kind ); source }) @@ -166,7 +183,7 @@ mod private impl< 'a > AsCode for WorkspacePackageRef< 'a > { - fn as_code< 'b >( &'b self ) -> std::io::Result< Cow< 'b, str > > + fn as_code( &self ) -> std::io::Result< Cow< '_, str > > { let mut results : Vec< String > = Vec::new(); // zzz : introduce formatter @@ -178,9 +195,9 @@ mod private .as_ref() .with_extension( "" ) .file_name() - .expect( &format!( "Cant get file name of path {}", source.as_ref().display() ) ) + .unwrap_or_else( || panic!( "Cant get file name of path {}", source.as_ref().display() ) ) .to_string_lossy() - .replace( ".", "_" ); + .replace( '.', "_" ); if kw::is( &filename ) { @@ -190,7 +207,7 @@ mod private // qqq : xxx : use callbacks instead of expect results.push( format!( "// === Begin of File {}", source.as_ref().display() ) ); - results.push( format!( "mod {}\n{{\n", filename ) ); + results.push( format!( "mod {filename}\n{{\n" ) ); results.push( code ); results.push( "\n}".to_string() ); results.push( format!( "// === End of File {}", source.as_ref().display() ) ); diff --git a/module/move/willbe/src/lib.rs b/module/move/willbe/src/lib.rs index 87149b74fa..a8a72e3d47 100644 --- a/module/move/willbe/src/lib.rs +++ b/module/move/willbe/src/lib.rs @@ -5,9 +5,10 @@ pub use mod_interface::mod_interface; -/// Internal namespace. +/// Define a private namespace for all its items. mod private { + #[ allow( clippy::wildcard_imports ) ] use crate::*; /// Takes the command line arguments and perform associated function(s). @@ -15,6 +16,9 @@ mod private /// It then terminates the program with an exit code of 1 to indicate an error due to the lack of input. /// /// Do not support interactive mode. + /// + /// # Errors + /// qqq: doc pub fn run( args : Vec< String > ) -> Result< (), error::untyped::Error > { #[ cfg( feature = "tracing" ) ] diff --git a/module/move/willbe/src/tool/cargo.rs b/module/move/willbe/src/tool/cargo.rs index 71590ecd45..a8f926860a 100644 --- a/module/move/willbe/src/tool/cargo.rs +++ b/module/move/willbe/src/tool/cargo.rs @@ -1,13 +1,17 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { - #[ allow( unused_imports ) ] + #[ allow( clippy::wildcard_imports ) ] + use crate::*; + + #[ allow( unused_imports, clippy::wildcard_imports ) ] use crate::tool::*; use std::ffi::OsString; use std::path::PathBuf; - use error::err; - use error::untyped::format_err; + // use error::err; + // use error::untyped::format_err; use former::Former; use process_tools::process; // use process_tools::process::*; @@ -25,6 +29,7 @@ mod private /// The `PackOptions` struct encapsulates various options that can be configured when packaging a project, /// including the path to the project, the distribution channel, and various flags for controlling the behavior of the packaging process. #[ derive( Debug, Former, Clone ) ] + #[ allow( clippy::struct_excessive_bools ) ] pub struct PackOptions { /// The path to the project to be packaged. @@ -47,6 +52,9 @@ mod private // aaa : don't abuse negative form, rename to checking_consistency // renamed and changed logic pub( crate ) checking_consistency : bool, + /// Setting this option to true will temporarily remove development dependencies before executing the command, then restore them afterward. + #[ former( default = true ) ] + pub( crate ) exclude_dev_dependencies : bool, /// An optional temporary path to be used during packaging. /// /// This field may contain a path to a temporary directory that will be used during the packaging process. @@ -68,6 +76,7 @@ mod private impl PackOptions { + #[ allow( clippy::if_not_else ) ] fn to_pack_args( &self ) -> Vec< String > { [ "run".to_string(), self.channel.to_string(), "cargo".into(), "package".into() ] @@ -79,6 +88,53 @@ mod private } } + #[ derive( Debug ) ] + struct TemporaryManifestFile + { + original : PathBuf, + temporary : PathBuf, + } + + impl TemporaryManifestFile + { + /// Creates a backup copy of the original file, allowing the original file location to serve as a temporary workspace. + /// When the object is dropped, the temporary file at the original location is replaced by the backup, restoring the original file. + fn new( path : impl Into< PathBuf > ) -> error::untyped::Result< Self > + { + let path = path.into(); + if !path.ends_with( "Cargo.toml" ) + { + error::untyped::bail!( "Wrong path to temporary manifest" ); + } + + let mut index = 0; + let original = loop + { + let temp_path = PathBuf::from( format!( "{}.temp_{index}", path.display() ) ); + if !temp_path.exists() + { + _ = std::fs::copy( &path, &temp_path )?; + break temp_path; + } + index += 1; + }; + + Ok( Self + { + original, + temporary : path, + }) + } + } + + impl Drop for TemporaryManifestFile + { + fn drop( &mut self ) + { + _ = std::fs::rename( &self.original, &self.temporary ).ok(); + } + } + /// /// Assemble the local package into a distributable tarball. /// @@ -96,6 +152,17 @@ mod private // qqq : use typed error pub fn pack( args : PackOptions ) -> error::untyped::Result< process::Report > { + let _temp = if args.exclude_dev_dependencies + { + let manifest = TemporaryManifestFile::new( args.path.join( "Cargo.toml" ) )?; + let mut file = Manifest::try_from( ManifestFile::try_from( &manifest.temporary )? )?; + let data = file.data(); + + _ = data.remove( "dev-dependencies" ); + file.store()?; + + Some( manifest ) + } else { None }; let ( program, options ) = ( "rustup", args.to_pack_args() ); if args.dry @@ -107,7 +174,7 @@ mod private command : format!( "{program} {}", options.join( " " ) ), out : String::new(), err : String::new(), - current_path: args.path.to_path_buf(), + current_path: args.path.clone(), error: Ok( () ), } ) @@ -118,7 +185,7 @@ mod private .bin_path( program ) .args( options.into_iter().map( OsString::from ).collect::< Vec< _ > >() ) .current_path( args.path ) - .run().map_err( | report | err!( report.to_string() ) ) + .run().map_err( | report | error::untyped::format_err!( report.to_string() ) ) } } @@ -129,6 +196,7 @@ mod private { pub( crate ) path : PathBuf, pub( crate ) temp_path : Option< PathBuf >, + pub( crate ) exclude_dev_dependencies : bool, #[ former( default = 0usize ) ] pub( crate ) retry_count : usize, pub( crate ) dry : bool, @@ -162,6 +230,17 @@ mod private pub fn publish( args : PublishOptions ) -> error::untyped::Result< process::Report > // qqq : use typed error { + let _temp = if args.exclude_dev_dependencies + { + let manifest = TemporaryManifestFile::new( args.path.join( "Cargo.toml" ) )?; + let mut file = Manifest::try_from( ManifestFile::try_from( &manifest.temporary )? )?; + let data = file.data(); + + _ = data.remove( "dev-dependencies" ); + file.store()?; + + Some( manifest ) + } else { None }; let ( program, arguments) = ( "cargo", args.as_publish_args() ); if args.dry @@ -173,7 +252,7 @@ mod private command : format!( "{program} {}", arguments.join( " " ) ), out : String::new(), err : String::new(), - current_path: args.path.to_path_buf(), + current_path: args.path.clone(), error: Ok( () ), } ) @@ -182,7 +261,7 @@ mod private { let mut results = Vec::with_capacity( args.retry_count + 1 ); let run_args : Vec< _ > = arguments.into_iter().map( OsString::from ).collect(); - for _ in 0 .. args.retry_count + 1 + for _ in 0 ..=args.retry_count { let result = process::Run::former() .bin_path( program ) @@ -197,11 +276,11 @@ mod private } if args.retry_count > 0 { - Err( format_err!( "It took {} attempts, but still failed. Here are the errors:\n{}", args.retry_count + 1, results.into_iter().map( | r | format!( "- {r}" ) ).collect::< Vec< _ > >().join( "\n" ) ) ) + Err( error::untyped::format_err!( "It took {} attempts, but still failed. Here are the errors:\n{}", args.retry_count + 1, results.into_iter().map( | r | format!( "- {r}" ) ).collect::< Vec< _ > >().join( "\n" ) ) ) } else { - Err( results.remove( 0 ) ).map_err( | report | err!( report.to_string() ) ) + Err( results.remove( 0 ) ).map_err( | report | error::untyped::format_err!( report.to_string() ) ) } } } diff --git a/module/move/willbe/src/tool/collection.rs b/module/move/willbe/src/tool/collection.rs deleted file mode 100644 index edd7bec8c8..0000000000 --- a/module/move/willbe/src/tool/collection.rs +++ /dev/null @@ -1,12 +0,0 @@ -/// Internal namespace. -mod private -{ -} - -crate::mod_interface! -{ - - use ::collection_tools; - own use ::collection_tools::own::*; - -} diff --git a/module/move/willbe/src/tool/error.rs b/module/move/willbe/src/tool/error.rs deleted file mode 100644 index bc00b92ba9..0000000000 --- a/module/move/willbe/src/tool/error.rs +++ /dev/null @@ -1,21 +0,0 @@ -/// Internal namespace. -#[ allow( unused_imports ) ] -mod private -{ - use crate::tool::*; - use ::error_tools::own::*; - -} - -crate::mod_interface! -{ - // #![ debug ] - - use ::error_tools; - own use ::error_tools::own::*; - - // exposed use ErrWith; - // exposed use ResultWithReport; - // exposed use ::error_tools::Result; - -} diff --git a/module/move/willbe/src/tool/files.rs b/module/move/willbe/src/tool/files.rs index 38878c477d..5b70f48535 100644 --- a/module/move/willbe/src/tool/files.rs +++ b/module/move/willbe/src/tool/files.rs @@ -1,8 +1,9 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::wildcard_imports ) ] use crate::tool::*; use std::path::{ Path, PathBuf }; @@ -10,8 +11,11 @@ mod private /// /// Find paths. /// + /// # Panics + /// qqq: doc /* xxx : check */ + #[ allow( clippy::useless_conversion ) ] pub fn find< P, S >( base_dir : P, patterns : &[ S ] ) -> Vec< PathBuf > where P : AsRef< Path >, @@ -27,6 +31,7 @@ mod private } /// Check if path is valid. + #[ must_use ] pub fn valid_is( path : &str ) -> bool { std::fs::metadata( path ).is_ok() diff --git a/module/move/willbe/src/tool/git.rs b/module/move/willbe/src/tool/git.rs index 828e4d3c64..27c9743f4d 100644 --- a/module/move/willbe/src/tool/git.rs +++ b/module/move/willbe/src/tool/git.rs @@ -1,13 +1,16 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::wildcard_imports ) ] use crate::tool::*; use std::ffi::OsString; use std::path::Path; + + #[ allow( clippy::wildcard_imports ) ] use process_tools::process::*; - use error::err; + // use error::err; // qqq : group dependencies /// Adds changes to the Git staging area. @@ -31,7 +34,7 @@ mod private Os : AsRef< [ O ] >, O : AsRef< str >, { - let objects = objects.as_ref().iter().map( | x | x.as_ref() ); + let objects = objects.as_ref().iter().map( std::convert::AsRef::as_ref ); // qqq : for Bohdan : don't enlarge length of lines artificially let ( program, args ) : ( _, Vec< _ > ) = ( "git", Some( "add" ).into_iter().chain( objects ).collect() ); @@ -56,7 +59,7 @@ mod private .bin_path( program ) .args( args.into_iter().map( OsString::from ).collect::< Vec< _ > >() ) .current_path( path.as_ref().to_path_buf() ) - .run().map_err( | report | err!( report.to_string() ) ) + .run().map_err( | report | error::untyped::format_err!( report.to_string() ) ) } } @@ -102,7 +105,7 @@ mod private .bin_path( program ) .args( args.into_iter().map( OsString::from ).collect::< Vec< _ > >() ) .current_path( path.as_ref().to_path_buf() ) - .run().map_err( | report | err!( report.to_string() ) ) + .run().map_err( | report | error::untyped::format_err!( report.to_string() ) ) } } @@ -148,7 +151,7 @@ mod private .bin_path( program ) .args( args.into_iter().map( OsString::from ).collect::< Vec< _ > >() ) .current_path( path.as_ref().to_path_buf() ) - .run().map_err( | report | err!( report.to_string() ) ) + .run().map_err( | report | error::untyped::format_err!( report.to_string() ) ) } } @@ -164,6 +167,9 @@ mod private /// # Returns : /// This function returns a `Result` containing a `Report` if the command is executed successfully. The `Report` contains the command executed, the output /// git reset command wrapper + /// + /// # Errors + /// qqq: doc // qqq : should be typed error, apply err_with @@ -173,7 +179,7 @@ mod private where P : AsRef< Path >, { - if commits_count < 1 { return Err( err!( "Cannot reset, the count of commits must be greater than 0" ) ) } + if commits_count < 1 { return Err( error::untyped::format_err!( "Cannot reset, the count of commits must be greater than 0" ) ) } let ( program, args ) : ( _, Vec< _ > ) = ( "git", @@ -181,7 +187,7 @@ mod private .into_iter() .chain( if hard { Some( "--hard" ) } else { None } ) .map( String::from ) - .chain( Some( format!( "HEAD~{}", commits_count ) ) ) + .chain( Some( format!( "HEAD~{commits_count}" ) ) ) .collect() ); @@ -205,7 +211,7 @@ mod private .bin_path( program ) .args( args.into_iter().map( OsString::from ).collect::< Vec< _ > >() ) .current_path( path.as_ref().to_path_buf() ) - .run().map_err( | report | err!( report.to_string() ) ) + .run().map_err( | report | error::untyped::format_err!( report.to_string() ) ) } } @@ -218,6 +224,9 @@ mod private /// # Returns /// /// A `Result` containing a `Report`, which represents the result of the command execution. + /// + /// # Errors + /// qqq: doc // qqq : should be typed error, apply err_with // qqq : don't use 1-prameter Result @@ -232,7 +241,7 @@ mod private .bin_path( program ) .args( args.into_iter().map( OsString::from ).collect::< Vec< _ > >() ) .current_path( path.as_ref().to_path_buf() ) - .run().map_err( | report | err!( report.to_string() ) ) + .run().map_err( | report | error::untyped::format_err!( report.to_string() ) ) } } diff --git a/module/move/willbe/src/tool/graph.rs b/module/move/willbe/src/tool/graph.rs index 296547ac82..e7e06db908 100644 --- a/module/move/willbe/src/tool/graph.rs +++ b/module/move/willbe/src/tool/graph.rs @@ -1,7 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::wildcard_imports ) ] use crate::*; // use crate::tool::*; @@ -21,6 +22,7 @@ mod private algo::toposort as pg_toposort, }; use petgraph::graph::NodeIndex; + #[ allow( clippy::wildcard_imports ) ] use petgraph::prelude::*; use error:: @@ -45,6 +47,11 @@ mod private /// /// Returns : /// The graph with all accepted packages + /// + /// # Panics + /// qqq: doc + #[ allow( clippy::implicit_hasher ) ] + #[ must_use ] pub fn construct< PackageIdentifier > ( packages : &HashMap @@ -92,6 +99,10 @@ mod private /// /// # Panics /// If there is a cycle in the dependency graph + /// + /// # Errors + /// qqq: doc + #[ allow( clippy::needless_pass_by_value ) ] pub fn toposort< 'a, PackageIdentifier : Clone + std::fmt::Debug > ( graph : Graph< &'a PackageIdentifier, &'a PackageIdentifier > @@ -123,6 +134,11 @@ mod private /// # Returns /// /// The function returns a vector of vectors, where each inner vector represents a group of nodes that can be executed in parallel. Tasks within each group are sorted in topological order. + /// + /// # Panics + /// qqq: doc + #[ must_use ] + #[ allow( clippy::needless_pass_by_value ) ] pub fn topological_sort_with_grouping< 'a, PackageIdentifier : Clone + std::fmt::Debug > ( graph : Graph< &'a PackageIdentifier, &'a PackageIdentifier > @@ -136,7 +152,7 @@ mod private } let mut roots = VecDeque::new(); - for ( node, °ree ) in in_degree.iter() + for ( node, °ree ) in &in_degree { if degree == 0 { @@ -194,6 +210,10 @@ mod private /// /// # Constraints /// * `N` must implement the `PartialEq` trait. + /// + /// # Panics + /// qqq: doc + #[ allow( clippy::single_match, clippy::map_entry ) ] pub fn subgraph< N, E >( graph : &Graph< N, E >, roots : &[ N ] ) -> Graph< NodeIndex, EdgeIndex > where N : PartialEq< N >, @@ -215,7 +235,7 @@ mod private } } - for ( _, sub_node_id ) in &node_map + for sub_node_id in node_map.values() { let node_id_graph = subgraph[ *sub_node_id ]; @@ -246,11 +266,18 @@ mod private /// # Returns /// /// A new `Graph` with the nodes that are not required to be published removed. + /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc // qqq : for Bohdan : typed error - pub fn remove_not_required_to_publish< 'a > + #[ allow( clippy::single_match, clippy::needless_pass_by_value, clippy::implicit_hasher ) ] + pub fn remove_not_required_to_publish ( - package_map : &HashMap< String, Package< 'a > >, + package_map : &HashMap< String, Package< '_ > >, graph : &Graph< String, String >, roots : &[ String ], temp_path : Option< PathBuf >, diff --git a/module/move/willbe/src/tool/http.rs b/module/move/willbe/src/tool/http.rs index d682a79d69..f62f86005f 100644 --- a/module/move/willbe/src/tool/http.rs +++ b/module/move/willbe/src/tool/http.rs @@ -1,7 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::wildcard_imports ) ] use crate::tool::*; use std:: @@ -16,6 +17,12 @@ mod private /// /// Get data of remote package. /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: docs + /// // qqq : typed error pub fn download< 'a >( name : &'a str, version : &'a str ) -> error::untyped::Result< Vec< u8 > > { @@ -24,7 +31,7 @@ mod private .timeout_write( Duration::from_secs( 5 ) ) .build(); let mut buf = String::new(); - write!( &mut buf, "https://static.crates.io/crates/{0}/{0}-{1}.crate", name, version )?; + write!( &mut buf, "https://static.crates.io/crates/{name}/{name}-{version}.crate" )?; let resp = agent.get( &buf[ .. ] ).call().context( "Get data of remote package" )?; diff --git a/module/move/willbe/src/tool/iter.rs b/module/move/willbe/src/tool/iter.rs index a7b82abd7a..855c492006 100644 --- a/module/move/willbe/src/tool/iter.rs +++ b/module/move/willbe/src/tool/iter.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } diff --git a/module/move/willbe/src/tool/macros.rs b/module/move/willbe/src/tool/macros.rs index 81861cb3de..96f7a3b06d 100644 --- a/module/move/willbe/src/tool/macros.rs +++ b/module/move/willbe/src/tool/macros.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } diff --git a/module/move/willbe/src/tool/mod.rs b/module/move/willbe/src/tool/mod.rs index 719b616b4b..7864cdc660 100644 --- a/module/move/willbe/src/tool/mod.rs +++ b/module/move/willbe/src/tool/mod.rs @@ -8,12 +8,15 @@ crate::mod_interface! orphan use super::cargo; /// Function and structures to work with collections. - layer collection; - orphan use super::collection; + // layer collection; + // orphan use super::collection; + use ::collection_tools; + // own use ::collection_tools::own::*; /// Errors handling. - layer error; - orphan use super::error; + // layer error; + // orphan use super::error; + use ::error_tools; /// Operate over files. layer files; diff --git a/module/move/willbe/src/tool/path.rs b/module/move/willbe/src/tool/path.rs index 028bbd4189..611a9c21ed 100644 --- a/module/move/willbe/src/tool/path.rs +++ b/module/move/willbe/src/tool/path.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { } diff --git a/module/move/willbe/src/tool/query.rs b/module/move/willbe/src/tool/query.rs index 3528d887ae..6724a0093f 100644 --- a/module/move/willbe/src/tool/query.rs +++ b/module/move/willbe/src/tool/query.rs @@ -1,7 +1,8 @@ -/// Internal namespace. +/// Define a private namespace for all its items. +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::wildcard_imports ) ] use crate::tool::*; use std:: @@ -36,10 +37,12 @@ mod private if let Ok( i ) = s.parse::< i32 >() { Ok( Value::Int( i ) ) - } else if let Ok( b ) = s.parse::< bool >() + } + else if let Ok( b ) = s.parse::< bool >() { Ok( Value::Bool( b ) ) - } else + } + else { let s = s.trim_matches( '\'' ); Ok( Value::String( s.to_string() ) ) @@ -85,6 +88,7 @@ mod private /// assert!( result.contains( &Value::Int( 2 ) ) ); /// assert!( result.contains( &Value::Int( 3 ) ) ); /// ``` + #[ must_use ] pub fn into_vec( self ) -> Vec< Value > { match self @@ -111,6 +115,8 @@ mod private /// assert_eq!( HashMap::from( [ ( "1".to_string(), Value::Int( 1 ) ), ( "2".to_string(),Value::Int( 2 ) ), ( "3".to_string(),Value::Int( 3 ) ) ] ), unnamed_map ); /// assert_eq!( HashMap::from( [ ( "var0".to_string(), Value::Int( 1 ) ), ( "1".to_string(),Value::Int( 2 ) ), ( "2".to_string(),Value::Int( 3 ) ) ] ), mixed_map ); /// ``` + #[ allow( clippy::needless_pass_by_value ) ] + #[ must_use ] pub fn into_map( self, names : Vec< String > ) -> HashMap< String, Value > { match self @@ -148,6 +154,12 @@ mod private /// expected_map.insert( "key".to_string(), Value::String( r#"hello\'test\'test"#.into() ) ); /// assert_eq!( parse( r#"{ key : 'hello\'test\'test' }"# ).unwrap().into_map( vec![] ), expected_map ); /// ``` + /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc // qqq : use typed error pub fn parse( input_string : &str ) -> error::untyped::Result< ParseResult > { @@ -253,6 +265,7 @@ mod private } // qqq : use typed error + #[ allow( clippy::unnecessary_wraps ) ] fn parse_to_vec( input : Vec< String > ) -> error::untyped::Result< Vec< Value > > { Ok( input.into_iter().filter_map( | w | Value::from_str( w.trim() ).ok() ).collect() ) diff --git a/module/move/willbe/src/tool/repository.rs b/module/move/willbe/src/tool/repository.rs index 66474d906d..7ec6fb7323 100644 --- a/module/move/willbe/src/tool/repository.rs +++ b/module/move/willbe/src/tool/repository.rs @@ -1,7 +1,7 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::wildcard_imports ) ] use crate::tool::*; /// Searches for a README file in specific subdirectories of the given directory path. @@ -9,6 +9,9 @@ mod private /// This function attempts to find a README file in the following subdirectories: ".github", /// the root directory, and "./docs". It returns the path to the first found README file, or /// `None` if no README file is found in any of these locations. + /// + /// # Errors + /// qqq: doc pub fn readme_path( dir_path : &std::path::Path ) -> Result< std::path::PathBuf, std::io::Error > { if let Some( path ) = readme_in_dir_find( &dir_path.join( ".github" ) ) diff --git a/module/move/willbe/src/tool/template.rs b/module/move/willbe/src/tool/template.rs index bd90b0b5d7..c8ac11af89 100644 --- a/module/move/willbe/src/tool/template.rs +++ b/module/move/willbe/src/tool/template.rs @@ -1,7 +1,7 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::wildcard_imports ) ] use crate::tool::*; use std:: @@ -29,7 +29,7 @@ mod private /// The values associated with the template. pub values : TemplateValues, /// Path to the parameter storage for recovering values - /// for already generated templated files. + /// for already generated templated files. pub parameter_storage : &'static Path, /// Name of the template to generate pub template_name : &'static str, @@ -49,6 +49,9 @@ mod private /// # Returns /// /// A `Result` which is `Ok` if the files are created successfully, or an `Err` otherwise. + /// + /// # Errors + /// qqq: doc pub fn create_all( self, path : &path::Path ) -> error::untyped::Result< () > // qqq : use typed error { self.files.create_all( path, &self.values ) @@ -59,6 +62,7 @@ mod private /// # Returns /// /// A reference to `TemplateParameters`. + #[ must_use ] pub fn parameters( &self ) -> &TemplateParameters { &self.parameters @@ -71,7 +75,7 @@ mod private /// - `values`: The new `TemplateValues` to be set. pub fn set_values( &mut self, values : TemplateValues ) { - self.values = values + self.values = values; } /// Returns a reference to the template values. @@ -79,6 +83,7 @@ mod private /// # Returns /// /// A reference to `TemplateValues`. + #[ must_use ] pub fn get_values( &self ) -> &TemplateValues { &self.values @@ -130,6 +135,7 @@ mod private } /// Fetches mandatory parameters that are not set yet. + #[ must_use ] pub fn get_missing_mandatory( &self ) -> Vec< &str > { let values = self.get_values(); @@ -137,7 +143,7 @@ mod private .parameters() .list_mandatory() .into_iter() - .filter( | key | values.0.get( *key ).map( | val | val.as_ref() ).flatten().is_none() ) + .filter( | key | values.0.get( *key ).and_then( | val | val.as_ref() ).is_none() ) .collect() } } @@ -150,10 +156,13 @@ mod private /// Creates all files in provided path with values for required parameters. /// /// Consumes owner of the files. + /// + /// # Errors + /// qqq: doc fn create_all( self, path : &Path, values : &TemplateValues ) -> error::untyped::Result< () > // qqq : use typed error { let fsw = FileSystem; - for file in self.into_iter() + for file in self { file.create_file( &fsw, path, values )?; } @@ -172,17 +181,19 @@ mod private impl TemplateParameters { /// Extracts template values from props for parameters required for this template. - pub fn values_from_props( &self, props : &wca::Props ) -> TemplateValues + #[ must_use ] + pub fn values_from_props( &self, props : &wca::executor::Props ) -> TemplateValues { let values = self.descriptors .iter() .map( | d | &d.parameter ) - .map( | param | ( param.clone(), props.get( param ).map( wca::Value::clone ) ) ) + .map( | param | ( param.clone(), props.get( param ).cloned() ) ) .collect(); TemplateValues( values ) } /// Get a list of all mandatory parameters. + #[ must_use ] pub fn list_mandatory( &self ) -> Vec< &str > { self.descriptors.iter().filter( | d | d.is_mandatory ).map( | d | d.parameter.as_str() ).collect() @@ -219,27 +230,28 @@ mod private /// Converts values to a serializable object. /// /// Currently only `String`, `Number`, and `Bool` are supported. + #[ must_use ] pub fn to_serializable( &self ) -> collection::BTreeMap< String, String > { self.0.iter().map ( | ( key, value ) | { - let value = value.as_ref().map + let value = value.as_ref().map_or ( + "___UNSPECIFIED___".to_string(), | value | { match value { wca::Value::String( val ) => val.to_string(), wca::Value::Number( val ) => val.to_string(), - wca::Value::Path( _ ) => "unsupported".to_string(), wca::Value::Bool( val ) => val.to_string(), + wca::Value::Path( _ ) | wca::Value::List( _ ) => "unsupported".to_string(), } } - ) - .unwrap_or( "___UNSPECIFIED___".to_string() ); + ); ( key.to_owned(), value ) } ) @@ -249,7 +261,7 @@ mod private /// Inserts new value if parameter wasn't initialized before. pub fn insert_if_empty( &mut self, key : &str, value : wca::Value ) { - if let None = self.0.get( key ).and_then( | v | v.as_ref() ) + if self.0.get( key ).and_then( | v | v.as_ref() ).is_none() { self.0.insert( key.into() , Some( value ) ); } @@ -258,7 +270,7 @@ mod private /// Interactively asks user to provide value for a parameter. pub fn interactive_if_empty( &mut self, key : &str ) { - if let None = self.0.get( key ).and_then( | v | v.as_ref() ) + if self.0.get( key ).and_then( | v | v.as_ref() ).is_none() { println! ("Parameter `{key}` is not set" ); let answer = wca::ask( "Enter value" ); @@ -299,7 +311,7 @@ mod private WriteMode::TomlExtend => { let instruction = FileReadInstruction { path : path.into() }; - if let Some(existing_contents) = fs.read( &instruction ).ok() + if let Ok( existing_contents ) = fs.read( &instruction ) { let document = contents.parse::< toml_edit::Document >().context( "Failed to parse template toml file" )?; let template_items = document.iter(); @@ -307,10 +319,10 @@ mod private let mut existing_document = existing_toml_contents.parse::< toml_edit::Document >().context( "Failed to parse existing toml file" )?; for ( template_key, template_item ) in template_items { - match existing_document.get_mut( &template_key ) + match existing_document.get_mut( template_key ) { - Some( item ) => *item = template_item.to_owned(), - None => existing_document[ &template_key ] = template_item.to_owned(), + Some( item ) => template_item.clone_into( item ), + None => template_item.clone_into( &mut existing_document[ template_key ] ), } } return Ok( existing_document.to_string() ); @@ -396,9 +408,13 @@ mod private pub trait FileSystemPort { /// Writing to file implementation. + /// # Errors + /// qqq: doc fn write( &self, instruction : &FileWriteInstruction ) -> error::untyped::Result< () >; // qqq : use typed error /// Reading from a file implementation. + /// # Errors + /// qqq: doc fn read( &self, instruction : &FileReadInstruction ) -> error::untyped::Result< Vec< u8 > >; // qqq : use typed error } diff --git a/module/move/willbe/src/tool/tree.rs b/module/move/willbe/src/tool/tree.rs index 3c1e0c670b..8525d0f2e0 100644 --- a/module/move/willbe/src/tool/tree.rs +++ b/module/move/willbe/src/tool/tree.rs @@ -1,3 +1,4 @@ +#[ allow( clippy::std_instead_of_alloc, clippy::std_instead_of_core ) ] mod private { use std::fmt::Write; @@ -26,7 +27,8 @@ mod private /// # Returns /// /// A new instance of `TreePrinter`. - pub fn new(info : &ListNodeReport) -> Self + #[ must_use ] + pub fn new(info : &ListNodeReport) -> Self { TreePrinter { @@ -44,15 +46,21 @@ mod private /// # Returns /// /// * A `Result` containing the formatted string or a `std::fmt::Error` if formatting fails. + /// + /// # Errors + /// qqq: doc + /// + /// # Panics + /// qqq: doc pub fn display_with_spacer( &self, spacer : &str ) -> Result< String, std::fmt::Error > { let mut f = String::new(); write!( f, "{}", self.info.name )?; if let Some( version ) = &self.info.version { write!( f, " {version}" )? } - if let Some( crate_dir ) = &self.info.crate_dir { write!( f, " {}", crate_dir )? } + if let Some( crate_dir ) = &self.info.crate_dir { write!( f, " {crate_dir}" )? } if self.info.duplicate { write!( f, "(*)" )? } - write!( f, "\n" )?; + writeln!( f )?; let mut new_spacer = format!( "{spacer}{} ", if self.info.normal_dependencies.len() < 2 { " " } else { self.symbols.down } ); @@ -72,7 +80,7 @@ mod private { let mut dev_dependencies_iter = self.info.dev_dependencies.iter(); let last = dev_dependencies_iter.next_back(); - write!( f, "{spacer}[dev-dependencies]\n" )?; + writeln!( f, "{spacer}[dev-dependencies]" )?; for dep in dev_dependencies_iter { write!( f, "{spacer}{}{} {}", self.symbols.tee, self.symbols.right, Self::display_with_spacer( &TreePrinter::new( dep ), &new_spacer )? )?; @@ -84,7 +92,7 @@ mod private { let mut build_dependencies_iter = self.info.build_dependencies.iter(); let last = build_dependencies_iter.next_back(); - write!( f, "{spacer}[build-dependencies]\n" )?; + writeln!( f, "{spacer}[build-dependencies]" )?; for dep in build_dependencies_iter { write!( f, "{spacer}{}{} {}", self.symbols.tee, self.symbols.right, Self::display_with_spacer( &TreePrinter::new( dep ), &new_spacer )? )?; @@ -146,15 +154,15 @@ mod private /// This field is a flag indicating whether the Node is a duplicate or not. pub duplicate : bool, /// A list that stores normal dependencies. - /// Each element in the list is also of the same 'ListNodeReport' type to allow + /// Each element in the list is also of the same '`ListNodeReport`' type to allow /// storage of nested dependencies. pub normal_dependencies : Vec< ListNodeReport >, /// A list that stores dev dependencies(dependencies required for tests or examples). - /// Each element in the list is also of the same 'ListNodeReport' type to allow + /// Each element in the list is also of the same '`ListNodeReport`' type to allow /// storage of nested dependencies. pub dev_dependencies : Vec< ListNodeReport >, /// A list that stores build dependencies. - /// Each element in the list is also of the same 'ListNodeReport' type to allow + /// Each element in the list is also of the same '`ListNodeReport`' type to allow /// storage of nested dependencies. pub build_dependencies : Vec< ListNodeReport >, } diff --git a/module/move/willbe/src/tool/url.rs b/module/move/willbe/src/tool/url.rs index f1ab5b8f9c..a7f76716c4 100644 --- a/module/move/willbe/src/tool/url.rs +++ b/module/move/willbe/src/tool/url.rs @@ -1,7 +1,7 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { - #[ allow( unused_imports ) ] + #[ allow( unused_imports, clippy::wildcard_imports ) ] use crate::tool::*; use error::untyped:: @@ -11,15 +11,16 @@ mod private }; /// Extracts the repository URL from a full URL. + #[ must_use ] pub fn repo_url_extract( full_url : &str ) -> Option< String > { let parts : Vec< &str > = full_url.split( '/' ).collect(); - if parts.len() >= 4 && parts[ 0 ] == "https:" && parts[ 1 ] == "" && parts[ 2 ] == "github.com" + if parts.len() >= 4 && parts[ 0 ] == "https:" && parts[ 1 ].is_empty() && parts[ 2 ] == "github.com" { let user = parts[ 3 ]; let repo = parts[ 4 ]; - let repo_url = format!( "https://github.com/{}/{}", user, repo ); + let repo_url = format!( "https://github.com/{user}/{repo}" ); Some( repo_url ) } else @@ -29,8 +30,10 @@ mod private } /// Extracts the username and repository name from a given URL. + /// # Errors + /// qqq: doc // qqq : use typed error - pub fn git_info_extract( url : &String ) -> error::untyped::Result< String > + pub fn git_info_extract( url : &str ) -> error::untyped::Result< String > { let parts : Vec< &str > = url.split( '/' ).collect(); if parts.len() >= 2 diff --git a/module/move/willbe/tests/asset/single_module/Cargo.toml b/module/move/willbe/tests/asset/single_module/Cargo.toml index 7e5912d446..a78145c170 100644 --- a/module/move/willbe/tests/asset/single_module/Cargo.toml +++ b/module/move/willbe/tests/asset/single_module/Cargo.toml @@ -5,6 +5,7 @@ members = [ ] [workspace.metadata] +workspace_name = "single_module" master_branch = "test_branch" project_name = "test" repo_url = "https://github.com/Username/test" diff --git a/module/move/willbe/tests/inc/action_tests/cicd_renew.rs b/module/move/willbe/tests/inc/action_tests/cicd_renew.rs index ffbbe5b570..75370b0db5 100644 --- a/module/move/willbe/tests/inc/action_tests/cicd_renew.rs +++ b/module/move/willbe/tests/inc/action_tests/cicd_renew.rs @@ -90,7 +90,7 @@ fn default_case() }; // Act - _ = action::cicd_renew( &temp ).unwrap(); + _ = action::cicd_renew::action( &temp ).unwrap(); dbg!( &file_path ); // Assert diff --git a/module/move/willbe/tests/inc/action_tests/features.rs b/module/move/willbe/tests/inc/action_tests/features.rs index 37a4b63cae..ea0e4e80a0 100644 --- a/module/move/willbe/tests/inc/action_tests/features.rs +++ b/module/move/willbe/tests/inc/action_tests/features.rs @@ -24,7 +24,7 @@ fn package_no_features() .form(); // Act - let report = willbe::action::features( options ).unwrap().to_string(); + let report = willbe::action::features::orphan::features( options ).unwrap().to_string(); // Assert assert!( report.contains( @@ -43,7 +43,7 @@ fn package_features() .form(); // Act - let report = willbe::action::features( options ).unwrap().to_string(); + let report = willbe::action::features::orphan::features( options ).unwrap().to_string(); // Assert assert!( report.contains( @@ -66,7 +66,7 @@ fn package_features_with_features_deps() .form(); // Act - let report = willbe::action::features( options ).unwrap().to_string(); + let report = willbe::action::features::orphan::features( options ).unwrap().to_string(); // Assert assert!( report.contains( @@ -89,7 +89,7 @@ fn workspace_no_features() .form(); // Act - let report = willbe::action::features( options ).unwrap().to_string(); + let report = willbe::action::features::orphan::features( options ).unwrap().to_string(); // Assert assert!( report.contains( @@ -118,7 +118,7 @@ fn workspace_features() .form(); // Act - let report = willbe::action::features( options ).unwrap().to_string(); + let report = willbe::action::features::orphan::features( options ).unwrap().to_string(); // Assert assert!( report.contains( @@ -156,7 +156,7 @@ fn workspace_features_with_features_deps() .form(); // Act - let report = willbe::action::features( options ).unwrap().to_string(); + let report = willbe::action::features::orphan::features( options ).unwrap().to_string(); // Assert assert!( report.contains( diff --git a/module/move/willbe/tests/inc/action_tests/list/data.rs b/module/move/willbe/tests/inc/action_tests/list/data.rs index 423baf654c..9100cf5dfb 100644 --- a/module/move/willbe/tests/inc/action_tests/list/data.rs +++ b/module/move/willbe/tests/inc/action_tests/list/data.rs @@ -44,7 +44,7 @@ mod chain_of_three_packages .form(); // Act - let output = action::list( args ).unwrap(); + let output = action::list_all( args ).unwrap(); // Assert let ListReport::Tree( trees ) = &output else { panic!( "Expected `Tree` format, but found another" ) }; @@ -85,7 +85,7 @@ mod chain_of_three_packages .form(); // Act - let output = action::list( args ).unwrap(); + let output = action::list_all( args ).unwrap(); // Assert let ListReport::List( names ) = &output else { panic!("Expected `Topological` format, but found another") }; @@ -106,7 +106,7 @@ mod chain_of_three_packages .form(); // Act - let output = action::list( args ).unwrap(); + let output = action::list_all( args ).unwrap(); // Assert let ListReport::List( names ) = &output else { panic!( "Expected `Topological` format, but found another" ) }; @@ -145,7 +145,7 @@ mod package_with_remote_dependency .form(); // Act - let output = action::list( args ).unwrap(); + let output = action::list_all( args ).unwrap(); // Assert let ListReport::Tree( trees ) = &output else { panic!( "Expected `Tree` format, but found another" ) }; @@ -183,7 +183,7 @@ mod package_with_remote_dependency .form(); // Act - let output = action::list( args ).unwrap(); + let output = action::list_all( args ).unwrap(); // Assert let ListReport::List( names ) = &output else { panic!( "Expected `Topological` format, but found another" ) }; @@ -208,7 +208,7 @@ mod package_with_remote_dependency .form(); // Act - let output = action::list( args ).unwrap(); + let output = action::list_all( args ).unwrap(); // Assert let ListReport::List( names ) = &output else { panic!( "Expected `Topological` format, but found another" ) }; @@ -242,7 +242,7 @@ mod workspace_with_cyclic_dependency .form(); // Act - let output = action::list( args ).unwrap(); + let output = action::list_all( args ).unwrap(); // Assert let ListReport::Tree( trees ) = &output else { panic!( "Expected `Tree` format, but found another" ) }; @@ -304,7 +304,7 @@ mod workspace_with_cyclic_dependency .form(); // Act - let output = action::list( args ); + let output = action::list_all( args ); // Assert diff --git a/module/move/willbe/tests/inc/action_tests/main_header.rs b/module/move/willbe/tests/inc/action_tests/main_header.rs index 82f1b89fba..6f65b44495 100644 --- a/module/move/willbe/tests/inc/action_tests/main_header.rs +++ b/module/move/willbe/tests/inc/action_tests/main_header.rs @@ -25,7 +25,7 @@ fn tag_shout_stay() let temp = arrange( "single_module" ); // Act - _ = action::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_header_renew::orphan::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "Readme.md" ) ).unwrap(); @@ -45,7 +45,7 @@ fn branch_cell() let temp = arrange( "single_module" ); // Act - _ = action::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_header_renew::orphan::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "Readme.md" ) ).unwrap(); @@ -64,7 +64,7 @@ fn discord_cell() let temp = arrange( "single_module" ); // Act - _ = action::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_header_renew::orphan::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "Readme.md" ) ).unwrap(); @@ -83,7 +83,7 @@ fn gitpod_cell() let temp = arrange( "single_module" ); // Act - _ = action::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_header_renew::orphan::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "Readme.md" ) ).unwrap(); @@ -102,7 +102,7 @@ fn docs_cell() let temp = arrange( "single_module" ); // Act - _ = action::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_header_renew::orphan::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "Readme.md" ) ).unwrap(); @@ -121,7 +121,7 @@ fn without_fool_config() let temp = arrange( "single_module_without_master_branch_and_discord" ); // Act - _ = action::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_header_renew::orphan::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "Readme.md" ) ).unwrap(); @@ -141,13 +141,13 @@ fn idempotency() let temp = arrange( "single_module" ); // Act - _ = action::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_header_renew::orphan::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "Readme.md" ) ).unwrap(); let mut actual1 = String::new(); _ = file.read_to_string( &mut actual1 ).unwrap(); drop( file ); - _ = action::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_header_renew::orphan::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "Readme.md" ) ).unwrap(); let mut actual2 = String::new(); _ = file.read_to_string( &mut actual2 ).unwrap(); @@ -164,5 +164,5 @@ fn without_needed_config() // Arrange let temp = arrange( "variadic_tag_configurations" ); // Act - _ = action::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_header_renew::orphan::readme_header_renew( AbsolutePath::try_from( temp.path() ).unwrap() ).unwrap(); } \ No newline at end of file diff --git a/module/move/willbe/tests/inc/action_tests/readme_health_table_renew.rs b/module/move/willbe/tests/inc/action_tests/readme_health_table_renew.rs index cce1e9065a..909a186116 100644 --- a/module/move/willbe/tests/inc/action_tests/readme_health_table_renew.rs +++ b/module/move/willbe/tests/inc/action_tests/readme_health_table_renew.rs @@ -23,7 +23,7 @@ fn without_any_toml_configurations_test() // Arrange let temp = arrange( "without_any_toml_configurations" ); // Act - _ = action::readme_health_table_renew( &temp ).unwrap(); + _ = action::readme_health_table_renew::orphan::readme_health_table_renew( &temp ).unwrap(); } #[ test ] @@ -33,7 +33,7 @@ fn tags_should_stay() let temp = arrange( "without_module_toml_configurations" ); // Act - _ = action::readme_health_table_renew( &temp ).unwrap(); + _ = action::readme_health_table_renew::orphan::readme_health_table_renew( &temp ).unwrap(); // Assert let mut file = std::fs::File::open( temp.path().join( "readme.md" ) ).unwrap(); @@ -52,7 +52,7 @@ fn stability_experimental_by_default() let temp = arrange( "without_module_toml_configurations" ); // Act - _ = action::readme_health_table_renew( &temp ).unwrap(); + _ = action::readme_health_table_renew::orphan::readme_health_table_renew( &temp ).unwrap(); // Assert let mut file = std::fs::File::open( temp.path().join( "readme.md" ) ).unwrap(); @@ -70,7 +70,7 @@ fn stability_and_repository_from_module_toml() let temp = arrange( "without_workspace_toml_configurations" ); // Act - _ = action::readme_health_table_renew( &temp ).unwrap(); + _ = action::readme_health_table_renew::orphan::readme_health_table_renew( &temp ).unwrap(); // Assert let mut file = std::fs::File::open( temp.path().join( "readme.md" ) ).unwrap(); @@ -101,7 +101,7 @@ fn variadic_tag_configuration_test() let temp = arrange( "variadic_tag_configurations" ); // Act - _ = action::readme_health_table_renew( &temp ).unwrap(); + _ = action::readme_health_table_renew::orphan::readme_health_table_renew( &temp ).unwrap(); // Assert let mut file = std::fs::File::open( temp.path().join( "readme.md" ) ).unwrap(); @@ -121,7 +121,7 @@ fn module_cell() let temp = arrange( "full_config" ); // Act - _ = action::readme_health_table_renew( &temp ).unwrap(); + _ = action::readme_health_table_renew::orphan::readme_health_table_renew( &temp ).unwrap(); // Assert let mut file = std::fs::File::open( temp.path().join( "readme.md" ) ).unwrap(); @@ -139,7 +139,7 @@ fn stability_cell() let temp = arrange( "full_config" ); // Act - _ = action::readme_health_table_renew( &temp ).unwrap(); + _ = action::readme_health_table_renew::orphan::readme_health_table_renew( &temp ).unwrap(); // Assert let mut file = std::fs::File::open( temp.path().join( "readme.md" ) ).unwrap(); @@ -157,7 +157,7 @@ fn branches_cell() let temp = arrange( "full_config" ); // Act - _ = action::readme_health_table_renew( &temp ).unwrap(); + _ = action::readme_health_table_renew::orphan::readme_health_table_renew( &temp ).unwrap(); // Assert let mut file = std::fs::File::open( temp.path().join( "readme.md" ) ).unwrap(); @@ -175,7 +175,7 @@ fn docs_cell() let temp = arrange( "full_config" ); // Act - _ = action::readme_health_table_renew( &temp ).unwrap(); + _ = action::readme_health_table_renew::orphan::readme_health_table_renew( &temp ).unwrap(); // Assert let mut file = std::fs::File::open( temp.path().join( "readme.md" ) ).unwrap(); @@ -193,7 +193,7 @@ fn sample_cell() let temp = arrange( "full_config" ); // Act - _ = action::readme_health_table_renew( &temp ).unwrap(); + _ = action::readme_health_table_renew::orphan::readme_health_table_renew( &temp ).unwrap(); // Assert let mut file = std::fs::File::open( temp.path().join( "readme.md" ) ).unwrap(); diff --git a/module/move/willbe/tests/inc/action_tests/readme_modules_headers_renew.rs b/module/move/willbe/tests/inc/action_tests/readme_modules_headers_renew.rs index db82f365ba..eed7873ef5 100644 --- a/module/move/willbe/tests/inc/action_tests/readme_modules_headers_renew.rs +++ b/module/move/willbe/tests/inc/action_tests/readme_modules_headers_renew.rs @@ -32,7 +32,9 @@ fn tags_should_stay() let temp = arrange( "single_module" ); // Act - _ = action::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_modules_headers_renew::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + // _ = action::main_header::action( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + let mut file = std::fs::File::open( temp.path().join( "test_module" ).join( "Readme.md" ) ).unwrap(); let mut actual = String::new(); @@ -51,7 +53,7 @@ fn default_stability() let temp = arrange( "single_module" ); // Act - _ = action::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_modules_headers_renew::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "test_module" ).join( "Readme.md" ) ).unwrap(); let mut actual = String::new(); @@ -70,7 +72,7 @@ fn docs() let temp = arrange( "single_module" ); // Act - _ = action::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_modules_headers_renew::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "test_module" ).join( "Readme.md" ) ).unwrap(); let mut actual = String::new(); @@ -88,7 +90,7 @@ fn no_gitpod() let temp = arrange("single_module"); // Act - _ = action::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_modules_headers_renew::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open(temp.path().join("test_module").join("Readme.md")).unwrap(); let mut actual = String::new(); @@ -105,7 +107,7 @@ fn with_gitpod() let temp = arrange( "single_module_with_example" ); // Act - _ = action::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_modules_headers_renew::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "module" ).join( "test_module" ).join( "Readme.md" ) ).unwrap(); let mut actual = String::new(); @@ -123,7 +125,7 @@ fn discord() let temp = arrange( "single_module" ); // Act - _ = action::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_modules_headers_renew::readme_modules_headers_renew(CrateDir::try_from(temp.path()).unwrap()).unwrap(); let mut file = std::fs::File::open( temp.path().join( "test_module" ).join( "Readme.md" ) ).unwrap(); let mut actual = String::new(); @@ -141,7 +143,7 @@ fn status() let temp = arrange( "single_module" ); // Act - _ = action::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_modules_headers_renew::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "test_module" ).join( "Readme.md" ) ).unwrap(); let mut actual = String::new(); @@ -159,13 +161,13 @@ fn idempotency() let temp = arrange( "single_module" ); // Act - _ = action::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_modules_headers_renew::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "test_module" ).join( "Readme.md" ) ).unwrap(); let mut actual1 = String::new(); _ = file.read_to_string( &mut actual1 ).unwrap(); drop( file ); - _ = action::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_modules_headers_renew::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); let mut file = std::fs::File::open( temp.path().join( "test_module" ).join( "Readme.md" ) ).unwrap(); let mut actual2 = String::new(); _ = file.read_to_string( &mut actual2 ).unwrap(); @@ -180,7 +182,7 @@ fn with_many_members_and_varius_config() { let temp = arrange( "three_packages" ); - _ = action::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::readme_modules_headers_renew::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); let mut file_b = std::fs::File::open( temp.path().join( "b" ).join( "Readme.md" ) ).unwrap(); let mut file_c = std::fs::File::open( temp.path().join( "c" ).join( "Readme.md" ) ).unwrap(); @@ -207,5 +209,5 @@ fn without_needed_config() let temp = arrange( "variadic_tag_configurations" ); // Act - _ = action::readme_modules_headers_renew( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); + _ = action::main_header::action( CrateDir::try_from( temp.path() ).unwrap() ).unwrap(); } diff --git a/module/move/willbe/tests/inc/action_tests/test.rs b/module/move/willbe/tests/inc/action_tests/test.rs index 16a4e8cd6a..67c926cb89 100644 --- a/module/move/willbe/tests/inc/action_tests/test.rs +++ b/module/move/willbe/tests/inc/action_tests/test.rs @@ -1,21 +1,13 @@ use super::*; -// use the_module::*; // qqq : for Bohdan : bad. don't import the_module::* use inc::helper:: { ProjectBuilder, WorkspaceBuilder, - // BINARY_NAME, }; use collection::BTreeSet; -// use std:: -// { -// fs::{ self, File }, -// io::Write, -// }; -// use path::{ Path, PathBuf }; use assert_fs::TempDir; use the_module::action::test::{ test, TestsCommandOptions }; diff --git a/module/move/willbe/tests/inc/action_tests/workspace_renew.rs b/module/move/willbe/tests/inc/action_tests/workspace_renew.rs index 9dbfcea23d..4790c39f25 100644 --- a/module/move/willbe/tests/inc/action_tests/workspace_renew.rs +++ b/module/move/willbe/tests/inc/action_tests/workspace_renew.rs @@ -26,7 +26,7 @@ fn default_case() create_dir(temp.join("test_project_name" )).unwrap(); // Act - _ = workspace_renew( &temp.path().join( "test_project_name" ), WorkspaceTemplate::default(), "https://github.con/Username/TestRepository".to_string(), vec![ "master".to_string() ] ).unwrap(); + _ = workspace_renew::action( &temp.path().join( "test_project_name" ), WorkspaceTemplate::default(), "https://github.con/Username/TestRepository".to_string(), vec![ "master".to_string() ] ).unwrap(); // Assets assert!( temp_path.join( "module" ).exists() ); @@ -57,7 +57,7 @@ fn non_empty_dir() let temp = arrange( "single_module" ); // Act - let r = workspace_renew( temp.path(), WorkspaceTemplate::default(), "".to_string(), vec![] ); + let r = workspace_renew::action( temp.path(), WorkspaceTemplate::default(), "".to_string(), vec![] ); // Assert assert!( r.is_err() ); diff --git a/module/move/willbe/tests/inc/mod.rs b/module/move/willbe/tests/inc/mod.rs index ca9dbda05d..0b456a9b87 100644 --- a/module/move/willbe/tests/inc/mod.rs +++ b/module/move/willbe/tests/inc/mod.rs @@ -14,6 +14,8 @@ mod action_tests; mod helper; +mod package; + // aaa : for Petro : for Bohdan : for Nikita : sort out test files to be consistent with src files // sorted diff --git a/module/move/willbe/tests/inc/package.rs b/module/move/willbe/tests/inc/package.rs index 8a5fb2a2f0..bc83b38d89 100644 --- a/module/move/willbe/tests/inc/package.rs +++ b/module/move/willbe/tests/inc/package.rs @@ -1,3 +1,310 @@ +use std::*; +use std::io::Write; + +use crate::the_module::{ action, channel, package }; + +enum Dependency +{ + Normal { name: String, path: Option< path::PathBuf >, is_macro: bool }, + Dev { name: String, path: Option< path::PathBuf >, is_macro: bool }, +} + +impl Dependency +{ + fn as_toml( &self ) -> String + { + match self + { + Dependency::Normal { name, path, is_macro } if !is_macro => + if let Some( path ) = path + { + format!( "[dependencies.{name}]\npath = \"../{}\"", path.display().to_string().replace( "\\", "/" ) ) + } + else + { + format!( "[dependencies.{name}]\nversion = \"*\"" ) + } + Dependency::Normal { name, .. } => format!( "[dependencies.{name}]\nworkspace = true" ), + Dependency::Dev { name, path, is_macro } if !is_macro => + if let Some( path ) = path + { + format!( "[dev-dependencies.{name}]\npath = \"../{}\"", path.display().to_string().replace( "\\", "/" ) ) + } + else + { + format!( "[dev-dependencies.{name}]\nversion = \"*\"" ) + } + Dependency::Dev { name, .. } => format!( "[dev-dependencies.{name}]\nworkspace = true" ), + } + } +} + +struct TestPackage +{ + name: String, + dependencies: Vec< Dependency >, + path: Option< path::PathBuf >, +} + +impl TestPackage +{ + pub fn new( name: impl Into< String > ) -> Self + { + Self { name: name.into(), dependencies: vec![], path: None } + } + + pub fn dependency( mut self, name: impl Into< String > ) -> Self + { + self.dependencies.push( Dependency::Normal { name: name.into(), path: None, is_macro: false } ); + self + } + + pub fn macro_dependency( mut self, name: impl Into< String > ) -> Self + { + self.dependencies.push( Dependency::Normal { name: name.into(), path: None, is_macro: true } ); + self + } + + pub fn dev_dependency( mut self, name: impl Into< String > ) -> Self + { + self.dependencies.push( Dependency::Dev { name: name.into(), path: None, is_macro: false } ); + self + } + + pub fn macro_dev_dependency( mut self, name: impl Into< String > ) -> Self + { + self.dependencies.push( Dependency::Dev { name: name.into(), path: None, is_macro: true } ); + self + } + + pub fn create( &mut self, path: impl AsRef< path::Path > ) -> io::Result< () > + { + let path = path.as_ref().join( &self.name ); + + () = fs::create_dir_all( path.join( "src" ) )?; + () = fs::write( path.join( "src" ).join( "lib.rs" ), &[] )?; + + let cargo = format! + ( + r#"[package] +name = "{}" +version = "0.1.0" +edition = "2021" +{}"#, + self.name, + self.dependencies.iter().map( Dependency::as_toml ).fold( String::new(), | acc, d | + { + format!( "{acc}\n\n{d}" ) + }) + ); + () = fs::write( path.join( "Cargo.toml" ), cargo.as_bytes() )?; + + self.path = Some( path ); + + Ok( () ) + } +} + +impl Drop for TestPackage +{ + fn drop( &mut self ) + { + if let Some( path ) = &self.path + { + _ = fs::remove_dir_all( path ).ok(); + } + } +} + +struct TestWorkspace +{ + packages: Vec< TestPackage >, + path: path::PathBuf, +} + +impl TestWorkspace +{ + fn new( path: impl AsRef< path::Path > ) -> io::Result< Self > + { + let path = path.as_ref(); + () = fs::create_dir_all( path )?; + + let cargo = r#"[workspace] +resolver = "2" +members = [ + "members/*", +] +"#; + () = fs::write( path.join( "Cargo.toml" ), cargo.as_bytes() )?; + + Ok(Self { packages: vec![], path: path.into() }) + } + + fn find( &self, package_name: impl AsRef< str > ) -> Option< &TestPackage > + { + let name = package_name.as_ref(); + self.packages.iter().find( | p | p.name == name ) + } + + fn with_package( mut self, mut package: TestPackage ) -> io::Result< Self > + { + let mut macro_deps = collections::HashMap::new(); + for dep in &mut package.dependencies + { + match dep + { + Dependency::Normal { name, is_macro, .. } if *is_macro => + { + if let Some( package ) = self.find( &name ) + { + if let Some( path ) = &package.path + { + macro_deps.insert( name.clone(), path.clone() ); + continue; + } + } + eprintln!( "macro dependency {} not found. required for {}", name, package.name ); + } + Dependency::Normal { name, path, .. } => + { + if let Some( package ) = self.find( &name ) + { + if let Some( real_path ) = &package.path + { + let real_path = real_path.strip_prefix( self.path.join( "members" ) ).unwrap_or( real_path ); + *path = Some( real_path.into() ); + } + } + } + Dependency::Dev { name, is_macro, .. } if *is_macro => + { + if let Some( package ) = self.find( &name ) + { + if let Some( path ) = &package.path + { + macro_deps.insert( name.clone(), path.clone() ); + continue; + } + } + eprintln!( "macro dev-dependency {} not found. required for {}", name, package.name ); + } + Dependency::Dev { name, path, .. } => + { + if let Some( package ) = self.find( &name ) + { + if let Some( real_path ) = &package.path + { + let real_path = real_path.strip_prefix( self.path.join( "members" ) ).unwrap_or( real_path ); + *path = Some( real_path.into() ); + } + } + } + } + } + let mut cargo = fs::OpenOptions::new().append( true ).open( self.path.join( "Cargo.toml" ) )?; + for ( name, _ ) in macro_deps + { + writeln!( cargo, + r#"[workspace.dependencies.{name}] +version = "*" +path = "members/{name}""#, + )?; + } + package.create( self.path.join( "members" ) )?; + self.packages.push( package ); + + Ok( self ) + } + + fn with_packages( mut self, packages: impl IntoIterator< Item = TestPackage > ) -> io::Result< Self > + { + for package in packages { self = self.with_package( package )?; } + + Ok( self ) + } +} + +impl Drop for TestWorkspace +{ + fn drop( &mut self ) + { + _ = fs::remove_dir_all( &self.path ).ok(); + } +} + +#[ test ] +fn kos_plan() +{ + let tmp_folder = env::temp_dir().join( "publish_plan_kos_plan" ); + _ = fs::remove_dir_all( &tmp_folder ).ok(); + + let workspace = TestWorkspace::new( tmp_folder ).unwrap() + .with_packages( + [ + TestPackage::new( "a" ), + TestPackage::new( "b" ).dependency( "a" ), + TestPackage::new( "c" ).dependency( "a" ), + TestPackage::new( "d" ).dependency( "a" ), + TestPackage::new( "e" ).dependency( "b" ).macro_dev_dependency( "c" ),//.macro_dependency( "c" ), + ]).unwrap(); + let the_patterns: Vec< String > = workspace + .packages + .iter() + .flat_map( | p | p.path.as_ref().map( | p | p.to_string_lossy().into_owned() ) ) + .collect(); + dbg!(&the_patterns); + + let plan = action::publish_plan + ( + the_patterns, + channel::Channel::Stable, + false, + false, + true, + false, + ) + .unwrap(); + + let queue: Vec< &package::PackageName > = plan.plans.iter().map( | i | &i.package_name ).collect(); + dbg!(&queue); + + // We don’t consider dev dependencies when constructing the project graph, which results in this number of variations. + // If you'd like to modify this behavior, please check `entity/workspace_graph.rs` in the `module_dependency_filter`. + let expected_one_of= + [ + [ "a", "b", "d", "c", "e" ], + [ "a", "b", "c", "d", "e" ], + [ "a", "d", "b", "c", "e" ], + [ "a", "c", "b", "d", "e" ], + [ "a", "d", "c", "b", "e" ], + [ "a", "c", "d", "b", "e" ], + [ "a", "b", "d", "e", "c" ], + [ "a", "d", "b", "e", "c" ], + [ "a", "b", "e", "d", "c" ], + [ "a", "e", "b", "d", "c" ], + [ "a", "d", "e", "b", "c" ], + [ "a", "e", "d", "b", "c" ], + [ "a", "b", "c", "e", "d" ], + [ "a", "c", "b", "e", "d" ], + [ "a", "b", "e", "c", "d" ], + [ "a", "e", "b", "c", "d" ], + [ "a", "c", "e", "b", "d" ], + [ "a", "e", "c", "b", "d" ], + ]; + + let mut fail = true; + 'sequences: for sequence in expected_one_of + { + for index in 0 .. 5 + { + if *queue[ index ] != sequence[ index ].to_string().into() { continue 'sequences; } + } + fail = false; + break; + } + assert!( !fail ); +} + // use super::*; // use the_module:: // { diff --git a/module/move/willbe/tests/inc/tool/graph_test.rs b/module/move/willbe/tests/inc/tool/graph_test.rs index 75a2b29db3..0ad57fa024 100644 --- a/module/move/willbe/tests/inc/tool/graph_test.rs +++ b/module/move/willbe/tests/inc/tool/graph_test.rs @@ -3,7 +3,7 @@ use super::*; // qqq : for Bohdan : bad. don't import the_module::* // use the_module::*; use the_module::graph::toposort; -use collection::HashMap; +use test_tools::collection::HashMap; use petgraph::Graph; use willbe::graph::topological_sort_with_grouping; diff --git a/module/move/wplot/src/plot/abs/change.rs b/module/move/wplot/src/plot/abs/change.rs index 660a54e108..ad2a0219a2 100644 --- a/module/move/wplot/src/plot/abs/change.rs +++ b/module/move/wplot/src/plot/abs/change.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/abs/changer.rs b/module/move/wplot/src/plot/abs/changer.rs index 3315e82b38..9c91ad95c2 100644 --- a/module/move/wplot/src/plot/abs/changer.rs +++ b/module/move/wplot/src/plot/abs/changer.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/abs/context.rs b/module/move/wplot/src/plot/abs/context.rs index c666e3edca..a27efc6748 100644 --- a/module/move/wplot/src/plot/abs/context.rs +++ b/module/move/wplot/src/plot/abs/context.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( not( feature = "no_std" ) ) ] mod private { diff --git a/module/move/wplot/src/plot/abs/identity.rs b/module/move/wplot/src/plot/abs/identity.rs index 48d9c0426a..9abecc7727 100644 --- a/module/move/wplot/src/plot/abs/identity.rs +++ b/module/move/wplot/src/plot/abs/identity.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( not( feature = "no_std" ) ) ] mod private { diff --git a/module/move/wplot/src/plot/abs/registry.rs b/module/move/wplot/src/plot/abs/registry.rs index 026c0f5c20..c69f775dca 100644 --- a/module/move/wplot/src/plot/abs/registry.rs +++ b/module/move/wplot/src/plot/abs/registry.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. #[ cfg( not( feature = "no_std" ) ) ] mod private { diff --git a/module/move/wplot/src/plot/color.rs b/module/move/wplot/src/plot/color.rs index 5cf94b95c8..3ae327c824 100644 --- a/module/move/wplot/src/plot/color.rs +++ b/module/move/wplot/src/plot/color.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/context.rs b/module/move/wplot/src/plot/sys/context.rs index a59ae6343d..19bd3ce2a9 100644 --- a/module/move/wplot/src/plot/sys/context.rs +++ b/module/move/wplot/src/plot/sys/context.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::abs::registry::private::Registry; diff --git a/module/move/wplot/src/plot/sys/context_changer.rs b/module/move/wplot/src/plot/sys/context_changer.rs index e6a91ca8e5..c0f1df3442 100644 --- a/module/move/wplot/src/plot/sys/context_changer.rs +++ b/module/move/wplot/src/plot/sys/context_changer.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/drawing.rs b/module/move/wplot/src/plot/sys/drawing.rs index 673fd1fa74..9e668966be 100644 --- a/module/move/wplot/src/plot/sys/drawing.rs +++ b/module/move/wplot/src/plot/sys/drawing.rs @@ -1,6 +1,6 @@ pub(crate) mod changer; -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/drawing/change_new.rs b/module/move/wplot/src/plot/sys/drawing/change_new.rs index ab075de7fa..f7628c2566 100644 --- a/module/move/wplot/src/plot/sys/drawing/change_new.rs +++ b/module/move/wplot/src/plot/sys/drawing/change_new.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/drawing/changer.rs b/module/move/wplot/src/plot/sys/drawing/changer.rs index a7ba4c1b67..84c69db2c3 100644 --- a/module/move/wplot/src/plot/sys/drawing/changer.rs +++ b/module/move/wplot/src/plot/sys/drawing/changer.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/drawing/command.rs b/module/move/wplot/src/plot/sys/drawing/command.rs index f98cedfd22..998272ee16 100644 --- a/module/move/wplot/src/plot/sys/drawing/command.rs +++ b/module/move/wplot/src/plot/sys/drawing/command.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/drawing/queue.rs b/module/move/wplot/src/plot/sys/drawing/queue.rs index c68de594ba..c3148011bb 100644 --- a/module/move/wplot/src/plot/sys/drawing/queue.rs +++ b/module/move/wplot/src/plot/sys/drawing/queue.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/drawing/rect_change_new.rs b/module/move/wplot/src/plot/sys/drawing/rect_change_new.rs index 212ffb82c1..b682c0ead8 100644 --- a/module/move/wplot/src/plot/sys/drawing/rect_change_new.rs +++ b/module/move/wplot/src/plot/sys/drawing/rect_change_new.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/drawing/rect_change_region.rs b/module/move/wplot/src/plot/sys/drawing/rect_change_region.rs index 463259b6cf..29b6885e63 100644 --- a/module/move/wplot/src/plot/sys/drawing/rect_change_region.rs +++ b/module/move/wplot/src/plot/sys/drawing/rect_change_region.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/drawing/rect_changer.rs b/module/move/wplot/src/plot/sys/drawing/rect_changer.rs index bb25c465aa..7e39fb06fc 100644 --- a/module/move/wplot/src/plot/sys/drawing/rect_changer.rs +++ b/module/move/wplot/src/plot/sys/drawing/rect_changer.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/stroke_brush.rs b/module/move/wplot/src/plot/sys/stroke_brush.rs index 78ad289dc7..9f52539630 100644 --- a/module/move/wplot/src/plot/sys/stroke_brush.rs +++ b/module/move/wplot/src/plot/sys/stroke_brush.rs @@ -1,7 +1,7 @@ mod change_width; mod change_new; -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/stroke_brush/change_color.rs b/module/move/wplot/src/plot/sys/stroke_brush/change_color.rs index ae615f89a4..76bd951613 100644 --- a/module/move/wplot/src/plot/sys/stroke_brush/change_color.rs +++ b/module/move/wplot/src/plot/sys/stroke_brush/change_color.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/stroke_brush/change_new.rs b/module/move/wplot/src/plot/sys/stroke_brush/change_new.rs index 077f20f6ba..4e70ba7ee7 100644 --- a/module/move/wplot/src/plot/sys/stroke_brush/change_new.rs +++ b/module/move/wplot/src/plot/sys/stroke_brush/change_new.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/stroke_brush/change_width.rs b/module/move/wplot/src/plot/sys/stroke_brush/change_width.rs index cf5a548778..a7fcecdcb8 100644 --- a/module/move/wplot/src/plot/sys/stroke_brush/change_width.rs +++ b/module/move/wplot/src/plot/sys/stroke_brush/change_width.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/stroke_brush/changer.rs b/module/move/wplot/src/plot/sys/stroke_brush/changer.rs index 407b234fac..152dfebaab 100644 --- a/module/move/wplot/src/plot/sys/stroke_brush/changer.rs +++ b/module/move/wplot/src/plot/sys/stroke_brush/changer.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::own::*; diff --git a/module/move/wplot/src/plot/sys/target.rs b/module/move/wplot/src/plot/sys/target.rs index 58634c4e36..95d123186b 100644 --- a/module/move/wplot/src/plot/sys/target.rs +++ b/module/move/wplot/src/plot/sys/target.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::prelude::*; diff --git a/module/postponed/non_std/Cargo.toml b/module/postponed/non_std/Cargo.toml index 516d197d99..1f684f13cb 100644 --- a/module/postponed/non_std/Cargo.toml +++ b/module/postponed/non_std/Cargo.toml @@ -72,7 +72,7 @@ meta_default = [ "meta_mod_interface", # "meta_former", # "meta_options", - "meta_constructors", + #"meta_constructors", "meta_idents_concat", ] meta_full = [ @@ -82,7 +82,7 @@ meta_full = [ "meta_mod_interface", # "meta_former", # "meta_options", - "meta_constructors", + #"meta_constructors", "meta_idents_concat", ] meta_no_std = [ "wtools/meta_no_std" ] diff --git a/module/postponed/std_tools/Cargo.toml b/module/postponed/std_tools/Cargo.toml index 44d29afa00..928fe93678 100644 --- a/module/postponed/std_tools/Cargo.toml +++ b/module/postponed/std_tools/Cargo.toml @@ -73,7 +73,7 @@ meta_default = [ "meta_mod_interface", # "meta_former", # "meta_options", - "meta_constructors", + #"meta_constructors", "meta_idents_concat", ] meta_full = [ @@ -83,7 +83,7 @@ meta_full = [ "meta_mod_interface", # "meta_former", # "meta_options", - "meta_constructors", + #"meta_constructors", "meta_idents_concat", ] meta_no_std = [ "wtools/meta_no_std" ] diff --git a/module/postponed/std_x/Cargo.toml b/module/postponed/std_x/Cargo.toml index 5693aa40a1..2ee0a6f55c 100644 --- a/module/postponed/std_x/Cargo.toml +++ b/module/postponed/std_x/Cargo.toml @@ -75,7 +75,7 @@ meta_default = [ "meta_mod_interface", # "meta_former", # "meta_options", - "meta_constructors", + #"meta_constructors", "meta_idents_concat", ] meta_full = [ @@ -85,7 +85,7 @@ meta_full = [ "meta_mod_interface", # "meta_former", # "meta_options", - "meta_constructors", + #"meta_constructors", "meta_idents_concat", ] meta_no_std = [ "wtools/meta_no_std" ] diff --git a/module/postponed/type_constructor/src/type_constuctor/enumerable.rs b/module/postponed/type_constructor/src/type_constuctor/enumerable.rs index e17553d21c..fdfa45fb97 100644 --- a/module/postponed/type_constructor/src/type_constuctor/enumerable.rs +++ b/module/postponed/type_constructor/src/type_constuctor/enumerable.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/postponed/type_constructor/src/type_constuctor/helper.rs b/module/postponed/type_constructor/src/type_constuctor/helper.rs index 57c9986a69..a4dcf9011f 100644 --- a/module/postponed/type_constructor/src/type_constuctor/helper.rs +++ b/module/postponed/type_constructor/src/type_constuctor/helper.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::exposed::*; diff --git a/module/postponed/type_constructor/src/type_constuctor/make.rs b/module/postponed/type_constructor/src/type_constuctor/make.rs index 807974a4ca..2cdb6d6973 100644 --- a/module/postponed/type_constructor/src/type_constuctor/make.rs +++ b/module/postponed/type_constructor/src/type_constuctor/make.rs @@ -1,4 +1,4 @@ -// /// Internal namespace. +// /// Define a private namespace for all its items. // #[ cfg( feature = "make" ) ] // mod private // { diff --git a/module/postponed/type_constructor/src/type_constuctor/many.rs b/module/postponed/type_constructor/src/type_constuctor/many.rs index 0c81d87180..3ded63125c 100644 --- a/module/postponed/type_constructor/src/type_constuctor/many.rs +++ b/module/postponed/type_constructor/src/type_constuctor/many.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::exposed::*; diff --git a/module/postponed/type_constructor/src/type_constuctor/no_many.rs b/module/postponed/type_constructor/src/type_constuctor/no_many.rs index a36e9829ef..d810f74d08 100644 --- a/module/postponed/type_constructor/src/type_constuctor/no_many.rs +++ b/module/postponed/type_constructor/src/type_constuctor/no_many.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/postponed/type_constructor/src/type_constuctor/pair.rs b/module/postponed/type_constructor/src/type_constuctor/pair.rs index 090428e500..56b71bc2ff 100644 --- a/module/postponed/type_constructor/src/type_constuctor/pair.rs +++ b/module/postponed/type_constructor/src/type_constuctor/pair.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::exposed::*; diff --git a/module/postponed/type_constructor/src/type_constuctor/single.rs b/module/postponed/type_constructor/src/type_constuctor/single.rs index 7fcf8642f4..2fd3637235 100644 --- a/module/postponed/type_constructor/src/type_constuctor/single.rs +++ b/module/postponed/type_constructor/src/type_constuctor/single.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::exposed::*; diff --git a/module/postponed/type_constructor/src/type_constuctor/traits.rs b/module/postponed/type_constructor/src/type_constuctor/traits.rs index cd11c438ee..cf4838bee3 100644 --- a/module/postponed/type_constructor/src/type_constuctor/traits.rs +++ b/module/postponed/type_constructor/src/type_constuctor/traits.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/postponed/type_constructor/src/type_constuctor/types.rs b/module/postponed/type_constructor/src/type_constuctor/types.rs index 151b33ae42..d9d1de235a 100644 --- a/module/postponed/type_constructor/src/type_constuctor/types.rs +++ b/module/postponed/type_constructor/src/type_constuctor/types.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::exposed::*; diff --git a/module/postponed/type_constructor/src/type_constuctor/vectorized_from.rs b/module/postponed/type_constructor/src/type_constuctor/vectorized_from.rs index c7e366142a..c145e31404 100644 --- a/module/postponed/type_constructor/src/type_constuctor/vectorized_from.rs +++ b/module/postponed/type_constructor/src/type_constuctor/vectorized_from.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { diff --git a/module/postponed/wautomata/src/graph/abs/edge.rs b/module/postponed/wautomata/src/graph/abs/edge.rs index 550a350efb..214f8f10d9 100644 --- a/module/postponed/wautomata/src/graph/abs/edge.rs +++ b/module/postponed/wautomata/src/graph/abs/edge.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/postponed/wautomata/src/graph/abs/factory.rs b/module/postponed/wautomata/src/graph/abs/factory.rs index 737cbfdf5c..ddf6012168 100644 --- a/module/postponed/wautomata/src/graph/abs/factory.rs +++ b/module/postponed/wautomata/src/graph/abs/factory.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/postponed/wautomata/src/graph/abs/id_generator.rs b/module/postponed/wautomata/src/graph/abs/id_generator.rs index 943315c041..2090439804 100644 --- a/module/postponed/wautomata/src/graph/abs/id_generator.rs +++ b/module/postponed/wautomata/src/graph/abs/id_generator.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::prelude::*; diff --git a/module/postponed/wautomata/src/graph/abs/identity.rs b/module/postponed/wautomata/src/graph/abs/identity.rs index c7fdcb3797..1e9c21d2f9 100644 --- a/module/postponed/wautomata/src/graph/abs/identity.rs +++ b/module/postponed/wautomata/src/graph/abs/identity.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { // use crate::prelude::*; diff --git a/module/postponed/wautomata/src/graph/abs/node.rs b/module/postponed/wautomata/src/graph/abs/node.rs index b227581718..703bd0893d 100644 --- a/module/postponed/wautomata/src/graph/abs/node.rs +++ b/module/postponed/wautomata/src/graph/abs/node.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/postponed/wautomata/src/graph/algo/dfs.rs b/module/postponed/wautomata/src/graph/algo/dfs.rs index 0a75884e2c..13e7c81e84 100644 --- a/module/postponed/wautomata/src/graph/algo/dfs.rs +++ b/module/postponed/wautomata/src/graph/algo/dfs.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/postponed/wautomata/src/graph/canonical/edge.rs b/module/postponed/wautomata/src/graph/canonical/edge.rs index 3bf782aaee..4d02b207d4 100644 --- a/module/postponed/wautomata/src/graph/canonical/edge.rs +++ b/module/postponed/wautomata/src/graph/canonical/edge.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/postponed/wautomata/src/graph/canonical/factory_generative.rs b/module/postponed/wautomata/src/graph/canonical/factory_generative.rs index 766002bfb3..0548aa26c5 100644 --- a/module/postponed/wautomata/src/graph/canonical/factory_generative.rs +++ b/module/postponed/wautomata/src/graph/canonical/factory_generative.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/postponed/wautomata/src/graph/canonical/factory_readable.rs b/module/postponed/wautomata/src/graph/canonical/factory_readable.rs index d9505b7819..1cad2804dd 100644 --- a/module/postponed/wautomata/src/graph/canonical/factory_readable.rs +++ b/module/postponed/wautomata/src/graph/canonical/factory_readable.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/postponed/wautomata/src/graph/canonical/identity.rs b/module/postponed/wautomata/src/graph/canonical/identity.rs index 497da5ff54..6680ead861 100644 --- a/module/postponed/wautomata/src/graph/canonical/identity.rs +++ b/module/postponed/wautomata/src/graph/canonical/identity.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/postponed/wautomata/src/graph/canonical/node.rs b/module/postponed/wautomata/src/graph/canonical/node.rs index 94d7f7d313..ce0aa547bd 100644 --- a/module/postponed/wautomata/src/graph/canonical/node.rs +++ b/module/postponed/wautomata/src/graph/canonical/node.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use crate::prelude::*; diff --git a/module/step/meta/src/module/terminal.rs b/module/step/meta/src/module/terminal.rs index 93289921c5..4a88acf6a9 100644 --- a/module/step/meta/src/module/terminal.rs +++ b/module/step/meta/src/module/terminal.rs @@ -1,4 +1,6 @@ +/// Mechanism to include tests only to terminal crate. +/// It exclude code in terminal module ( crate ), but include for aggregating module ( crate ). #[ macro_export ] macro_rules! only_for_terminal_module { @@ -8,6 +10,8 @@ macro_rules! only_for_terminal_module }; } +/// Mechanism to include tests only to aggregating crate. +/// It exclude code in terminal module ( crate ), but include for aggregating module ( crate ). #[ macro_export ] macro_rules! only_for_aggregating_module { diff --git a/module/step/meta/tests/_conditional/local_module.rs b/module/step/meta/tests/_conditional/local_module.rs index 93289921c5..4a88acf6a9 100644 --- a/module/step/meta/tests/_conditional/local_module.rs +++ b/module/step/meta/tests/_conditional/local_module.rs @@ -1,4 +1,6 @@ +/// Mechanism to include tests only to terminal crate. +/// It exclude code in terminal module ( crate ), but include for aggregating module ( crate ). #[ macro_export ] macro_rules! only_for_terminal_module { @@ -8,6 +10,8 @@ macro_rules! only_for_terminal_module }; } +/// Mechanism to include tests only to aggregating crate. +/// It exclude code in terminal module ( crate ), but include for aggregating module ( crate ). #[ macro_export ] macro_rules! only_for_aggregating_module { diff --git a/module/step/meta/tests/_conditional/wtools.rs b/module/step/meta/tests/_conditional/wtools.rs index e6bb553f35..ba669c790d 100644 --- a/module/step/meta/tests/_conditional/wtools.rs +++ b/module/step/meta/tests/_conditional/wtools.rs @@ -1,4 +1,6 @@ +/// Mechanism to include tests only to terminal crate. +/// It exclude code in terminal module ( crate ), but include for aggregating module ( crate ). #[ macro_export ] macro_rules! only_for_terminal_module { @@ -7,6 +9,8 @@ macro_rules! only_for_terminal_module } } +/// Mechanism to include tests only to aggregating crate. +/// It exclude code in terminal module ( crate ), but include for aggregating module ( crate ). #[ macro_export ] macro_rules! only_for_aggregating_module { diff --git a/module/template/layer/layer.rs b/module/template/layer/layer.rs index 45d766e897..b4b8322d92 100644 --- a/module/template/layer/layer.rs +++ b/module/template/layer/layer.rs @@ -1,4 +1,4 @@ -/// Internal namespace. +/// Define a private namespace for all its items. mod private { use super::super::*;