Skip to content

Commit

Permalink
Allow paths in derives
Browse files Browse the repository at this point in the history
  • Loading branch information
NightEule5 committed Jun 12, 2024
1 parent 0f29d1f commit 0991b73
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 32 deletions.
32 changes: 20 additions & 12 deletions src/generate/gen_enum.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -46,7 +47,7 @@ pub struct GenEnum<'a, P: Parent> {
visibility: Visibility,
generics: Option<Generics>,
values: Vec<EnumValue>,
derives: Vec<StringOrIdent>,
derives: Vec<Path>,
attributes: Vec<StreamBuilder>,
additional: Vec<StreamBuilder>,
}
Expand Down Expand Up @@ -75,40 +76,47 @@ 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<StringOrIdent>) -> &mut Self {
pub fn with_derive(&mut self, derive: impl Into<Path>) -> &mut Self {
AttributeContainer::with_derive(self, derive)
}

/// Add derive macros to the enum.
///
/// ```
/// # 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<Item = StringOrIdent>) -> &mut Self {
pub fn with_derives<T: Into<Path>>(&mut self, derives: impl IntoIterator<Item = T>) -> &mut Self {
AttributeContainer::with_derives(self, derives)
}

Expand Down Expand Up @@ -260,7 +268,7 @@ impl<'a, P: Parent> GenEnum<'a, P> {
}

impl<P: Parent> AttributeContainer for GenEnum<'_, P> {
fn derives(&mut self) -> &mut Vec<StringOrIdent> {
fn derives(&mut self) -> &mut Vec<Path> {
&mut self.derives
}

Expand Down Expand Up @@ -480,7 +488,7 @@ impl EnumValue {
}

impl AttributeContainer for EnumValue {
fn derives(&mut self) -> &mut Vec<StringOrIdent> {
fn derives(&mut self) -> &mut Vec<Path> {
unreachable!("enum variants cannot have derives")
}

Expand Down
32 changes: 21 additions & 11 deletions src/generate/gen_struct.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -13,7 +14,7 @@ pub struct GenStruct<'a, P: Parent> {
visibility: Visibility,
generics: Option<Generics>,
fields: Vec<Field>,
derives: Vec<StringOrIdent>,
derives: Vec<Path>,
attributes: Vec<StreamBuilder>,
additional: Vec<StreamBuilder>,
struct_type: StructType,
Expand Down Expand Up @@ -176,40 +177,49 @@ 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<StringOrIdent>) -> &mut Self {
/// ```
pub fn with_derive(&mut self, derive: impl Into<Path>) -> &mut Self {
AttributeContainer::with_derive(self, derive)
}

/// Add derive macros to the struct.
///
/// ```
/// # 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<Item = StringOrIdent>) -> &mut Self {
/// ```
pub fn with_derives<T: Into<Path>>(&mut self, derives: impl IntoIterator<Item = T>) -> &mut Self {
AttributeContainer::with_derives(self, derives)
}

Expand Down Expand Up @@ -317,7 +327,7 @@ impl<'a, P: Parent> GenStruct<'a, P> {
}

impl<P: Parent> AttributeContainer for GenStruct<'_, P> {
fn derives(&mut self) -> &mut Vec<StringOrIdent> {
fn derives(&mut self) -> &mut Vec<Path> {
&mut self.derives
}

Expand Down
84 changes: 75 additions & 9 deletions src/generate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,66 @@ impl<'a> From<&'a str> for StringOrIdent {
}
}

/// A path of identifiers, like `mod::Type`.
pub struct Path(Vec<StringOrIdent>);

impl From<String> for Path {
fn from(s: String) -> Self {
StringOrIdent::from(s).into()
}
}

impl From<Ident> 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<StringOrIdent> for Path {
fn from(value: StringOrIdent) -> Self {
Self(vec![value])
}
}

impl FromIterator<String> for Path {
fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
iter.into_iter().map(StringOrIdent::from).collect()
}
}

impl FromIterator<Ident> for Path {
fn from_iter<T: IntoIterator<Item = Ident>>(iter: T) -> Self {
iter.into_iter().map(StringOrIdent::from).collect()
}
}

impl<'a> FromIterator<&'a str> for Path {
fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
iter.into_iter().map(StringOrIdent::from).collect()
}
}

impl FromIterator<StringOrIdent> for Path {
fn from_iter<T: IntoIterator<Item = StringOrIdent>>(iter: T) -> Self {
Self(iter.into_iter().collect())
}
}

impl IntoIterator for Path {
type Item = StringOrIdent;
type IntoIter = std::vec::IntoIter<StringOrIdent>;

fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}

/// A struct or enum variant field.
struct Field {
name: String,
Expand Down Expand Up @@ -251,16 +311,16 @@ impl<P> FieldBuilder<'_, P> {

/// A helper trait to share attribute code between struct and enum generators.
trait AttributeContainer {
fn derives(&mut self) -> &mut Vec<StringOrIdent>;
fn derives(&mut self) -> &mut Vec<Path>;
fn attributes(&mut self) -> &mut Vec<StreamBuilder>;

fn with_derive(&mut self, derive: impl Into<StringOrIdent>) -> &mut Self {
fn with_derive(&mut self, derive: impl Into<Path>) -> &mut Self {
self.derives().push(derive.into());
self
}

fn with_derives(&mut self, derives: impl IntoIterator<Item = StringOrIdent>) -> &mut Self {
self.derives().extend(derives);
fn with_derives<T: Into<Path>>(&mut self, derives: impl IntoIterator<Item = T>) -> &mut Self {
self.derives().extend(derives.into_iter().map(Into::into));
self
}

Expand Down Expand Up @@ -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(())
})
Expand All @@ -313,7 +379,7 @@ trait AttributeContainer {
}

impl AttributeContainer for Field {
fn derives(&mut self) -> &mut Vec<StringOrIdent> {
fn derives(&mut self) -> &mut Vec<Path> {
unreachable!("fields cannot have derives")
}

Expand Down

0 comments on commit 0991b73

Please sign in to comment.