Split in multiple crates, builders

Signed-off-by: Luca Fulchir <luca.fulchir@runesauth.com>
This commit is contained in:
Luca Fulchir 2024-02-25 14:33:08 +01:00
parent 6f8fc593d7
commit 48b4fc6113
Signed by: luca.fulchir
GPG Key ID: 8F6440603D13A78E
18 changed files with 455 additions and 171 deletions

60
Cargo.lock generated
View File

@ -6,9 +6,65 @@ version = 3
name = "bok" name = "bok"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bokmacro", "bok-macro",
"paste",
] ]
[[package]] [[package]]
name = "bokmacro" name = "bok-macro"
version = "0.1.0" version = "0.1.0"
dependencies = [
"bok",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "bok-utils"
version = "0.1.0"
dependencies = [
"bok",
"bok-macro",
]
[[package]]
name = "paste"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "proc-macro2"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"

View File

@ -3,5 +3,6 @@
resolver = "2" resolver = "2"
members = [ members = [
"bok", "bok",
"bokmacro", "bok-macro",
"bok-utils",
] ]

19
bok-macro/Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
[package]
name = "bok-macro"
version = "0.1.0"
edition = "2021"
authors = ["Luca Fulchir <luca.fulchir@runesauth.com>"]
homepage = "https://git.runesauth.com/RunesAuth/bok"
repository = "https://git.runesauth.com/RunesAuth/bok"
license = "Apache-2.0 WITH LLVM-exception"
keywords = [ "bok" ]
categories = [ "config" ]
[lib]
proc-macro = true
[dependencies]
syn = { version = "2.0" }
quote = { version = "1.0" }
bok = { path = "../bok" }
proc-macro2 = "1.0"

212
bok-macro/src/lib.rs Normal file
View File

@ -0,0 +1,212 @@
/*
* Copyright 2024 Luca Fulchir <luca.fulchir@runesauth.com>
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use ::proc_macro::TokenStream;
use ::quote::quote;
use ::syn::{parse::Parser, parse_macro_input, DeriveInput};
#[proc_macro_attribute]
pub fn repository(attrs: TokenStream, input: TokenStream) -> TokenStream {
let mut ast = parse_macro_input!(input as DeriveInput);
match &mut ast.data {
syn::Data::Struct(ref mut struct_data) => {
match &mut struct_data.fields {
syn::Fields::Named(fields) => {
let base = proc_macro2::TokenStream::from(attrs);
fields.named.push(
syn::Field::parse_named
.parse2(quote! { base: #base })
.unwrap(),
);
}
_ => (),
}
quote! {
#ast
}
.into()
}
_ => panic!("`repository` has to be used with a struct"),
}
}
//#[proc_macro_attribute]
//pub fn packages(attrs: TokenStream, input: TokenStream) -> TokenStream {}
#[proc_macro_derive(Repository)]
pub fn derive_repository(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident.clone();
let elements = match input.data {
::syn::Data::Struct(s) => match s.fields {
syn::Fields::Named(n) => n.named,
_ => panic!("only named supported"),
},
_ => panic!("`Repository` has to be used on a struct"),
};
let base_type = elements
.iter()
.find_map(|field| {
if let Some(name) = &field.ident {
if name != "base" {
None
} else {
let t = &field.ty;
Some(quote! {#t})
}
} else {
None
}
})
.expect("can't find base value. Add #[repository] to your struct");
let expanded = quote! {
impl ::bok::Repository for #name {}
impl ::std::ops::Deref for #name {
type Target = #base_type;
fn deref(&self) -> &#base_type {
&self.base
}
}
};
TokenStream::from(expanded)
}
#[proc_macro_derive(Package)]
pub fn derive_package(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident.clone();
let name_builder = quote::format_ident!("{name}Builder");
let elements = match input.data {
::syn::Data::Struct(s) => match s.fields {
syn::Fields::Named(n) => n.named,
_ => panic!("only named supported"),
},
_ => panic!("only struct allowed"),
};
let all_fields = elements.iter().map(|field| &field.ident);
let non_opt_fields = elements.iter().filter_map(|field| match &field.ty {
syn::Type::Path(pth) => {
let first_path = pth.path.segments.first().unwrap();
if first_path.ident == "Option" {
None
} else {
let id = &field.ident;
Some(quote! {#id})
}
}
t => Some(quote! {#t}),
});
let opt_fields = elements.iter().filter_map(|field| match &field.ty {
syn::Type::Path(pth) => {
let first_path = pth.path.segments.first().unwrap();
if first_path.ident == "Option" {
let id = &field.ident;
Some(quote! {#id})
} else {
None
}
}
_ => None,
});
let non_opt_types = elements.iter().filter_map(|field| match &field.ty {
syn::Type::Path(pth) => {
let first_path = pth.path.segments.first().unwrap();
if first_path.ident == "Option" {
None
} else {
let t = &field.ty;
Some(quote! {#t})
}
}
_ => None,
});
let opt_types = elements.iter().filter_map(|field| match &field.ty {
syn::Type::Path(pth) => {
let first_path = pth.path.segments.first().unwrap();
if first_path.ident == "Option" {
match &first_path.arguments {
syn::PathArguments::AngleBracketed(
syn::AngleBracketedGenericArguments { args, .. },
) => {
if let Some(syn::GenericArgument::Type(
syn::Type::Path(p),
)) = args.first()
{
let id = &p.path.segments.first().unwrap().ident;
Some(quote! {#id})
} else {
None
}
}
_ => None,
}
} else {
None
}
}
_ => None,
});
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 opt_fields2 = opt_fields.clone();
let opt_fields3 = opt_fields.clone();
let opt_types2 = opt_types.clone();
let non_opt_types2 = non_opt_types.clone();
let expanded = quote! {
impl ::bok::Pkg for #name {}
impl #name {
pub fn builder() -> #name_builder {
#name_builder {
#(#all_fields : ::std::option::Option::None,)*
}
}
}
pub struct #name_builder {
#(#non_opt_fields: ::std::option::Option<#non_opt_types>,)*
#(#opt_fields: ::std::option::Option<#opt_types>,)*
}
impl #name_builder {
pub fn build(&mut self) -> Result<#name, ::std::boxed::Box<dyn ::std::error::Error>> {
#(if self.#non_opt_fields2.is_none() {
return ::std::result::Result::Err("unset field".into());
})*
Ok(
#name {
#(#non_opt_fields3 : self.#non_opt_fields3.clone().unwrap(),)*
#(#opt_fields2 : self.#opt_fields2.clone(),)*
}
)
}
#(pub fn #non_opt_fields4 (&mut self, val : #non_opt_types2) -> &mut Self {
self.#non_opt_fields4 = Some(val);
self
})*
#(pub fn #opt_fields3 (&mut self, val : #opt_types2) -> &mut Self {
self.#opt_fields3 = Some(val);
self
})*
}
};
TokenStream::from(expanded)
}

16
bok-utils/Cargo.toml Normal file
View File

@ -0,0 +1,16 @@
[package]
name = "bok-utils"
version = "0.1.0"
edition = "2021"
authors = ["Luca Fulchir <luca.fulchir@runesauth.com>"]
homepage = "https://git.runesauth.com/RunesAuth/bok"
repository = "https://git.runesauth.com/RunesAuth/bok"
license = "Apache-2.0 WITH LLVM-exception"
keywords = [ "bok" ]
categories = [ "config" ]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bok = { path = "../bok" }
bok-macro = { path = "../bok-macro" }

View File

@ -14,12 +14,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/*
use crate::libt; static CONF: ::bok::Conf = ::bok::Conf {};
static CONF: libt::Conf = libt::Conf {};
mod conf { mod conf {
use crate::libt; static CONF: ::bok::Conf = ::bok::Conf {};
static CONF: libt::Conf = libt::Conf {};
} }
*/

View File

@ -16,7 +16,6 @@
*/ */
mod conf; mod conf;
mod libt;
mod pkgs; mod pkgs;
fn main() { fn main() {

68
bok-utils/src/pkgs/mod.rs Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright 2024 Luca Fulchir <luca.fulchir@runesauth.com>
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//!
//! Example of two package repositories, where one
//! extends ancd changes another
//!
// Export multiple packages in this module
bok::moduse! {
one,
two,
three,
}
///
/// Base repository with some packages
///
#[::bok_macro::repository(::bok::RepositoryEmpty)]
#[derive(::bok_macro::Repository, ::std::default::Default)]
pub struct Pkgs1 {}
// Add some packages to the repository
// all packages will have `::default()` values
bok::repo_packages! {
Pkgs1 {
One,
Two,
}
}
///
/// This repository extends and changes Pkgs1
///
#[::bok_macro::repository(Pkgs1)]
#[derive(::bok_macro::Repository, ::std::default::Default)]
pub struct Pkgs2 {}
// add a third package with `::default()` values
bok::repo_packages! {
Pkgs1 {
Three,
}
}
impl Pkgs2 {
/// override the package `two` options from the base repostiory (Pkgs1)
pub fn two(&self) -> Two {
Two::builder()
.my_attr(42)
.build()
.expect("Can't build package Two")
}
}

View File

@ -15,17 +15,15 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::libt; /// Example package
//use ::std::boxed::Box; /// Automatically implements `.builder().my_attr(42).build()` pattern
#[derive(::bok_macro::Package)]
pub struct One { pub struct One {
pub my_attr: u32, pub my_attr: u32,
} }
impl libt::Pkg for One {} impl ::std::default::Default for One {
fn default() -> Self {
impl One {
pub fn new() -> Self {
One { my_attr: 1 } One { my_attr: 1 }
} }
} }

View File

@ -15,16 +15,15 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::libt; /// Example package
/// Automatically implements `.builder().my_attr(42).build()` pattern
#[derive(::bok_macro::Package)]
pub struct Three { pub struct Three {
pub my_attr: u32, pub my_attr: u32,
} }
impl libt::Pkg for Three {} impl ::std::default::Default for Three {
fn default() -> Self {
impl Three {
pub fn new() -> Self {
Three { my_attr: 3 } Three { my_attr: 3 }
} }
} }

View File

@ -15,16 +15,15 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::libt; /// Example package
/// Automatically implements `.builder().my_attr(42).build()` pattern
#[derive(::bok_macro::Package)]
pub struct Two { pub struct Two {
pub my_attr: u32, pub my_attr: u32,
} }
impl libt::Pkg for Two {} impl ::std::default::Default for Two {
fn default() -> Self {
impl Two {
pub fn new() -> Self {
Two { my_attr: 2 } Two { my_attr: 2 }
} }
} }

View File

@ -14,4 +14,7 @@ publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
bokmacro = { path="../bokmacro" } paste = "1.0"
[dev-dependencies]
bok-macro = { path="../bok-macro" }

View File

@ -19,9 +19,10 @@ use ::std::any::Any;
// Package stuff // Package stuff
/// Get a package from its module and export it in the current module
#[macro_export] #[macro_export]
macro_rules! moduse { macro_rules! moduse {
($($name:ident)*) => { ($($name:ident,)*) => {
$( $(
mod $name; mod $name;
#[allow(unused_imports)] #[allow(unused_imports)]
@ -29,18 +30,57 @@ macro_rules! moduse {
)* )*
}; };
} }
pub use moduse; // re-export `paste` crate for next macros
pub use paste;
pub trait PkgsList {} /// Add multipla packages to a repo
/// e.g.:
/// bok::repo_packages! {
/// MyRepo {
/// Mypkg1,
/// Mypkg2,
/// }
/// }
#[macro_export]
macro_rules! repo_packages {
( $repo:ident { $($name:ident,)*} ) => {
impl $repo {
$crate::packages!{$($name ,)*}
}
};
}
/// Add multipla packages to a repo Impl
/// e.g.:
/// impl MyRepo {
/// bok::packages! {
/// Mypkg1,
/// Mypkg2,
/// }
/// }
#[macro_export]
macro_rules! packages {
($($name:ident,)*) => {
$crate::paste::paste! {
$(
pub fn [<$name:snake>] (&self) -> $name {
$name::default()
}
)*
}
};
}
pub trait Repository: Default {}
/// ///
/// This is an empty Package List. Will be available in the main library /// This is an empty Package List. Will be available in the main library
/// ///
#[derive(::std::default::Default)] #[derive(::std::default::Default)]
pub struct PkgsEmpty {} pub struct RepositoryEmpty {}
impl PkgsList for PkgsEmpty {} impl Repository for RepositoryEmpty {}
pub trait Pkg: Any { pub trait Pkg: ::std::default::Default + Any {
fn as_any(&self) -> &dyn Any fn as_any(&self) -> &dyn Any
where where
Self: Sized, Self: Sized,
@ -50,9 +90,9 @@ pub trait Pkg: Any {
} }
// Conf stuff // Conf stuff
/*
pub struct Conf {} pub struct Conf {}
/*
pub enum Value<T: Sized> { pub enum Value<T: Sized> {
/// Set, only once per /// Set, only once per
Set(T), Set(T),

View File

@ -1,87 +0,0 @@
/*
* Copyright 2024 Luca Fulchir <luca.fulchir@runesauth.com>
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//!
//! Example of two package repositories, where one
//! extends ancd changes another
//!
use crate::libt;
//use ::std::{boxed::Box, vec::Vec};
crate::libt::moduse! {
one
two
three
}
///
/// This is a base Package List
///
#[derive(::std::default::Default)]
pub struct Pkgs1 {
base: libt::PkgsEmpty,
}
/// eventually PkgsList and deref will be replaced by macros
impl libt::PkgsList for Pkgs1 {}
impl ::std::ops::Deref for Pkgs1 {
type Target = libt::PkgsEmpty;
fn deref(&self) -> &libt::PkgsEmpty {
&self.base
}
}
impl Pkgs1 {
/// Packages like this can become a macro
pub fn one(&self) -> One {
One::new()
}
/// Packages like this can become a macro
pub fn two(&self) -> Two {
Two::new()
}
}
///
/// This is a Package List that extends and changes Pkgs1
///
#[derive(::std::default::Default)]
pub struct Pkgs2 {
base: Pkgs1,
}
/// eventually PkgsList and deref will be replaced by macros
impl libt::PkgsList for Pkgs2 {}
impl ::std::ops::Deref for Pkgs2 {
type Target = Pkgs1;
fn deref(&self) -> &Pkgs1 {
&self.base
}
}
impl Pkgs2 {
/// example of option override in a package
pub fn two(&self) -> Two {
let mut t = Two::new();
t.my_attr = 42;
t
}
/// Packages like this can become a macro
pub fn three(&self) -> Three {
Three::new()
}
}

View File

@ -1,9 +0,0 @@
[package]
name = "bokmacro"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]

View File

@ -1,28 +0,0 @@
/*
* Copyright 2024 Luca Fulchir <luca.fulchir@runesauth.com>
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
macro_rules! moduse {
($(mod $name:ident;)*) => {
$(
mod $name;
#[allow(unused_imports)]
use $name::*;
)*
};
}
*/

View File

@ -38,11 +38,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1707978831, "lastModified": 1708702655,
"narHash": "sha256-UblFdWQ2MMZNzD9C/w8+7RjAJ2QIbebbzHUniQ/a44o=", "narHash": "sha256-qxT5jSLhelfLhQ07+AUxSTm1VnVH+hQxDkQSZ/m/Smo=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "c68a9fc85c2cb3a313be6ff40511635544dde8da", "rev": "c5101e457206dd437330d283d6626944e28794b3",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -54,11 +54,11 @@
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1707956935, "lastModified": 1708655239,
"narHash": "sha256-ZL2TrjVsiFNKOYwYQozpbvQSwvtV/3Me7Zwhmdsfyu4=", "narHash": "sha256-ZrP/yACUvDB+zbqYJsln4iwotbH6CTZiTkANJ0AgDv4=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "a4d4fe8c5002202493e87ec8dbc91335ff55552c", "rev": "cbc4211f0afffe6dfd2478a62615dd5175a13f9a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -98,11 +98,11 @@
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_2"
}, },
"locked": { "locked": {
"lastModified": 1708049456, "lastModified": 1708827164,
"narHash": "sha256-8qGWZTQPPBhcF5dsl1KSWF+H7RX8C3BZGvqYWKBtLjQ=", "narHash": "sha256-oBNS6pO04Y6gZBLThP3JDDgviex0+WTXz3bVBenyzms=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "4ee92bf124fbc4e157cbce1bc2a35499866989fc", "rev": "e0626adabd5ea461f80b1b11390da2a6575adb30",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -42,10 +42,11 @@
cargo-watch cargo-watch
cargo-flamegraph cargo-flamegraph
cargo-license cargo-license
cargo-expand
lld lld
rust-bin.stable.${RUST_VERSION}.default rust-bin.stable.${RUST_VERSION}.default
rustfmt rustfmt
rust-analyzer pkgs-unstable.rust-analyzer
#clang_16 #clang_16
#mold #mold
# fenrir deps # fenrir deps