Skip to content

Commit

Permalink
WIP (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
loganmzz committed Jul 16, 2024
1 parent 699fcc5 commit f799d79
Show file tree
Hide file tree
Showing 6 changed files with 357 additions and 19 deletions.
35 changes: 35 additions & 0 deletions macon-config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,41 @@
}
}
}
},
"extend_types": {
"description": "Override pathes that should implement Extend",
"type": "object",
"properties": {
"includes": {
"description": "Pathes that should implement Extend",
"type": "array",
"items": {
"oneOf": [
{
"description": "Path that should implement Extend",
"type": "string"
},
{
"description": "Path and associated wrapped type",
"type": "object",
"properties": {
"path": {
"description": "Path that should implement Extend",
"type": "string"
},
"wrapped": {
"description": "Contained type",
"type": "string"
},
"required": [
"path"
]
}
}
]
}
}
}
}
}
}
48 changes: 47 additions & 1 deletion macon_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
//! See it for all details.
//!
use std::fmt::Debug;
use std::{
fmt::Debug,
vec,
};

/// Builder field type when building struct implementing [`Default`].
#[derive(Default,)]
Expand All @@ -25,6 +28,14 @@ pub enum Defaulting<T: Default> {
Set(T),
}

/// Builder field type when target implment [`Extend`].
pub struct Extending<C,I> {
/// Collecting items
items: Vec<I>,
/// Building value
value: C,
}

/// Builder field type for `Panic` or `Result` mode.
#[derive(Default,)]
pub enum Building<T> {
Expand Down Expand Up @@ -82,6 +93,41 @@ impl<T: Default> Defaulting<T> {
}
}

impl<C, I> Default for Extending<C, I> where C: Default {
fn default() -> Self {
Self {
items: Default::default(),
value: Default::default(),
}
}
}

impl<C, I> Extend<I> for Extending<C, I> {
/// Store `iter` values into `items` (until container is created)
fn extend<T: IntoIterator<Item = I>>(&mut self, iter: T) {
self.items.extend(iter)
}
}

impl<C, I> IntoIterator for Extending<C, I> {
type Item = I;
type IntoIter = vec::IntoIter<I>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}

impl<C, I> Extending<C, I> {
pub fn value_mut(&mut self) -> &mut C {
&mut self.value
}

/// Consume to return `value` and collected `items`.
pub fn unwrap(self) -> (C, Vec<I>) {
(self.value, self.items)
}
}

impl<T> Debug for Building<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand Down
92 changes: 75 additions & 17 deletions macon_derive/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ pub fn get() -> &'static anyhow::Result<Configuration> {
#[derive(Debug,)]
pub struct Configuration {
default_types: TypeSet,
option_types: TypeSet<OptionTypeSetItem>,
option_types: TypeSet<ContainerTypeSetItem>,
extend_types: TypeSet<ContainerTypeSetItem>,
}

pub trait TypeSetItem {
Expand Down Expand Up @@ -133,7 +134,12 @@ impl Default for Configuration {
fn default() -> Self {
let default_types = Configuration::default_default_types();
let option_types = Configuration::default_option_types();
Self { default_types, option_types, }
let extend_types = Configuration::default_extend_types();
Self {
default_types,
option_types,
extend_types,
}
}
}

Expand All @@ -157,10 +163,15 @@ impl Configuration {
crate_config.option_types.map_includes(|i| i.into()),
Self::default_option_types,
);
let extend_types = TypeSet::create(
crate_config.extend_types.map_includes(|i| i.into()),
Self::default_extend_types,
);

let this = Self {
default_types,
option_types,
extend_types,
};
#[cfg(feature = "debug")]
eprintln!("Merge configuration\n{:#?}", this);
Expand Down Expand Up @@ -197,18 +208,26 @@ impl Configuration {
.add_path("std::collections::hash_set::HashSet")
}

pub fn default_option_types() -> TypeSet<OptionTypeSetItem> {
pub fn default_option_types() -> TypeSet<ContainerTypeSetItem> {
TypeSet::default()
.add_path("std::option::Option")
.add_path("core::option::Option")
}

pub fn default_extend_types() -> TypeSet<ContainerTypeSetItem> {
TypeSet::default()
.add_path("std::vec::Vec")
}

pub fn default_types(&self) -> &TypeSet {
&self.default_types
}
pub fn option_types(&self) -> &TypeSet<OptionTypeSetItem> {
pub fn option_types(&self) -> &TypeSet<ContainerTypeSetItem> {
&self.option_types
}
pub fn extend_types(&self) -> &TypeSet<ContainerTypeSetItem> {
&self.extend_types
}
}

#[derive(Debug,Deserialize,)]
Expand All @@ -218,31 +237,33 @@ struct CrateConfiguration {
pub version: String,
#[serde(default)]
pub default_types: TypeSetConfiguration<String>,
#[serde(default = "default_typesetconfiguration", deserialize_with="deserialize_crateconfiguration_option_types")]
pub option_types: TypeSetConfiguration<OptionTypeSetItem>,
#[serde(default = "default_typesetconfiguration", deserialize_with="deserialize_crateconfiguration_container_types")]
pub option_types: TypeSetConfiguration<ContainerTypeSetItem>,
#[serde(default = "default_typesetconfiguration", deserialize_with="deserialize_crateconfiguration_container_types")]
pub extend_types: TypeSetConfiguration<ContainerTypeSetItem>,
}

fn deserialize_crateconfiguration_option_types<'de, D>(deserializer: D) -> std::result::Result<TypeSetConfiguration<OptionTypeSetItem>, D::Error>
fn deserialize_crateconfiguration_container_types<'de, D>(deserializer: D) -> std::result::Result<TypeSetConfiguration<ContainerTypeSetItem>, D::Error>
where
D: Deserializer<'de>,
{
let decoded: TypeSetConfiguration<OptionTypeSetItemConfiguration> = Deserialize::deserialize(deserializer)?;
Ok(decoded.map_includes(OptionTypeSetItem::from))
Ok(decoded.map_includes(ContainerTypeSetItem::from))
}

#[derive(Debug,Default,Deserialize,PartialEq,)]
pub struct OptionTypeSetItem {
pub struct ContainerTypeSetItem {
pub path: String,
pub wrapped: Option<String>,
}

impl TypeSetItem for OptionTypeSetItem {
impl TypeSetItem for ContainerTypeSetItem {
fn path(&self) -> String {
self.path.clone()
}
}

impl From<&str> for OptionTypeSetItem {
impl From<&str> for ContainerTypeSetItem {
fn from(path: &str) -> Self {
Self {
path: path.to_owned(),
Expand All @@ -255,7 +276,7 @@ impl From<&str> for OptionTypeSetItem {
#[serde(untagged)]
pub enum OptionTypeSetItemConfiguration {
String(String),
Item(OptionTypeSetItem),
Item(ContainerTypeSetItem),
}

impl Default for OptionTypeSetItemConfiguration {
Expand All @@ -264,7 +285,7 @@ impl Default for OptionTypeSetItemConfiguration {
}
}

impl From<OptionTypeSetItemConfiguration> for OptionTypeSetItem {
impl From<OptionTypeSetItemConfiguration> for ContainerTypeSetItem {
fn from(value: OptionTypeSetItemConfiguration) -> Self {
match value {
OptionTypeSetItemConfiguration::String(string) => string.as_str().into(),
Expand Down Expand Up @@ -402,7 +423,7 @@ mod tests {
let mut option_types_includes = option_types.includes.iter();
assert_eq!(
option_types_includes.next(),
Some(&OptionTypeSetItem {
Some(&ContainerTypeSetItem {
path: "AsString".to_owned(),
wrapped: None,
}),
Expand All @@ -411,25 +432,62 @@ mod tests {

assert_eq!(
option_types_includes.next(),
Some(&OptionTypeSetItem { path: "AsItemWithoutWrapped".to_owned(), wrapped: None, }),
Some(&ContainerTypeSetItem { path: "AsItemWithoutWrapped".to_owned(), wrapped: None, }),
"option_types.includes[1]\n{:#?}", config
);

assert_eq!(
option_types_includes.next(),
Some(&OptionTypeSetItem { path: "AsItemWithShortWrapped".to_owned(), wrapped: Some("ShortWrapped".to_string()), }),
Some(&ContainerTypeSetItem { path: "AsItemWithShortWrapped".to_owned(), wrapped: Some("ShortWrapped".to_string()), }),
"option_types.includes[2]\n{:#?}", config
);

assert_eq!(
option_types_includes.next(),
Some(&OptionTypeSetItem { path: "AsItemWithFullWrapped".to_owned(), wrapped: Some("::full::path::FullWrapped".to_string()), }),
Some(&ContainerTypeSetItem { path: "AsItemWithFullWrapped".to_owned(), wrapped: Some("::full::path::FullWrapped".to_string()), }),
"option_types.includes[3]\n{:#?}", config
);

assert!(option_types_includes.next().is_none(), "option_types.includes[4]\n{:#?}", config);

let mut option_types_excludes = option_types.excludes.iter();
assert_eq!(option_types_excludes.next(), None, "option_types.excludes[0]\n{:#?}", config);


let extend_types = &config.extend_types;
assert_eq!(extend_types.defaults, true, "extend_types.defaults");

let mut extend_types_includes = extend_types.includes.iter();
assert_eq!(
extend_types_includes.next(),
Some(&ContainerTypeSetItem {
path: "AsString".to_owned(),
wrapped: None,
}),
"extend_types.includes[0]\n{:#?}", config
);

assert_eq!(
extend_types_includes.next(),
Some(&ContainerTypeSetItem { path: "AsItemWithoutWrapped".to_owned(), wrapped: None, }),
"extend_types.includes[1]\n{:#?}", config
);

assert_eq!(
extend_types_includes.next(),
Some(&ContainerTypeSetItem { path: "AsItemWithShortWrapped".to_owned(), wrapped: Some("ShortWrapped".to_string()), }),
"extend_types.includes[2]\n{:#?}", config
);

assert_eq!(
extend_types_includes.next(),
Some(&ContainerTypeSetItem { path: "AsItemWithFullWrapped".to_owned(), wrapped: Some("::full::path::FullWrapped".to_string()), }),
"extend_types.includes[3]\n{:#?}", config
);

assert!(extend_types_includes.next().is_none(), "extend_types.includes[4]\n{:#?}", config);

let mut extend_types_excludes = extend_types.excludes.iter();
assert_eq!(extend_types_excludes.next(), None, "extend_types.excludes[0]\n{:#?}", config);
}
}
25 changes: 24 additions & 1 deletion macon_derive/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use proc_macro2::{
};
use quote::{
format_ident,
quote, ToTokens,
quote,
ToTokens,
};
use syn::{
Attribute,
Expand Down Expand Up @@ -135,6 +136,7 @@ impl<T> From<T> for Setting<T> {
pub struct PropertySettings {
pub option: Setting<Type>,
pub default: Setting<()>,
pub extend: Setting<Type>,
}

#[derive(Debug,Default,)]
Expand Down Expand Up @@ -432,6 +434,13 @@ impl Property {
settings.option = Setting::enable(ty);
}
}
if settings.extend.is_undefined() {
if let Some(ty) = Self::get_extend_arg(&field.ty)? {
#[cfg(feature = "debug")]
eprintln!("{}.{}: Extend<{}>", builder.ident, name, ty.to_token_stream());
settings.extend = Setting::enable(ty);
}
}
if settings.default.is_undefined() {
let default_types = match crate::config::get() {
Ok(config) => config.default_types(),
Expand Down Expand Up @@ -489,6 +498,19 @@ impl Property {
})
}

pub fn get_extend_arg(ty: &Type) -> Result<Option<Type>> {
let config = match crate::config::get() {
Ok(config) => config,
Err(error) => return Err(Error::new_spanned(ty, error)),
};

Ok(if let Some(_item) = config.extend_types().match_type(ty) {
None
} else {
None
})
}

pub fn id(&self) -> TokenStream {
if self.is_tuple {
let literal = Literal::usize_unsuffixed(self.ordinal);
Expand Down Expand Up @@ -536,6 +558,7 @@ impl Property {
}
}

/// Not option, field default or struct default.
pub fn is_required(&self) -> bool {
! self.option.is_enabled() &&
! self.default.is_enabled() &&
Expand Down
9 changes: 9 additions & 0 deletions macon_derive/tests/config/macon-config-parse.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,12 @@ option_types:
wrapped: ShortWrapped
- path: AsItemWithFullWrapped
wrapped: ::full::path::FullWrapped

extend_types:
includes:
- AsString
- path: AsItemWithoutWrapped
- path: AsItemWithShortWrapped
wrapped: ShortWrapped
- path: AsItemWithFullWrapped
wrapped: ::full::path::FullWrapped
Loading

0 comments on commit f799d79

Please sign in to comment.