diff --git a/src/generate/gen_enum.rs b/src/generate/gen_enum.rs index a230263..2eeb06b 100644 --- a/src/generate/gen_enum.rs +++ b/src/generate/gen_enum.rs @@ -1,5 +1,6 @@ use super::{ - AttributeContainer, Field, FieldBuilder, Impl, ImplFor, Parent, StreamBuilder, StringOrIdent, + AttributeContainer, Field, FieldBuilder, Impl, ImplFor, Parent, Path, StreamBuilder, + StringOrIdent, }; use crate::parse::{Generic, Generics, Visibility}; use crate::prelude::{Delimiter, Ident, Span}; @@ -46,7 +47,7 @@ pub struct GenEnum<'a, P: Parent> { visibility: Visibility, generics: Option, values: Vec, - derives: Vec, + derives: Vec, attributes: Vec, additional: Vec, } @@ -75,20 +76,22 @@ impl<'a, P: Parent> GenEnum<'a, P> { /// /// ``` /// # use virtue::prelude::Generator; + /// # use virtue::generate::Path; /// # let mut generator = Generator::with_name("Bar"); /// generator /// .generate_enum("Foo") /// .with_derive("Clone") - /// .with_derive("Default"); - /// # generator.assert_eq("# [derive (Clone , Default)] enum Foo { }"); + /// .with_derive("Default") + /// .with_derive(Path::from_iter(vec!["serde", "Deserialize"])); + /// # generator.assert_eq("# [derive (Clone , Default , serde ::Deserialize)] enum Foo { }"); /// # Ok::<_, virtue::Error>(()) /// ``` /// /// Generates: /// ```ignore - /// #[derive(Clone, Default)] + /// #[derive(Clone, Default, serde::Deserialize)] /// enum Foo { } - pub fn with_derive(&mut self, derive: impl Into) -> &mut Self { + pub fn with_derive(&mut self, derive: impl Into) -> &mut Self { AttributeContainer::with_derive(self, derive) } @@ -96,19 +99,24 @@ impl<'a, P: Parent> GenEnum<'a, P> { /// /// ``` /// # use virtue::prelude::Generator; + /// # use virtue::generate::Path; /// # let mut generator = Generator::with_name("Bar"); /// generator /// .generate_enum("Foo") - /// .with_derives(["Clone".into(), "Default".into()]); - /// # generator.assert_eq("# [derive (Clone , Default)] enum Foo { }"); + /// .with_derives([ + /// "Clone".into(), + /// "Default".into(), + /// Path::from_iter(vec!["serde", "Deserialize"]), + /// ]); + /// # generator.assert_eq("# [derive (Clone , Default , serde ::Deserialize)] enum Foo { }"); /// # Ok::<_, virtue::Error>(()) /// ``` /// /// Generates: /// ```ignore - /// #[derive(Clone, Default)] + /// #[derive(Clone, Default, serde::Deserialize)] /// enum Foo { } - pub fn with_derives(&mut self, derives: impl IntoIterator) -> &mut Self { + pub fn with_derives>(&mut self, derives: impl IntoIterator) -> &mut Self { AttributeContainer::with_derives(self, derives) } @@ -260,7 +268,7 @@ impl<'a, P: Parent> GenEnum<'a, P> { } impl AttributeContainer for GenEnum<'_, P> { - fn derives(&mut self) -> &mut Vec { + fn derives(&mut self) -> &mut Vec { &mut self.derives } @@ -480,7 +488,7 @@ impl EnumValue { } impl AttributeContainer for EnumValue { - fn derives(&mut self) -> &mut Vec { + fn derives(&mut self) -> &mut Vec { unreachable!("enum variants cannot have derives") } diff --git a/src/generate/gen_struct.rs b/src/generate/gen_struct.rs index 8763fb7..438a3f7 100644 --- a/src/generate/gen_struct.rs +++ b/src/generate/gen_struct.rs @@ -1,5 +1,6 @@ use super::{ - AttributeContainer, Field, FieldBuilder, Impl, ImplFor, Parent, StreamBuilder, StringOrIdent, + AttributeContainer, Field, FieldBuilder, Impl, ImplFor, Parent, Path, StreamBuilder, + StringOrIdent, }; use crate::parse::{Generic, Generics, Visibility}; use crate::prelude::{Delimiter, Ident, Span}; @@ -13,7 +14,7 @@ pub struct GenStruct<'a, P: Parent> { visibility: Visibility, generics: Option, fields: Vec, - derives: Vec, + derives: Vec, attributes: Vec, additional: Vec, struct_type: StructType, @@ -176,20 +177,23 @@ impl<'a, P: Parent> GenStruct<'a, P> { /// /// ``` /// # use virtue::prelude::Generator; + /// # use virtue::generate::Path; /// # let mut generator = Generator::with_name("Bar"); /// generator /// .generate_struct("Foo") /// .with_derive("Clone") - /// .with_derive("Default"); - /// # generator.assert_eq("# [derive (Clone , Default)] struct Foo { }"); + /// .with_derive("Default") + /// .with_derive(Path::from_iter(vec!["serde", "Deserialize"])); + /// # generator.assert_eq("# [derive (Clone , Default , serde ::Deserialize)] struct Foo { }"); /// # Ok::<_, virtue::Error>(()) /// ``` /// /// Generates: /// ```ignore - /// #[derive(Clone, Default)] + /// #[derive(Clone, Default, serde::Deserialize)] /// struct Foo { } - pub fn with_derive(&mut self, derive: impl Into) -> &mut Self { + /// ``` + pub fn with_derive(&mut self, derive: impl Into) -> &mut Self { AttributeContainer::with_derive(self, derive) } @@ -197,19 +201,25 @@ impl<'a, P: Parent> GenStruct<'a, P> { /// /// ``` /// # use virtue::prelude::Generator; + /// # use virtue::generate::Path; /// # let mut generator = Generator::with_name("Bar"); /// generator /// .generate_struct("Foo") - /// .with_derives(["Clone".into(), "Default".into()]); - /// # generator.assert_eq("# [derive (Clone , Default)] struct Foo { }"); + /// .with_derives([ + /// "Clone".into(), + /// "Default".into(), + /// Path::from_iter(vec!["serde", "Deserialize"]), + /// ]); + /// # generator.assert_eq("# [derive (Clone , Default , serde ::Deserialize)] struct Foo { }"); /// # Ok::<_, virtue::Error>(()) /// ``` /// /// Generates: /// ```ignore - /// #[derive(Clone, Default)] + /// #[derive(Clone, Default, serde::Deserialize)] /// struct Foo { } - pub fn with_derives(&mut self, derives: impl IntoIterator) -> &mut Self { + /// ``` + pub fn with_derives>(&mut self, derives: impl IntoIterator) -> &mut Self { AttributeContainer::with_derives(self, derives) } @@ -317,7 +327,7 @@ impl<'a, P: Parent> GenStruct<'a, P> { } impl AttributeContainer for GenStruct<'_, P> { - fn derives(&mut self) -> &mut Vec { + fn derives(&mut self) -> &mut Vec { &mut self.derives } diff --git a/src/generate/mod.rs b/src/generate/mod.rs index 070739e..d68b5c2 100644 --- a/src/generate/mod.rs +++ b/src/generate/mod.rs @@ -81,6 +81,66 @@ impl<'a> From<&'a str> for StringOrIdent { } } +/// A path of identifiers, like `mod::Type`. +pub struct Path(Vec); + +impl From for Path { + fn from(s: String) -> Self { + StringOrIdent::from(s).into() + } +} + +impl From for Path { + fn from(i: Ident) -> Self { + StringOrIdent::from(i).into() + } +} + +impl From<&str> for Path { + fn from(s: &str) -> Self { + StringOrIdent::from(s).into() + } +} + +impl From for Path { + fn from(value: StringOrIdent) -> Self { + Self(vec![value]) + } +} + +impl FromIterator for Path { + fn from_iter>(iter: T) -> Self { + iter.into_iter().map(StringOrIdent::from).collect() + } +} + +impl FromIterator for Path { + fn from_iter>(iter: T) -> Self { + iter.into_iter().map(StringOrIdent::from).collect() + } +} + +impl<'a> FromIterator<&'a str> for Path { + fn from_iter>(iter: T) -> Self { + iter.into_iter().map(StringOrIdent::from).collect() + } +} + +impl FromIterator for Path { + fn from_iter>(iter: T) -> Self { + Self(iter.into_iter().collect()) + } +} + +impl IntoIterator for Path { + type Item = StringOrIdent; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + /// A struct or enum variant field. struct Field { name: String, @@ -251,16 +311,16 @@ impl

FieldBuilder<'_, P> { /// A helper trait to share attribute code between struct and enum generators. trait AttributeContainer { - fn derives(&mut self) -> &mut Vec; + fn derives(&mut self) -> &mut Vec; fn attributes(&mut self) -> &mut Vec; - fn with_derive(&mut self, derive: impl Into) -> &mut Self { + fn with_derive(&mut self, derive: impl Into) -> &mut Self { self.derives().push(derive.into()); self } - fn with_derives(&mut self, derives: impl IntoIterator) -> &mut Self { - self.derives().extend(derives); + fn with_derives>(&mut self, derives: impl IntoIterator) -> &mut Self { + self.derives().extend(derives.into_iter().map(Into::into)); self } @@ -291,10 +351,16 @@ trait AttributeContainer { if idx > 0 { b.punct(','); } - match derive { - StringOrIdent::String(s) => b.ident_str(s), - StringOrIdent::Ident(i) => b.ident(i), - }; + for (idx, component) in derive.into_iter().enumerate() { + if idx > 0 { + b.puncts("::"); + } + + match component { + StringOrIdent::String(s) => b.ident_str(s), + StringOrIdent::Ident(i) => b.ident(i), + }; + } } Ok(()) }) @@ -313,7 +379,7 @@ trait AttributeContainer { } impl AttributeContainer for Field { - fn derives(&mut self) -> &mut Vec { + fn derives(&mut self) -> &mut Vec { unreachable!("fields cannot have derives") }