diff --git a/Cargo.lock b/Cargo.lock index 9f24ab1..c7cc4b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,15 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bok" version = "0.1.0" @@ -66,6 +75,7 @@ dependencies = [ "paste", "proc-macro2", "quote", + "sha3", ] [[package]] @@ -87,6 +97,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", + "sha3", "syn", ] @@ -138,6 +149,45 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "heck" version = "0.5.0" @@ -150,6 +200,21 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "libc" +version = "0.2.162" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" + [[package]] name = "paste" version = "1.0.15" @@ -184,6 +249,16 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + [[package]] name = "strsim" version = "0.11.1" @@ -201,6 +276,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicase" version = "2.8.0" @@ -225,6 +306,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "windows-sys" version = "0.59.0" diff --git a/bok-macro/src/lib.rs b/bok-macro/src/lib.rs index 33d17f3..b16bfa4 100644 --- a/bok-macro/src/lib.rs +++ b/bok-macro/src/lib.rs @@ -1,9 +1,9 @@ /* * Copyright 2024 Luca Fulchir * - * Licensed under the Apache License, Version 2.0 with LLVM exception (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License and of the exception at + * Licensed under the Apache License, Version 2.0 with LLVM exception (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License and of the exception at * * http://www.apache.org/licenses/LICENSE-2.0 * https://spdx.org/licenses/LLVM-exception.html @@ -51,8 +51,8 @@ pub fn repository(attrs: TokenStream, input: TokenStream) -> TokenStream { } } -/// Unless you know what you are doing, use `#[::bok::repository(MyBaseRepo)]` instead -/// needs a `.base` field +/// Unless you know what you are doing, use `#[::bok::repository(MyBaseRepo)]` +/// instead needs a `.base` field /// /// Use like: /// ``` @@ -183,7 +183,7 @@ pub fn package(attrs: TokenStream, input: TokenStream) -> TokenStream { } quote! { - #[derive(::bok::Package)] + #[derive(::bok::Package,::std::fmt::Debug)] #ast } .into() @@ -234,8 +234,8 @@ pub fn impl_package(_attrs: TokenStream, input: TokenStream) -> TokenStream { .into() } -/// Unless you know what you are doing, use `#[::bok::package(MyBasePackage)]` instead -/// needs a `.base` field +/// Unless you know what you are doing, use `#[::bok::package(MyBasePackage)]` +/// instead needs a `.base` field /// /// ``` /// #[derive(::bok::Package)] @@ -255,6 +255,7 @@ pub fn derive_package(input: TokenStream) -> TokenStream { let name = input.ident.clone(); let name_builder = quote::format_ident!("{name}Builder"); let name_builder2 = name_builder.clone(); + let name_builder3 = name_builder.clone(); let elements = match input.data { ::syn::Data::Struct(s) => match s.fields { syn::Fields::Named(n) => n.named, @@ -385,6 +386,7 @@ pub fn derive_package(input: TokenStream) -> TokenStream { let non_opt_fields2 = non_opt_fields.clone(); let non_opt_fields3 = non_opt_fields.clone(); let non_opt_fields4 = non_opt_fields.clone(); + let non_opt_fields5 = non_opt_fields.clone(); let opt_fields2 = opt_fields.clone(); let opt_fields3 = opt_fields.clone(); let opt_types2 = opt_types.clone(); @@ -483,10 +485,21 @@ pub fn derive_package(input: TokenStream) -> TokenStream { } } impl #name { + pub fn as_any(&self) -> &dyn ::std::any::Any { + self + } + pub fn as_any_mut(&mut self) -> &mut dyn ::std::any::Any { + self + } pub fn builder() -> #name_builder { - #name_builder { - #(#all_fields : ::std::option::Option::None,)* - } + #name_builder::default() + } + pub fn hash() -> ::bok::Hash { + // FIXME: this does not capture the package field status + use ::sha3::{Digest, Sha3_256}; + let mut hasher = ::sha3::Sha3_256::new(); + let hash = hasher.finalize(); + ::bok::Hash::Sha3(hash) } #(pub fn #all_fields2(&self) -> &#all_types { &self.#all_fields2 @@ -495,6 +508,7 @@ pub fn derive_package(input: TokenStream) -> TokenStream { &mut self.#all_fields3 })* } + #[derive(::std::default::Default, ::std::fmt::Debug)] pub struct #name_builder { #(#non_opt_fields: ::std::option::Option<#non_opt_types>,)* #(#opt_fields: ::std::option::Option<#opt_types>,)* @@ -507,8 +521,15 @@ pub fn derive_package(input: TokenStream) -> TokenStream { } } */ - impl #name_builder2 { - pub fn build(&mut self) -> Result<#name, ::std::boxed::Box> { + impl ::bok::PkgBuilder for #name_builder2 { + type Package = #name; + fn default_unused(&mut self){ + let def = #name::default(); + #(if self.#non_opt_fields5.is_none() { + self.#non_opt_fields5 = Some(def.#non_opt_fields5); + })* + } + fn build(&mut self) -> Result<#name, ::std::boxed::Box> { #(if self.#non_opt_fields2.is_none() { return ::std::result::Result::Err("unset field".into()); })* @@ -521,11 +542,37 @@ pub fn derive_package(input: TokenStream) -> TokenStream { } ) } + } + impl #name_builder3 { + pub fn as_any(&self) -> &dyn ::std::any::Any { + self + } + pub fn as_any_mut(&mut self) -> &mut dyn ::std::any::Any { + self + } + pub fn as_builder(&self) -> &dyn ::bok::PkgBuilder { + self + } + pub fn as_builder_mut(&mut self) -> &mut dyn ::bok::PkgBuilder { + self + } #(pub fn #non_opt_fields4 (&mut self, val : #non_opt_types2) -> &mut Self { + if self.#non_opt_fields4 != None && + self.#non_opt_fields4 != Some(val) { + panic!("Package \"{}\": mandatory attribute set multiple times: \"{}\"", + ::std::stringify!(#name), + ::std::stringify!(#non_opt_fields4)); + } self.#non_opt_fields4 = Some(val); self })* #(pub fn #opt_fields3 (&mut self, val : #opt_types2) -> &mut Self { + if self.#opt_fields3 != None && + self.#opt_fields3 != Some(val) { + panic!("Package \"{}\": optional attribute set multiple times: \"{}\"", + ::std::stringify!(#name), + ::std::stringify!(#opt_fields3)); + } self.#opt_fields3 = Some(val); self })* diff --git a/bok-utils/Cargo.toml b/bok-utils/Cargo.toml index bea24eb..20bc2fb 100644 --- a/bok-utils/Cargo.toml +++ b/bok-utils/Cargo.toml @@ -17,3 +17,4 @@ proc-macro2 = "1.0" quote = "1.0" prettyplease = "0.2" syn = { version = "2", features = [ "full", "parsing" ] } +sha3 = { version = "0.10" } diff --git a/bok-utils/src/main.rs b/bok-utils/src/main.rs index d42dbcf..eb9bf7d 100644 --- a/bok-utils/src/main.rs +++ b/bok-utils/src/main.rs @@ -18,15 +18,42 @@ mod conf; mod pkgs; +/* +trait TP { + fn p(r: &impl TR); +} +trait TR { + fn r(); +} + +struct R {} +impl TR for R { + fn r() {} +} +struct P {} +impl TP for P { + fn p(r: &impl TR) {} +} +*/ + fn main() { let pkgs1 = pkgs::Pkgs1::default(); let pkgs2 = pkgs::Pkgs2::default(); + let mut pb: pkgs::one::OneBuilder = pkgs1.one_builder(); + + let b = pb.as_builder(); + let a = pb.as_any_mut(); + let m_pb2: Option<&mut pkgs::one::OneBuilder> = a.downcast_mut(); + println!("m_pb2: {:?}", m_pb2); + println!("pkgs1 - 1:{}", pkgs1.one().my_attr); println!("pkgs1 - 2:{}", pkgs1.two().my_attr); println!("pkgs2 - 1:{}", pkgs2.one().my_attr); println!("pkgs2 - 2:{}", pkgs2.two().my_attr); println!("pkgs2 - 3:{}", pkgs2.three().my_attr); - println!("pkgs1:\n{}", pkgs1.one()); + println!("pkgs2-1:\n{}", pkgs2.one()); + println!("pkgs2-2:\n{}", pkgs2.two()); + println!("pkgs2-3:\n{}", pkgs2.three()); } diff --git a/bok-utils/src/pkgs/mod.rs b/bok-utils/src/pkgs/mod.rs index 9bf8f73..efee455 100644 --- a/bok-utils/src/pkgs/mod.rs +++ b/bok-utils/src/pkgs/mod.rs @@ -1,9 +1,9 @@ /* * Copyright 2024 Luca Fulchir * - * Licensed under the Apache License, Version 2.0 with LLVM exception (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License and of the exception at + * Licensed under the Apache License, Version 2.0 with LLVM exception (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License and of the exception at * * http://www.apache.org/licenses/LICENSE-2.0 * https://spdx.org/licenses/LLVM-exception.html @@ -18,7 +18,6 @@ //! //! Example of two package repositories, where one //! extends ancd changes another -//! // Export multiple packages in this module bok::moduse! { @@ -29,7 +28,6 @@ bok::moduse! { /// /// Base repository with some packages -/// #[::bok_macro::repository(::bok::RepositoryEmpty)] #[derive(::std::default::Default)] pub struct Pkgs1 {} @@ -45,7 +43,6 @@ bok::repo_packages! { /// /// This repository extends and changes Pkgs1 -/// #[::bok_macro::repository(Pkgs1)] #[derive(::std::default::Default)] pub struct Pkgs2 {} @@ -60,6 +57,7 @@ bok::repo_packages! { impl Pkgs2 { /// override the package `two` options from the base repostiory (Pkgs1) pub fn two(&self) -> Two { + use ::bok::PkgBuilder; Two::builder() .my_attr(42) .build() diff --git a/bok/Cargo.toml b/bok/Cargo.toml index fda9f43..4e5dd9c 100644 --- a/bok/Cargo.toml +++ b/bok/Cargo.toml @@ -19,3 +19,4 @@ bitflags = "2.4" proc-macro2 = "1.0" quote = "1.0" bok-macro = { path="../bok-macro" } +sha3 = { version = "0.10" } diff --git a/bok/src/lib.rs b/bok/src/lib.rs index ff9e5c7..f89799c 100644 --- a/bok/src/lib.rs +++ b/bok/src/lib.rs @@ -1,9 +1,9 @@ /* * Copyright 2024 Luca Fulchir * - * Licensed under the Apache License, Version 2.0 with LLVM exception (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License and of the exception at + * Licensed under the Apache License, Version 2.0 with LLVM exception (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License and of the exception at * * http://www.apache.org/licenses/LICENSE-2.0 * https://spdx.org/licenses/LLVM-exception.html @@ -28,9 +28,9 @@ pub use ::bok_macro::{ macro_rules! moduse { ($($name:ident,)*) => { $( - mod $name; + pub mod $name; #[allow(unused_imports)] - use $name::*; + pub use $name::*; )* }; } @@ -70,6 +70,9 @@ macro_rules! packages { pub fn [<$name:snake>] (&self) -> $name { $name::default() } + pub fn [<$name:snake _builder>] (&self) -> [<$name Builder>] { + $name::builder() + } )* } }; @@ -80,13 +83,17 @@ pub trait Repository: Default {} /// /// This is an empty Package List. Will be available in the main library -/// #[derive(::std::default::Default)] pub struct RepositoryEmpty {} impl Repository for RepositoryEmpty {} /// Implement common package operations -pub trait Pkg: ::std::default::Default + ::core::fmt::Display { +pub trait Pkg: + ::std::default::Default + + ::core::fmt::Debug + + ::core::fmt::Display + + ::std::any::Any +{ fn base(&self) -> ::core::option::Option<&impl Pkg>; fn prepare(&self) -> ::core::result::Result<(), ()> { self.base().unwrap().prepare() @@ -137,7 +144,15 @@ pub trait Pkg: ::std::default::Default + ::core::fmt::Display { } } -#[derive(Default)] +pub trait PkgBuilder: ::std::any::Any { + type Package; + fn default_unused(&mut self); + fn build( + &mut self, + ) -> Result>; +} + +#[derive(Default, Debug)] pub struct PkgEmpty {} impl ::core::fmt::Display for PkgEmpty { @@ -223,6 +238,10 @@ impl Pkg for PkgEmpty { // Conf stuff pub struct Conf {} +/// package hash +pub enum Hash { + Sha3(::sha3::digest::Output<::sha3::Sha3_256>), +} /* pub enum Value { /// Set, only once per