From c6d48746049e0dec66c2db6fecce4bdeed2fc050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s-Combarro=20=27piranna?= Date: Tue, 26 May 2020 03:56:36 +0200 Subject: [PATCH 1/4] Splitted librare in several module files --- src/associated_type.rs | 20 + src/block.rs | 78 ++ src/body.rs | 21 + src/bound.rs | 8 + src/docs.rs | 26 + src/enum.rs | 101 ++ src/field.rs | 45 + src/fields.rs | 106 +++ src/formatter.rs | 154 +++ src/function.rs | 290 ++++++ src/impl.rs | 163 ++++ src/import.rs | 25 + src/item.rs | 19 + src/lib.rs | 2037 +--------------------------------------- src/module.rs | 176 ++++ src/scope.rs | 322 +++++++ src/struct.rs | 131 +++ src/trait.rs | 142 +++ src/type.rs | 104 ++ src/type_def.rs | 146 +++ src/variant.rs | 49 + 21 files changed, 2164 insertions(+), 1999 deletions(-) create mode 100644 src/associated_type.rs create mode 100644 src/block.rs create mode 100644 src/body.rs create mode 100644 src/bound.rs create mode 100644 src/docs.rs create mode 100644 src/enum.rs create mode 100644 src/field.rs create mode 100644 src/fields.rs create mode 100644 src/formatter.rs create mode 100644 src/function.rs create mode 100644 src/impl.rs create mode 100644 src/import.rs create mode 100644 src/item.rs create mode 100644 src/module.rs create mode 100644 src/scope.rs create mode 100644 src/struct.rs create mode 100644 src/trait.rs create mode 100644 src/type.rs create mode 100644 src/type_def.rs create mode 100644 src/variant.rs diff --git a/src/associated_type.rs b/src/associated_type.rs new file mode 100644 index 0000000..a9d91f5 --- /dev/null +++ b/src/associated_type.rs @@ -0,0 +1,20 @@ +use bound::Bound; + +use r#type::Type; + + +/// Defines an associated type. +#[derive(Debug, Clone)] +pub struct AssociatedType(pub Bound); + + +impl AssociatedType { + /// Add a bound to the associated type. + pub fn bound(&mut self, ty: T) -> &mut Self + where + T: Into, + { + self.0.bound.push(ty.into()); + self + } +} diff --git a/src/block.rs b/src/block.rs new file mode 100644 index 0000000..57d720e --- /dev/null +++ b/src/block.rs @@ -0,0 +1,78 @@ +use std::fmt::{self, Write}; + +use body::Body; +use formatter::Formatter; + + +/// Defines a code block. This is used to define a function body. +#[derive(Debug, Clone)] +pub struct Block { + before: Option, + after: Option, + body: Vec, +} + + +impl Block { + /// Returns an empty code block. + pub fn new(before: &str) -> Self { + Block { + before: Some(before.to_string()), + after: None, + body: vec![], + } + } + + /// Push a line to the code block. + pub fn line(&mut self, line: T) -> &mut Self + where + T: ToString, + { + self.body.push(Body::String(line.to_string())); + self + } + + /// Push a nested block to this block. + pub fn push_block(&mut self, block: Block) -> &mut Self { + self.body.push(Body::Block(block)); + self + } + + /// Add a snippet after the block. + pub fn after(&mut self, after: &str) -> &mut Self { + self.after = Some(after.to_string()); + self + } + + /// Formats the block using the given formatter. + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + if let Some(ref before) = self.before { + write!(fmt, "{}", before)?; + } + + // Inlined `Formatter::fmt` + + if !fmt.is_start_of_line() { + write!(fmt, " ")?; + } + + write!(fmt, "{{\n")?; + + fmt.indent(|fmt| { + for b in &self.body { + b.fmt(fmt)?; + } + + Ok(()) + })?; + + write!(fmt, "}}")?; + + if let Some(ref after) = self.after { + write!(fmt, "{}", after)?; + } + + write!(fmt, "\n")?; + Ok(()) + } +} diff --git a/src/body.rs b/src/body.rs new file mode 100644 index 0000000..b8d27a8 --- /dev/null +++ b/src/body.rs @@ -0,0 +1,21 @@ +use std::fmt::{self, Write}; + +use block::Block; +use formatter::Formatter; + + +#[derive(Debug, Clone)] +pub enum Body { + String(String), + Block(Block), +} + + +impl Body { + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + match *self { + Body::String(ref s) => write!(fmt, "{}\n", s), + Body::Block(ref b) => b.fmt(fmt), + } + } +} diff --git a/src/bound.rs b/src/bound.rs new file mode 100644 index 0000000..3904638 --- /dev/null +++ b/src/bound.rs @@ -0,0 +1,8 @@ +use r#type::Type; + + +#[derive(Debug, Clone)] +pub struct Bound { + pub name: String, + pub bound: Vec, +} diff --git a/src/docs.rs b/src/docs.rs new file mode 100644 index 0000000..0fcbe21 --- /dev/null +++ b/src/docs.rs @@ -0,0 +1,26 @@ +use std::fmt::{self, Write}; + +use formatter::Formatter; + + +#[derive(Debug, Clone)] +pub struct Docs { + docs: String, +} + + +impl Docs { + pub fn new(docs: &str) -> Self { + Docs { + docs: docs.to_string(), + } + } + + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + for line in self.docs.lines() { + write!(fmt, "/// {}\n", line)?; + } + + Ok(()) + } +} diff --git a/src/enum.rs b/src/enum.rs new file mode 100644 index 0000000..6e08906 --- /dev/null +++ b/src/enum.rs @@ -0,0 +1,101 @@ +use std::fmt; + +use formatter::Formatter; +use type_def::TypeDef; +use variant::Variant; + +use r#type::Type; + + +/// Defines an enumeration. +#[derive(Debug, Clone)] +pub struct Enum { + type_def: TypeDef, + variants: Vec, +} + + +impl Enum { + /// Return a enum definition with the provided name. + pub fn new(name: &str) -> Self { + Enum { + type_def: TypeDef::new(name), + variants: vec![], + } + } + + /// Returns a reference to the type. + pub fn ty(&self) -> &Type { + &self.type_def.ty + } + + /// Set the enum visibility. + pub fn vis(&mut self, vis: &str) -> &mut Self { + self.type_def.vis(vis); + self + } + + /// Add a generic to the enum. + pub fn generic(&mut self, name: &str) -> &mut Self { + self.type_def.ty.generic(name); + self + } + + /// Add a `where` bound to the enum. + pub fn bound(&mut self, name: &str, ty: T) -> &mut Self + where + T: Into, + { + self.type_def.bound(name, ty); + self + } + + /// Set the enum documentation. + pub fn doc(&mut self, docs: &str) -> &mut Self { + self.type_def.doc(docs); + self + } + + /// Add a new type that the struct should derive. + pub fn derive(&mut self, name: &str) -> &mut Self { + self.type_def.derive(name); + self + } + + /// Specify lint attribute to supress a warning or error. + pub fn allow(&mut self, allow: &str) -> &mut Self { + self.type_def.allow(allow); + self + } + + /// Specify representation. + pub fn repr(&mut self, repr: &str) -> &mut Self { + self.type_def.repr(repr); + self + } + + /// Push a variant to the enum, returning a mutable reference to it. + pub fn new_variant(&mut self, name: &str) -> &mut Variant { + self.push_variant(Variant::new(name)); + self.variants.last_mut().unwrap() + } + + /// Push a variant to the enum. + pub fn push_variant(&mut self, item: Variant) -> &mut Self { + self.variants.push(item); + self + } + + /// Formats the enum using the given formatter. + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + self.type_def.fmt_head("enum", &[], fmt)?; + + fmt.block(|fmt| { + for variant in &self.variants { + variant.fmt(fmt)?; + } + + Ok(()) + }) + } +} diff --git a/src/field.rs b/src/field.rs new file mode 100644 index 0000000..6077f12 --- /dev/null +++ b/src/field.rs @@ -0,0 +1,45 @@ +use r#type::Type; + + +/// Defines a struct field. +#[derive(Debug, Clone)] +pub struct Field { + /// Field name + pub name: String, + + /// Field type + pub ty: Type, + + /// Field documentation + pub documentation: Vec, + + /// Field annotation + pub annotation: Vec, +} + + +impl Field { + /// Return a field definition with the provided name and type + pub fn new(name: &str, ty: T) -> Self + where T: Into, + { + Field { + name: name.into(), + ty: ty.into(), + documentation: Vec::new(), + annotation: Vec::new(), + } + } + + /// Set field's documentation. + pub fn doc(&mut self, documentation: Vec<&str>) -> &mut Self { + self.documentation = documentation.iter().map(|doc| doc.to_string()).collect(); + self + } + + /// Set field's annotation. + pub fn annotation(&mut self, annotation: Vec<&str>) -> &mut Self { + self.annotation = annotation.iter().map(|ann| ann.to_string()).collect(); + self + } +} diff --git a/src/fields.rs b/src/fields.rs new file mode 100644 index 0000000..f3d6465 --- /dev/null +++ b/src/fields.rs @@ -0,0 +1,106 @@ +use std::fmt::{self, Write}; + +use field::Field; +use formatter::Formatter; + +use r#type::Type; + + +/// Defines a set of fields. +#[derive(Debug, Clone)] +pub enum Fields { + Empty, + Tuple(Vec), + Named(Vec), +} + + +impl Fields { + pub fn push_named(&mut self, field: Field) -> &mut Self + { + match *self { + Fields::Empty => { + *self = Fields::Named(vec![field]); + } + Fields::Named(ref mut fields) => { + fields.push(field); + } + _ => panic!("field list is named"), + } + + self + } + + pub fn named(&mut self, name: &str, ty: T) -> &mut Self + where T: Into, + { + self.push_named(Field { + name: name.to_string(), + ty: ty.into(), + documentation: Vec::new(), + annotation: Vec::new(), + }) + } + + pub fn tuple(&mut self, ty: T) -> &mut Self + where + T: Into, + { + match *self { + Fields::Empty => { + *self = Fields::Tuple(vec![ty.into()]); + } + Fields::Tuple(ref mut fields) => { + fields.push(ty.into()); + } + _ => panic!("field list is tuple"), + } + + self + } + + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + match *self { + Fields::Named(ref fields) => { + assert!(!fields.is_empty()); + + fmt.block(|fmt| { + for f in fields { + if !f.documentation.is_empty() { + for doc in &f.documentation { + write!(fmt, "/// {}\n", doc)?; + } + } + if !f.annotation.is_empty() { + for ann in &f.annotation { + write!(fmt, "{}\n", ann)?; + } + } + write!(fmt, "{}: ", f.name)?; + f.ty.fmt(fmt)?; + write!(fmt, ",\n")?; + } + + Ok(()) + })?; + } + Fields::Tuple(ref tys) => { + assert!(!tys.is_empty()); + + write!(fmt, "(")?; + + for (i, ty) in tys.iter().enumerate() { + if i != 0 { + write!(fmt, ", ")?; + } + ty.fmt(fmt)?; + } + + write!(fmt, ")")?; + } + Fields::Empty => {} + } + + Ok(()) + } +} diff --git a/src/formatter.rs b/src/formatter.rs new file mode 100644 index 0000000..aa06354 --- /dev/null +++ b/src/formatter.rs @@ -0,0 +1,154 @@ +use std::fmt::{self, Write}; + +use bound::Bound; + +use r#type::Type; + + +const DEFAULT_INDENT: usize = 4; + + +/// Configures how a scope is formatted. +#[derive(Debug)] +pub struct Formatter<'a> { + /// Write destination + dst: &'a mut String, + + /// Number of spaces to start a new line with. + spaces: usize, + + /// Number of spaces per indentiation + indent: usize, +} + + +impl<'a> Formatter<'a> { + /// Return a new formatter that writes to the given string. + pub fn new(dst: &'a mut String) -> Self { + Formatter { + dst, + spaces: 0, + indent: DEFAULT_INDENT, + } + } + + /// Wrap the given function inside a block. + pub fn block(&mut self, f: F) -> fmt::Result + where + F: FnOnce(&mut Self) -> fmt::Result, + { + if !self.is_start_of_line() { + write!(self, " ")?; + } + + write!(self, "{{\n")?; + self.indent(f)?; + write!(self, "}}\n")?; + Ok(()) + } + + /// Call the given function with the indentation level incremented by one. + pub fn indent(&mut self, f: F) -> R + where + F: FnOnce(&mut Self) -> R, + { + self.spaces += self.indent; + let ret = f(self); + self.spaces -= self.indent; + ret + } + + /// Check if current destination is the start of a new line. + pub fn is_start_of_line(&self) -> bool { + self.dst.is_empty() || self.dst.as_bytes().last() == Some(&b'\n') + } + + fn push_spaces(&mut self) { + for _ in 0..self.spaces { + self.dst.push_str(" "); + } + } +} + +impl<'a> fmt::Write for Formatter<'a> { + fn write_str(&mut self, s: &str) -> fmt::Result { + let mut first = true; + let mut should_indent = self.is_start_of_line(); + + for line in s.lines() { + if !first { + self.dst.push_str("\n"); + } + + first = false; + + let do_indent = should_indent && !line.is_empty() && line.as_bytes()[0] != b'\n'; + + if do_indent { + self.push_spaces(); + } + + // If this loops again, then we just wrote a new line + should_indent = true; + + self.dst.push_str(line); + } + + if s.as_bytes().last() == Some(&b'\n') { + self.dst.push_str("\n"); + } + + Ok(()) + } +} + + +/// Format generics. +pub fn fmt_generics(generics: &[String], fmt: &mut Formatter) -> fmt::Result { + if !generics.is_empty() { + write!(fmt, "<")?; + + for (i, ty) in generics.iter().enumerate() { + if i != 0 { + write!(fmt, ", ")? + } + write!(fmt, "{}", ty)?; + } + + write!(fmt, ">")?; + } + + Ok(()) +} + +/// Format generic bounds. +pub fn fmt_bounds(bounds: &[Bound], fmt: &mut Formatter) -> fmt::Result { + if !bounds.is_empty() { + write!(fmt, "\n")?; + + // Write first bound + write!(fmt, "where {}: ", bounds[0].name)?; + fmt_bound_rhs(&bounds[0].bound, fmt)?; + write!(fmt, ",\n")?; + + for bound in &bounds[1..] { + write!(fmt, " {}: ", bound.name)?; + fmt_bound_rhs(&bound.bound, fmt)?; + write!(fmt, ",\n")?; + } + } + + Ok(()) +} + +/// Format multiple generic bounds. +pub fn fmt_bound_rhs(tys: &[Type], fmt: &mut Formatter) -> fmt::Result { + for (i, ty) in tys.iter().enumerate() { + if i != 0 { + write!(fmt, " + ")? + } + ty.fmt(fmt)?; + } + + Ok(()) +} diff --git a/src/function.rs b/src/function.rs new file mode 100644 index 0000000..e89fc66 --- /dev/null +++ b/src/function.rs @@ -0,0 +1,290 @@ +use std::fmt::{self, Write}; + +use block::Block; +use body::Body; +use bound::Bound; +use docs::Docs; +use field::Field; +use formatter::{fmt_bounds, fmt_generics}; +use formatter::Formatter; + +use r#type::Type; + + +/// Defines a function. +#[derive(Debug, Clone)] +pub struct Function { + /// Name of the function + name: String, + + /// Function documentation + docs: Option, + + /// A lint attribute used to suppress a warning or error + allow: Option, + + /// Function visibility + vis: Option, + + /// Function generics + generics: Vec, + + /// If the function takes `&self` or `&mut self` + arg_self: Option, + + /// Function arguments + args: Vec, + + /// Return type + ret: Option, + + /// Where bounds + bounds: Vec, + + /// Body contents + pub body: Option>, + + /// Function attributes, e.g., `#[no_mangle]`. + attributes: Vec, + + /// Function `extern` ABI + extern_abi: Option, + + /// Whether or not this function is `async` or not + r#async: bool, +} + + +impl Function { + /// Return a new function definition. + pub fn new(name: &str) -> Self { + Function { + name: name.to_string(), + docs: None, + allow: None, + vis: None, + generics: vec![], + arg_self: None, + args: vec![], + ret: None, + bounds: vec![], + body: Some(vec![]), + attributes: vec![], + extern_abi: None, + r#async: false, + } + } + + /// Set the function documentation. + pub fn doc(&mut self, docs: &str) -> &mut Self { + self.docs = Some(Docs::new(docs)); + self + } + + /// Specify lint attribute to supress a warning or error. + pub fn allow(&mut self, allow: &str) -> &mut Self { + self.allow = Some(allow.to_string()); + self + } + + /// Set the function visibility. + pub fn vis(&mut self, vis: &str) -> &mut Self { + self.vis = Some(vis.to_string()); + self + } + + /// Set whether this function is async or not + pub fn set_async(&mut self, r#async: bool) -> &mut Self { + self.r#async = r#async; + self + } + + /// Add a generic to the function. + pub fn generic(&mut self, name: &str) -> &mut Self { + self.generics.push(name.to_string()); + self + } + + /// Add `self` as a function argument. + pub fn arg_self(&mut self) -> &mut Self { + self.arg_self = Some("self".to_string()); + self + } + + /// Add `&self` as a function argument. + pub fn arg_ref_self(&mut self) -> &mut Self { + self.arg_self = Some("&self".to_string()); + self + } + + /// Add `&mut self` as a function argument. + pub fn arg_mut_self(&mut self) -> &mut Self { + self.arg_self = Some("&mut self".to_string()); + self + } + + /// Add a function argument. + pub fn arg(&mut self, name: &str, ty: T) -> &mut Self + where + T: Into, + { + self.args.push(Field { + name: name.to_string(), + ty: ty.into(), + // While a `Field` is used here, both `documentation` + // and `annotation` does not make sense for function arguments. + // Simply use empty strings. + documentation: Vec::new(), + annotation: Vec::new(), + }); + + self + } + + /// Set the function return type. + pub fn ret(&mut self, ty: T) -> &mut Self + where + T: Into, + { + self.ret = Some(ty.into()); + self + } + + /// Add a `where` bound to the function. + pub fn bound(&mut self, name: &str, ty: T) -> &mut Self + where + T: Into, + { + self.bounds.push(Bound { + name: name.to_string(), + bound: vec![ty.into()], + }); + self + } + + /// Push a line to the function implementation. + pub fn line(&mut self, line: T) -> &mut Self + where + T: ToString, + { + self.body + .get_or_insert(vec![]) + .push(Body::String(line.to_string())); + + self + } + + /// Add an attribute to the function. + /// + /// ``` + /// use codegen::Function; + /// + /// let mut func = Function::new("test"); + /// + /// // add a `#[test]` attribute + /// func.attr("test"); + /// ``` + pub fn attr(&mut self, attribute: &str) -> &mut Self { + self.attributes.push(attribute.to_string()); + self + } + + /// Specify an `extern` ABI for the function. + /// ``` + /// use codegen::Function; + /// + /// let mut extern_func = Function::new("extern_func"); + /// + /// // use the "C" calling convention + /// extern_func.extern_abi("C"); + /// ``` + pub fn extern_abi(&mut self, abi: &str) -> &mut Self { + self.extern_abi.replace(abi.to_string()); + self + } + + /// Push a block to the function implementation + pub fn push_block(&mut self, block: Block) -> &mut Self { + self.body.get_or_insert(vec![]).push(Body::Block(block)); + + self + } + + /// Formats the function using the given formatter. + pub fn fmt(&self, is_trait: bool, fmt: &mut Formatter) -> fmt::Result { + if let Some(ref docs) = self.docs { + docs.fmt(fmt)?; + } + + if let Some(ref allow) = self.allow { + write!(fmt, "#[allow({})]\n", allow)?; + } + + for attr in self.attributes.iter() { + write!(fmt, "#[{}]\n", attr)?; + } + + if is_trait { + assert!( + self.vis.is_none(), + "trait fns do not have visibility modifiers" + ); + } + + if let Some(ref vis) = self.vis { + write!(fmt, "{} ", vis)?; + } + + if let Some(ref extern_abi) = self.extern_abi { + write!(fmt, "extern \"{extern_abi}\" ", extern_abi = extern_abi)?; + } + + if self.r#async { + write!(fmt, "async ")?; + } + + write!(fmt, "fn {}", self.name)?; + fmt_generics(&self.generics, fmt)?; + + write!(fmt, "(")?; + + if let Some(ref s) = self.arg_self { + write!(fmt, "{}", s)?; + } + + for (i, arg) in self.args.iter().enumerate() { + if i != 0 || self.arg_self.is_some() { + write!(fmt, ", ")?; + } + + write!(fmt, "{}: ", arg.name)?; + arg.ty.fmt(fmt)?; + } + + write!(fmt, ")")?; + + if let Some(ref ret) = self.ret { + write!(fmt, " -> ")?; + ret.fmt(fmt)?; + } + + fmt_bounds(&self.bounds, fmt)?; + + match self.body { + Some(ref body) => fmt.block(|fmt| { + for b in body { + b.fmt(fmt)?; + } + + Ok(()) + }), + None => { + if !is_trait { + panic!("impl blocks must define fn bodies"); + } + + write!(fmt, ";\n") + } + } + } +} diff --git a/src/impl.rs b/src/impl.rs new file mode 100644 index 0000000..1aef190 --- /dev/null +++ b/src/impl.rs @@ -0,0 +1,163 @@ +use std::fmt::{self, Write}; + +use bound::Bound; +use field::Field; +use formatter::{Formatter, fmt_bounds, fmt_generics}; +use function::Function; + +use r#type::Type; + + +/// Defines an impl block. +#[derive(Debug, Clone)] +pub struct Impl { + /// The struct being implemented + target: Type, + + /// Impl level generics + generics: Vec, + + /// If implementing a trait + impl_trait: Option, + + /// Associated types + assoc_tys: Vec, + + /// Bounds + bounds: Vec, + + fns: Vec, + + macros: Vec, +} + + +impl Impl { + /// Return a new impl definition + pub fn new(target: T) -> Self + where + T: Into, + { + Impl { + target: target.into(), + generics: vec![], + impl_trait: None, + assoc_tys: vec![], + bounds: vec![], + fns: vec![], + macros: vec![], + } + } + + /// Add a generic to the impl block. + /// + /// This adds the generic for the block (`impl`) and not the target type. + pub fn generic(&mut self, name: &str) -> &mut Self { + self.generics.push(name.to_string()); + self + } + + /// Add a generic to the target type. + pub fn target_generic(&mut self, ty: T) -> &mut Self + where + T: Into, + { + self.target.generic(ty); + self + } + + /// Set the trait that the impl block is implementing. + pub fn impl_trait(&mut self, ty: T) -> &mut Self + where + T: Into, + { + self.impl_trait = Some(ty.into()); + self + } + + /// Add a macro to the impl block (e.g. `"#[async_trait]"`) + pub fn r#macro(&mut self, r#macro: &str) -> &mut Self { + self.macros.push(r#macro.to_string()); + self + } + + /// Set an associated type. + pub fn associate_type(&mut self, name: &str, ty: T) -> &mut Self + where + T: Into, + { + self.assoc_tys.push(Field { + name: name.to_string(), + ty: ty.into(), + documentation: Vec::new(), + annotation: Vec::new(), + }); + + self + } + + /// Add a `where` bound to the impl block. + pub fn bound(&mut self, name: &str, ty: T) -> &mut Self + where + T: Into, + { + self.bounds.push(Bound { + name: name.to_string(), + bound: vec![ty.into()], + }); + self + } + + /// Push a new function definition, returning a mutable reference to it. + pub fn new_fn(&mut self, name: &str) -> &mut Function { + self.push_fn(Function::new(name)); + self.fns.last_mut().unwrap() + } + + /// Push a function definition. + pub fn push_fn(&mut self, item: Function) -> &mut Self { + self.fns.push(item); + self + } + + /// Formats the impl block using the given formatter. + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + for m in self.macros.iter() { + write!(fmt, "{}\n", m)?; + } + write!(fmt, "impl")?; + fmt_generics(&self.generics[..], fmt)?; + + if let Some(ref t) = self.impl_trait { + write!(fmt, " ")?; + t.fmt(fmt)?; + write!(fmt, " for")?; + } + + write!(fmt, " ")?; + self.target.fmt(fmt)?; + + fmt_bounds(&self.bounds, fmt)?; + + fmt.block(|fmt| { + // format associated types + if !self.assoc_tys.is_empty() { + for ty in &self.assoc_tys { + write!(fmt, "type {} = ", ty.name)?; + ty.ty.fmt(fmt)?; + write!(fmt, ";\n")?; + } + } + + for (i, func) in self.fns.iter().enumerate() { + if i != 0 || !self.assoc_tys.is_empty() { + write!(fmt, "\n")?; + } + + func.fmt(false, fmt)?; + } + + Ok(()) + }) + } +} diff --git a/src/import.rs b/src/import.rs new file mode 100644 index 0000000..0cc1209 --- /dev/null +++ b/src/import.rs @@ -0,0 +1,25 @@ +/// Defines an import (`use` statement). +#[derive(Debug, Clone)] +pub struct Import { + line: String, + + /// Function visibility + pub vis: Option, +} + + +impl Import { + /// Return a new import. + pub fn new(path: &str, ty: &str) -> Self { + Import { + line: format!("{}::{}", path, ty), + vis: None, + } + } + + /// Set the import visibility. + pub fn vis(&mut self, vis: &str) -> &mut Self { + self.vis = Some(vis.to_string()); + self + } +} diff --git a/src/item.rs b/src/item.rs new file mode 100644 index 0000000..56d3c96 --- /dev/null +++ b/src/item.rs @@ -0,0 +1,19 @@ +use function::Function; +use module::Module; + +use r#enum::Enum; +use r#impl::Impl; +use r#struct::Struct; +use r#trait::Trait; + + +#[derive(Debug, Clone)] +pub enum Item { + Module(Module), + Struct(Struct), + Function(Function), + Trait(Trait), + Enum(Enum), + Impl(Impl), + Raw(String), +} diff --git a/src/lib.rs b/src/lib.rs index 1008fa0..b722f4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,2002 +24,41 @@ //! println!("{}", scope.to_string()); //! ``` -extern crate indexmap; - -use indexmap::IndexMap; -use std::fmt::{self, Write}; - -/// Defines a scope. -/// -/// A scope contains modules, types, etc... -#[derive(Debug, Clone)] -pub struct Scope { - /// Scope documentation - docs: Option, - - /// Imports - imports: IndexMap>, - - /// Contents of the documentation, - items: Vec, -} - -#[derive(Debug, Clone)] -enum Item { - Module(Module), - Struct(Struct), - Function(Function), - Trait(Trait), - Enum(Enum), - Impl(Impl), - Raw(String), -} - -/// Defines a module. -#[derive(Debug, Clone)] -pub struct Module { - /// Module name - name: String, - - /// Visibility - vis: Option, - - /// Module documentation - docs: Option, - - /// Contents of the module - scope: Scope, -} - -/// Defines an enumeration. -#[derive(Debug, Clone)] -pub struct Enum { - type_def: TypeDef, - variants: Vec, -} - -/// Defines a struct. -#[derive(Debug, Clone)] -pub struct Struct { - type_def: TypeDef, - - /// Struct fields - fields: Fields, -} - -/// Define a trait. -#[derive(Debug, Clone)] -pub struct Trait { - type_def: TypeDef, - parents: Vec, - associated_tys: Vec, - fns: Vec, - macros: Vec, -} - -/// Defines a type. -#[derive(Debug, Clone)] -pub struct Type { - name: String, - generics: Vec, -} - -/// Defines a type definition. -#[derive(Debug, Clone)] -struct TypeDef { - ty: Type, - vis: Option, - docs: Option, - derive: Vec, - allow: Option, - repr: Option, - bounds: Vec, - macros: Vec, -} - -/// Defines an enum variant. -#[derive(Debug, Clone)] -pub struct Variant { - name: String, - fields: Fields, -} - -/// Defines a set of fields. -#[derive(Debug, Clone)] -enum Fields { - Empty, - Tuple(Vec), - Named(Vec), -} - -/// Defines a struct field. -#[derive(Debug, Clone)] -pub struct Field { - /// Field name - name: String, - - /// Field type - ty: Type, - - /// Field documentation - documentation: Vec, - - /// Field annotation - annotation: Vec, -} - -/// Defines an associated type. -#[derive(Debug, Clone)] -pub struct AssociatedType(Bound); - -#[derive(Debug, Clone)] -struct Bound { - name: String, - bound: Vec, -} - -/// Defines an impl block. -#[derive(Debug, Clone)] -pub struct Impl { - /// The struct being implemented - target: Type, - - /// Impl level generics - generics: Vec, - - /// If implementing a trait - impl_trait: Option, - - /// Associated types - assoc_tys: Vec, - - /// Bounds - bounds: Vec, - - fns: Vec, - - macros: Vec, -} - -/// Defines an import (`use` statement). -#[derive(Debug, Clone)] -pub struct Import { - line: String, - vis: Option, -} - -/// Defines a function. -#[derive(Debug, Clone)] -pub struct Function { - /// Name of the function - name: String, - - /// Function documentation - docs: Option, - - /// A lint attribute used to suppress a warning or error - allow: Option, - - /// Function visibility - vis: Option, - - /// Function generics - generics: Vec, - - /// If the function takes `&self` or `&mut self` - arg_self: Option, - - /// Function arguments - args: Vec, - - /// Return type - ret: Option, - - /// Where bounds - bounds: Vec, - - /// Body contents - body: Option>, - - /// Function attributes, e.g., `#[no_mangle]`. - attributes: Vec, - - /// Function `extern` ABI - extern_abi: Option, - - /// Whether or not this function is `async` or not - r#async: bool, -} - -/// Defines a code block. This is used to define a function body. -#[derive(Debug, Clone)] -pub struct Block { - before: Option, - after: Option, - body: Vec, -} - -#[derive(Debug, Clone)] -enum Body { - String(String), - Block(Block), -} - -#[derive(Debug, Clone)] -struct Docs { - docs: String, -} - -/// Configures how a scope is formatted. -#[derive(Debug)] -pub struct Formatter<'a> { - /// Write destination - dst: &'a mut String, - - /// Number of spaces to start a new line with. - spaces: usize, - - /// Number of spaces per indentiation - indent: usize, -} - -const DEFAULT_INDENT: usize = 4; - -// ===== impl Scope ===== - -impl Scope { - /// Returns a new scope - pub fn new() -> Self { - Scope { - docs: None, - imports: IndexMap::new(), - items: vec![], - } - } - - /// Import a type into the scope. - /// - /// This results in a new `use` statement being added to the beginning of - /// the scope. - pub fn import(&mut self, path: &str, ty: &str) -> &mut Import { - // handle cases where the caller wants to refer to a type namespaced - // within the containing namespace, like "a::B". - let ty = ty.split("::").next().unwrap_or(ty); - self.imports - .entry(path.to_string()) - .or_insert(IndexMap::new()) - .entry(ty.to_string()) - .or_insert_with(|| Import::new(path, ty)) - } - - /// Push a new module definition, returning a mutable reference to it. - /// - /// # Panics - /// - /// Since a module's name must uniquely identify it within the scope in - /// which it is defined, pushing a module whose name is already defined - /// in this scope will cause this function to panic. - /// - /// In many cases, the [`get_or_new_module`] function is preferrable, as it - /// will return the existing definition instead. - /// - /// [`get_or_new_module`]: #method.get_or_new_module - pub fn new_module(&mut self, name: &str) -> &mut Module { - self.push_module(Module::new(name)); - - match *self.items.last_mut().unwrap() { - Item::Module(ref mut v) => v, - _ => unreachable!(), - } - } - - /// Returns a mutable reference to a module if it is exists in this scope. - pub fn get_module_mut(&mut self, name: &Q) -> Option<&mut Module> - where - String: PartialEq, - { - self.items - .iter_mut() - .filter_map(|item| match item { - &mut Item::Module(ref mut module) if module.name == *name => Some(module), - _ => None, - }) - .next() - } - - /// Returns a mutable reference to a module if it is exists in this scope. - pub fn get_module(&self, name: &Q) -> Option<&Module> - where - String: PartialEq, - { - self.items - .iter() - .filter_map(|item| match item { - &Item::Module(ref module) if module.name == *name => Some(module), - _ => None, - }) - .next() - } - - /// Returns a mutable reference to a module, creating it if it does - /// not exist. - pub fn get_or_new_module(&mut self, name: &str) -> &mut Module { - if self.get_module(name).is_some() { - self.get_module_mut(name).unwrap() - } else { - self.new_module(name) - } - } - - /// Push a module definition. - /// - /// # Panics - /// - /// Since a module's name must uniquely identify it within the scope in - /// which it is defined, pushing a module whose name is already defined - /// in this scope will cause this function to panic. - /// - /// In many cases, the [`get_or_new_module`] function is preferrable, as it will - /// return the existing definition instead. - /// - /// [`get_or_new_module`]: #method.get_or_new_module - pub fn push_module(&mut self, item: Module) -> &mut Self { - assert!(self.get_module(&item.name).is_none()); - self.items.push(Item::Module(item)); - self - } - - /// Push a new struct definition, returning a mutable reference to it. - pub fn new_struct(&mut self, name: &str) -> &mut Struct { - self.push_struct(Struct::new(name)); - - match *self.items.last_mut().unwrap() { - Item::Struct(ref mut v) => v, - _ => unreachable!(), - } - } - - /// Push a struct definition - pub fn push_struct(&mut self, item: Struct) -> &mut Self { - self.items.push(Item::Struct(item)); - self - } - - /// Push a new function definition, returning a mutable reference to it. - pub fn new_fn(&mut self, name: &str) -> &mut Function { - self.push_fn(Function::new(name)); - - match *self.items.last_mut().unwrap() { - Item::Function(ref mut v) => v, - _ => unreachable!(), - } - } - - /// Push a function definition - pub fn push_fn(&mut self, item: Function) -> &mut Self { - self.items.push(Item::Function(item)); - self - } - - /// Push a new trait definition, returning a mutable reference to it. - pub fn new_trait(&mut self, name: &str) -> &mut Trait { - self.push_trait(Trait::new(name)); - - match *self.items.last_mut().unwrap() { - Item::Trait(ref mut v) => v, - _ => unreachable!(), - } - } - - /// Push a trait definition - pub fn push_trait(&mut self, item: Trait) -> &mut Self { - self.items.push(Item::Trait(item)); - self - } - - /// Push a new struct definition, returning a mutable reference to it. - pub fn new_enum(&mut self, name: &str) -> &mut Enum { - self.push_enum(Enum::new(name)); - - match *self.items.last_mut().unwrap() { - Item::Enum(ref mut v) => v, - _ => unreachable!(), - } - } - - /// Push a structure definition - pub fn push_enum(&mut self, item: Enum) -> &mut Self { - self.items.push(Item::Enum(item)); - self - } - - /// Push a new `impl` block, returning a mutable reference to it. - pub fn new_impl(&mut self, target: &str) -> &mut Impl { - self.push_impl(Impl::new(target)); - - match *self.items.last_mut().unwrap() { - Item::Impl(ref mut v) => v, - _ => unreachable!(), - } - } - - /// Push an `impl` block. - pub fn push_impl(&mut self, item: Impl) -> &mut Self { - self.items.push(Item::Impl(item)); - self - } - - /// Push a raw string to the scope. - /// - /// This string will be included verbatim in the formatted string. - pub fn raw(&mut self, val: &str) -> &mut Self { - self.items.push(Item::Raw(val.to_string())); - self - } - - /// Return a string representation of the scope. - pub fn to_string(&self) -> String { - let mut ret = String::new(); - - self.fmt(&mut Formatter::new(&mut ret)).unwrap(); - - // Remove the trailing newline - if ret.as_bytes().last() == Some(&b'\n') { - ret.pop(); - } - - ret - } - - /// Formats the scope using the given formatter. - pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - self.fmt_imports(fmt)?; - - if !self.imports.is_empty() { - write!(fmt, "\n")?; - } - - for (i, item) in self.items.iter().enumerate() { - if i != 0 { - write!(fmt, "\n")?; - } - - match *item { - Item::Module(ref v) => v.fmt(fmt)?, - Item::Struct(ref v) => v.fmt(fmt)?, - Item::Function(ref v) => v.fmt(false, fmt)?, - Item::Trait(ref v) => v.fmt(fmt)?, - Item::Enum(ref v) => v.fmt(fmt)?, - Item::Impl(ref v) => v.fmt(fmt)?, - Item::Raw(ref v) => { - write!(fmt, "{}\n", v)?; - } - } - } - - Ok(()) - } - - fn fmt_imports(&self, fmt: &mut Formatter) -> fmt::Result { - // First, collect all visibilities - let mut visibilities = vec![]; - - for (_, imports) in &self.imports { - for (_, import) in imports { - if !visibilities.contains(&import.vis) { - visibilities.push(import.vis.clone()); - } - } - } - - let mut tys = vec![]; - - // Loop over all visibilities and format the associated imports - for vis in &visibilities { - for (path, imports) in &self.imports { - tys.clear(); - - for (ty, import) in imports { - if *vis == import.vis { - tys.push(ty); - } - } - - if !tys.is_empty() { - if let Some(ref vis) = *vis { - write!(fmt, "{} ", vis)?; - } - - write!(fmt, "use {}::", path)?; - - if tys.len() > 1 { - write!(fmt, "{{")?; - - for (i, ty) in tys.iter().enumerate() { - if i != 0 { - write!(fmt, ", ")?; - } - write!(fmt, "{}", ty)?; - } - - write!(fmt, "}};\n")?; - } else if tys.len() == 1 { - write!(fmt, "{};\n", tys[0])?; - } - } - } - } - - Ok(()) - } -} - -// ===== impl Module ===== - -impl Module { - /// Return a new, blank module - pub fn new(name: &str) -> Self { - Module { - name: name.to_string(), - vis: None, - docs: None, - scope: Scope::new(), - } - } - - /// Returns a mutable reference to the module's scope. - pub fn scope(&mut self) -> &mut Scope { - &mut self.scope - } - - /// Set the module visibility. - pub fn vis(&mut self, vis: &str) -> &mut Self { - self.vis = Some(vis.to_string()); - self - } - - /// Import a type into the module's scope. - /// - /// This results in a new `use` statement bein added to the beginning of the - /// module. - pub fn import(&mut self, path: &str, ty: &str) -> &mut Self { - self.scope.import(path, ty); - self - } - - /// Push a new module definition, returning a mutable reference to it. - /// - /// # Panics - /// - /// Since a module's name must uniquely identify it within the scope in - /// which it is defined, pushing a module whose name is already defined - /// in this scope will cause this function to panic. - /// - /// In many cases, the [`get_or_new_module`] function is preferrable, as it - /// will return the existing definition instead. - /// - /// [`get_or_new_module`]: #method.get_or_new_module - pub fn new_module(&mut self, name: &str) -> &mut Module { - self.scope.new_module(name) - } - - /// Returns a reference to a module if it is exists in this scope. - pub fn get_module(&self, name: &Q) -> Option<&Module> - where - String: PartialEq, - { - self.scope.get_module(name) - } - - /// Returns a mutable reference to a module if it is exists in this scope. - pub fn get_module_mut(&mut self, name: &Q) -> Option<&mut Module> - where - String: PartialEq, - { - self.scope.get_module_mut(name) - } - - /// Returns a mutable reference to a module, creating it if it does - /// not exist. - pub fn get_or_new_module(&mut self, name: &str) -> &mut Module { - self.scope.get_or_new_module(name) - } - - /// Push a module definition. - /// - /// # Panics - /// - /// Since a module's name must uniquely identify it within the scope in - /// which it is defined, pushing a module whose name is already defined - /// in this scope will cause this function to panic. - /// - /// In many cases, the [`get_or_new_module`] function is preferrable, as it will - /// return the existing definition instead. - /// - /// [`get_or_new_module`]: #method.get_or_new_module - pub fn push_module(&mut self, item: Module) -> &mut Self { - self.scope.push_module(item); - self - } - - /// Push a new struct definition, returning a mutable reference to it. - pub fn new_struct(&mut self, name: &str) -> &mut Struct { - self.scope.new_struct(name) - } - - /// Push a structure definition - pub fn push_struct(&mut self, item: Struct) -> &mut Self { - self.scope.push_struct(item); - self - } - - /// Push a new function definition, returning a mutable reference to it. - pub fn new_fn(&mut self, name: &str) -> &mut Function { - self.scope.new_fn(name) - } - - /// Push a function definition - pub fn push_fn(&mut self, item: Function) -> &mut Self { - self.scope.push_fn(item); - self - } - - /// Push a new enum definition, returning a mutable reference to it. - pub fn new_enum(&mut self, name: &str) -> &mut Enum { - self.scope.new_enum(name) - } - - /// Push an enum definition - pub fn push_enum(&mut self, item: Enum) -> &mut Self { - self.scope.push_enum(item); - self - } - - /// Push a new `impl` block, returning a mutable reference to it. - pub fn new_impl(&mut self, target: &str) -> &mut Impl { - self.scope.new_impl(target) - } - - /// Push an `impl` block. - pub fn push_impl(&mut self, item: Impl) -> &mut Self { - self.scope.push_impl(item); - self - } - - /// Push a trait definition - pub fn push_trait(&mut self, item: Trait) -> &mut Self { - self.scope.push_trait(item); - self - } - - /// Formats the module using the given formatter. - pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - if let Some(ref vis) = self.vis { - write!(fmt, "{} ", vis)?; - } - - write!(fmt, "mod {}", self.name)?; - fmt.block(|fmt| self.scope.fmt(fmt)) - } -} - -// ===== impl Struct ===== - -impl Struct { - /// Return a structure definition with the provided name - pub fn new(name: &str) -> Self { - Struct { - type_def: TypeDef::new(name), - fields: Fields::Empty, - } - } - - /// Returns a reference to the type - pub fn ty(&self) -> &Type { - &self.type_def.ty - } - - /// Set the structure visibility. - pub fn vis(&mut self, vis: &str) -> &mut Self { - self.type_def.vis(vis); - self - } - - /// Add a generic to the struct. - pub fn generic(&mut self, name: &str) -> &mut Self { - self.type_def.ty.generic(name); - self - } - - /// Add a `where` bound to the struct. - pub fn bound(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.type_def.bound(name, ty); - self - } - - /// Set the structure documentation. - pub fn doc(&mut self, docs: &str) -> &mut Self { - self.type_def.doc(docs); - self - } - - /// Add a new type that the struct should derive. - pub fn derive(&mut self, name: &str) -> &mut Self { - self.type_def.derive(name); - self - } - - /// Specify lint attribute to supress a warning or error. - pub fn allow(&mut self, allow: &str) -> &mut Self { - self.type_def.allow(allow); - self - } - - /// Specify representation. - pub fn repr(&mut self, repr: &str) -> &mut Self { - self.type_def.repr(repr); - self - } - - /// Push a named field to the struct. - /// - /// A struct can either set named fields with this function or tuple fields - /// with `push_tuple_field`, but not both. - pub fn push_field(&mut self, field: Field) -> &mut Self - { - self.fields.push_named(field); - self - } - - /// Add a named field to the struct. - /// - /// A struct can either set named fields with this function or tuple fields - /// with `tuple_field`, but not both. - pub fn field(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.fields.named(name, ty); - self - } - - /// Add a tuple field to the struct. - /// - /// A struct can either set tuple fields with this function or named fields - /// with `field`, but not both. - pub fn tuple_field(&mut self, ty: T) -> &mut Self - where - T: Into, - { - self.fields.tuple(ty); - self - } - - /// Formats the struct using the given formatter. - pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - self.type_def.fmt_head("struct", &[], fmt)?; - self.fields.fmt(fmt)?; - - match self.fields { - Fields::Empty => { - write!(fmt, ";\n")?; - } - Fields::Tuple(..) => { - write!(fmt, ";\n")?; - } - _ => {} - } - - Ok(()) - } -} - -// ===== impl Trait ===== - -impl Trait { - /// Return a trait definition with the provided name - pub fn new(name: &str) -> Self { - Trait { - type_def: TypeDef::new(name), - parents: vec![], - associated_tys: vec![], - fns: vec![], - macros: vec![], - } - } - - /// Returns a reference to the type - pub fn ty(&self) -> &Type { - &self.type_def.ty - } - - /// Set the trait visibility. - pub fn vis(&mut self, vis: &str) -> &mut Self { - self.type_def.vis(vis); - self - } - - /// Add a generic to the trait - pub fn generic(&mut self, name: &str) -> &mut Self { - self.type_def.ty.generic(name); - self - } - - /// Add a `where` bound to the trait. - pub fn bound(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.type_def.bound(name, ty); - self - } - - /// Add a macro to the trait def (e.g. `"#[async_trait]"`) - pub fn r#macro(&mut self, r#macro: &str) -> &mut Self { - self.type_def.r#macro(r#macro); - self - } - - /// Add a parent trait. - pub fn parent(&mut self, ty: T) -> &mut Self - where - T: Into, - { - self.parents.push(ty.into()); - self - } - - /// Set the trait documentation. - pub fn doc(&mut self, docs: &str) -> &mut Self { - self.type_def.doc(docs); - self - } - - /// Add an associated type. Returns a mutable reference to the new - /// associated type for futher configuration. - pub fn associated_type(&mut self, name: &str) -> &mut AssociatedType { - self.associated_tys.push(AssociatedType(Bound { - name: name.to_string(), - bound: vec![], - })); - - self.associated_tys.last_mut().unwrap() - } - - /// Push a new function definition, returning a mutable reference to it. - pub fn new_fn(&mut self, name: &str) -> &mut Function { - let mut func = Function::new(name); - func.body = None; - - self.push_fn(func); - self.fns.last_mut().unwrap() - } - - /// Push a function definition. - pub fn push_fn(&mut self, item: Function) -> &mut Self { - self.fns.push(item); - self - } - - /// Formats the scope using the given formatter. - pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - self.type_def.fmt_head("trait", &self.parents, fmt)?; - - fmt.block(|fmt| { - let assoc = &self.associated_tys; - - // format associated types - if !assoc.is_empty() { - for ty in assoc { - let ty = &ty.0; - - write!(fmt, "type {}", ty.name)?; - - if !ty.bound.is_empty() { - write!(fmt, ": ")?; - fmt_bound_rhs(&ty.bound, fmt)?; - } - - write!(fmt, ";\n")?; - } - } - - for (i, func) in self.fns.iter().enumerate() { - if i != 0 || !assoc.is_empty() { - write!(fmt, "\n")?; - } - - func.fmt(true, fmt)?; - } - - Ok(()) - }) - } -} - -// ===== impl Enum ===== - -impl Enum { - /// Return a enum definition with the provided name. - pub fn new(name: &str) -> Self { - Enum { - type_def: TypeDef::new(name), - variants: vec![], - } - } - - /// Returns a reference to the type. - pub fn ty(&self) -> &Type { - &self.type_def.ty - } - - /// Set the enum visibility. - pub fn vis(&mut self, vis: &str) -> &mut Self { - self.type_def.vis(vis); - self - } - - /// Add a generic to the enum. - pub fn generic(&mut self, name: &str) -> &mut Self { - self.type_def.ty.generic(name); - self - } - - /// Add a `where` bound to the enum. - pub fn bound(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.type_def.bound(name, ty); - self - } - - /// Set the enum documentation. - pub fn doc(&mut self, docs: &str) -> &mut Self { - self.type_def.doc(docs); - self - } - - /// Add a new type that the struct should derive. - pub fn derive(&mut self, name: &str) -> &mut Self { - self.type_def.derive(name); - self - } - - /// Specify lint attribute to supress a warning or error. - pub fn allow(&mut self, allow: &str) -> &mut Self { - self.type_def.allow(allow); - self - } - - /// Specify representation. - pub fn repr(&mut self, repr: &str) -> &mut Self { - self.type_def.repr(repr); - self - } - - /// Push a variant to the enum, returning a mutable reference to it. - pub fn new_variant(&mut self, name: &str) -> &mut Variant { - self.push_variant(Variant::new(name)); - self.variants.last_mut().unwrap() - } - - /// Push a variant to the enum. - pub fn push_variant(&mut self, item: Variant) -> &mut Self { - self.variants.push(item); - self - } - - /// Formats the enum using the given formatter. - pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - self.type_def.fmt_head("enum", &[], fmt)?; - - fmt.block(|fmt| { - for variant in &self.variants { - variant.fmt(fmt)?; - } - - Ok(()) - }) - } -} - -// ===== impl Variant ===== - -impl Variant { - /// Return a new enum variant with the given name. - pub fn new(name: &str) -> Self { - Variant { - name: name.to_string(), - fields: Fields::Empty, - } - } - - /// Add a named field to the variant. - pub fn named(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.fields.named(name, ty); - self - } - - /// Add a tuple field to the variant. - pub fn tuple(&mut self, ty: &str) -> &mut Self { - self.fields.tuple(ty); - self - } - - /// Formats the variant using the given formatter. - pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - write!(fmt, "{}", self.name)?; - self.fields.fmt(fmt)?; - write!(fmt, ",\n")?; - - Ok(()) - } -} - -// ===== impl Type ===== - -impl Type { - /// Return a new type with the given name. - pub fn new(name: &str) -> Self { - Type { - name: name.to_string(), - generics: vec![], - } - } - - /// Add a generic to the type. - pub fn generic(&mut self, ty: T) -> &mut Self - where - T: Into, - { - // Make sure that the name doesn't already include generics - assert!( - !self.name.contains("<"), - "type name already includes generics" - ); - - self.generics.push(ty.into()); - self - } - - /// Rewrite the `Type` with the provided path - /// - /// TODO: Is this needed? - pub fn path(&self, path: &str) -> Type { - // TODO: This isn't really correct - assert!(!self.name.contains("::")); - - let mut name = path.to_string(); - name.push_str("::"); - name.push_str(&self.name); - - Type { - name, - generics: self.generics.clone(), - } - } - - /// Formats the struct using the given formatter. - pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - write!(fmt, "{}", self.name)?; - Type::fmt_slice(&self.generics, fmt) - } - - fn fmt_slice(generics: &[Type], fmt: &mut Formatter) -> fmt::Result { - if !generics.is_empty() { - write!(fmt, "<")?; - - for (i, ty) in generics.iter().enumerate() { - if i != 0 { - write!(fmt, ", ")? - } - ty.fmt(fmt)?; - } - - write!(fmt, ">")?; - } - - Ok(()) - } -} - -impl<'a> From<&'a str> for Type { - fn from(src: &'a str) -> Self { - Type::new(src) - } -} - -impl From for Type { - fn from(src: String) -> Self { - Type { - name: src, - generics: vec![], - } - } -} - -impl<'a> From<&'a String> for Type { - fn from(src: &'a String) -> Self { - Type::new(src) - } -} - -impl<'a> From<&'a Type> for Type { - fn from(src: &'a Type) -> Self { - src.clone() - } -} - -// ===== impl TypeDef ===== - -impl TypeDef { - /// Return a structure definition with the provided name - fn new(name: &str) -> Self { - TypeDef { - ty: Type::new(name), - vis: None, - docs: None, - derive: vec![], - allow: None, - repr: None, - bounds: vec![], - macros: vec![], - } - } - - fn vis(&mut self, vis: &str) { - self.vis = Some(vis.to_string()); - } - - fn bound(&mut self, name: &str, ty: T) - where - T: Into, - { - self.bounds.push(Bound { - name: name.to_string(), - bound: vec![ty.into()], - }); - } - - fn r#macro(&mut self, r#macro: &str) { - self.macros.push(r#macro.to_string()); - } - - fn doc(&mut self, docs: &str) { - self.docs = Some(Docs::new(docs)); - } - - fn derive(&mut self, name: &str) { - self.derive.push(name.to_string()); - } - - fn allow(&mut self, allow: &str) { - self.allow = Some(allow.to_string()); - } - - fn repr(&mut self, repr: &str) { - self.repr = Some(repr.to_string()); - } - - fn fmt_head(&self, keyword: &str, parents: &[Type], fmt: &mut Formatter) -> fmt::Result { - if let Some(ref docs) = self.docs { - docs.fmt(fmt)?; - } - - self.fmt_allow(fmt)?; - self.fmt_derive(fmt)?; - self.fmt_repr(fmt)?; - self.fmt_macros(fmt)?; - - if let Some(ref vis) = self.vis { - write!(fmt, "{} ", vis)?; - } - - write!(fmt, "{} ", keyword)?; - self.ty.fmt(fmt)?; - - if !parents.is_empty() { - for (i, ty) in parents.iter().enumerate() { - if i == 0 { - write!(fmt, ": ")?; - } else { - write!(fmt, " + ")?; - } - - ty.fmt(fmt)?; - } - } - - fmt_bounds(&self.bounds, fmt)?; - - Ok(()) - } - - fn fmt_allow(&self, fmt: &mut Formatter) -> fmt::Result { - if let Some(ref allow) = self.allow { - write!(fmt, "#[allow({})]\n", allow)?; - } - - Ok(()) - } - - fn fmt_repr(&self, fmt: &mut Formatter) -> fmt::Result { - if let Some(ref repr) = self.repr { - write!(fmt, "#[repr({})]\n", repr)?; - } - - Ok(()) - } - - fn fmt_derive(&self, fmt: &mut Formatter) -> fmt::Result { - if !self.derive.is_empty() { - write!(fmt, "#[derive(")?; - - for (i, name) in self.derive.iter().enumerate() { - if i != 0 { - write!(fmt, ", ")? - } - write!(fmt, "{}", name)?; - } - - write!(fmt, ")]\n")?; - } - - Ok(()) - } - - fn fmt_macros(&self, fmt: &mut Formatter) -> fmt::Result { - for m in self.macros.iter() { - write!(fmt, "{}\n", m)?; - } - Ok(()) - } -} - -fn fmt_generics(generics: &[String], fmt: &mut Formatter) -> fmt::Result { - if !generics.is_empty() { - write!(fmt, "<")?; - - for (i, ty) in generics.iter().enumerate() { - if i != 0 { - write!(fmt, ", ")? - } - write!(fmt, "{}", ty)?; - } - - write!(fmt, ">")?; - } - - Ok(()) -} - -fn fmt_bounds(bounds: &[Bound], fmt: &mut Formatter) -> fmt::Result { - if !bounds.is_empty() { - write!(fmt, "\n")?; - - // Write first bound - write!(fmt, "where {}: ", bounds[0].name)?; - fmt_bound_rhs(&bounds[0].bound, fmt)?; - write!(fmt, ",\n")?; - - for bound in &bounds[1..] { - write!(fmt, " {}: ", bound.name)?; - fmt_bound_rhs(&bound.bound, fmt)?; - write!(fmt, ",\n")?; - } - } - - Ok(()) -} - -fn fmt_bound_rhs(tys: &[Type], fmt: &mut Formatter) -> fmt::Result { - for (i, ty) in tys.iter().enumerate() { - if i != 0 { - write!(fmt, " + ")? - } - ty.fmt(fmt)?; - } - - Ok(()) -} - -// ===== impl AssociatedType ===== - -impl AssociatedType { - /// Add a bound to the associated type. - pub fn bound(&mut self, ty: T) -> &mut Self - where - T: Into, - { - self.0.bound.push(ty.into()); - self - } -} - -// ===== impl Field ===== - -impl Field { - /// Return a field definition with the provided name and type - pub fn new(name: &str, ty: T) -> Self - where T: Into, - { - Field { - name: name.into(), - ty: ty.into(), - documentation: Vec::new(), - annotation: Vec::new(), - } - } - - /// Set field's documentation. - pub fn doc(&mut self, documentation: Vec<&str>) -> &mut Self { - self.documentation = documentation.iter().map(|doc| doc.to_string()).collect(); - self - } - - /// Set field's annotation. - pub fn annotation(&mut self, annotation: Vec<&str>) -> &mut Self { - self.annotation = annotation.iter().map(|ann| ann.to_string()).collect(); - self - } -} - -// ===== impl Fields ===== - -impl Fields { - fn push_named(&mut self, field: Field) -> &mut Self - { - match *self { - Fields::Empty => { - *self = Fields::Named(vec![field]); - } - Fields::Named(ref mut fields) => { - fields.push(field); - } - _ => panic!("field list is named"), - } - - self - } - - fn named(&mut self, name: &str, ty: T) -> &mut Self - where T: Into, - { - self.push_named(Field { - name: name.to_string(), - ty: ty.into(), - documentation: Vec::new(), - annotation: Vec::new(), - }) - } - - fn tuple(&mut self, ty: T) -> &mut Self - where - T: Into, - { - match *self { - Fields::Empty => { - *self = Fields::Tuple(vec![ty.into()]); - } - Fields::Tuple(ref mut fields) => { - fields.push(ty.into()); - } - _ => panic!("field list is tuple"), - } - - self - } - - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - match *self { - Fields::Named(ref fields) => { - assert!(!fields.is_empty()); - - fmt.block(|fmt| { - for f in fields { - if !f.documentation.is_empty() { - for doc in &f.documentation { - write!(fmt, "/// {}\n", doc)?; - } - } - if !f.annotation.is_empty() { - for ann in &f.annotation { - write!(fmt, "{}\n", ann)?; - } - } - write!(fmt, "{}: ", f.name)?; - f.ty.fmt(fmt)?; - write!(fmt, ",\n")?; - } - - Ok(()) - })?; - } - Fields::Tuple(ref tys) => { - assert!(!tys.is_empty()); - - write!(fmt, "(")?; - - for (i, ty) in tys.iter().enumerate() { - if i != 0 { - write!(fmt, ", ")?; - } - ty.fmt(fmt)?; - } - - write!(fmt, ")")?; - } - Fields::Empty => {} - } - - Ok(()) - } -} - -// ===== impl Impl ===== - -impl Impl { - /// Return a new impl definition - pub fn new(target: T) -> Self - where - T: Into, - { - Impl { - target: target.into(), - generics: vec![], - impl_trait: None, - assoc_tys: vec![], - bounds: vec![], - fns: vec![], - macros: vec![], - } - } - - /// Add a generic to the impl block. - /// - /// This adds the generic for the block (`impl`) and not the target type. - pub fn generic(&mut self, name: &str) -> &mut Self { - self.generics.push(name.to_string()); - self - } - - /// Add a generic to the target type. - pub fn target_generic(&mut self, ty: T) -> &mut Self - where - T: Into, - { - self.target.generic(ty); - self - } - - /// Set the trait that the impl block is implementing. - pub fn impl_trait(&mut self, ty: T) -> &mut Self - where - T: Into, - { - self.impl_trait = Some(ty.into()); - self - } - - /// Add a macro to the impl block (e.g. `"#[async_trait]"`) - pub fn r#macro(&mut self, r#macro: &str) -> &mut Self { - self.macros.push(r#macro.to_string()); - self - } - - /// Set an associated type. - pub fn associate_type(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.assoc_tys.push(Field { - name: name.to_string(), - ty: ty.into(), - documentation: Vec::new(), - annotation: Vec::new(), - }); - - self - } - - /// Add a `where` bound to the impl block. - pub fn bound(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.bounds.push(Bound { - name: name.to_string(), - bound: vec![ty.into()], - }); - self - } - - /// Push a new function definition, returning a mutable reference to it. - pub fn new_fn(&mut self, name: &str) -> &mut Function { - self.push_fn(Function::new(name)); - self.fns.last_mut().unwrap() - } - - /// Push a function definition. - pub fn push_fn(&mut self, item: Function) -> &mut Self { - self.fns.push(item); - self - } - - /// Formats the impl block using the given formatter. - pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - for m in self.macros.iter() { - write!(fmt, "{}\n", m)?; - } - write!(fmt, "impl")?; - fmt_generics(&self.generics[..], fmt)?; - - if let Some(ref t) = self.impl_trait { - write!(fmt, " ")?; - t.fmt(fmt)?; - write!(fmt, " for")?; - } - - write!(fmt, " ")?; - self.target.fmt(fmt)?; - - fmt_bounds(&self.bounds, fmt)?; - - fmt.block(|fmt| { - // format associated types - if !self.assoc_tys.is_empty() { - for ty in &self.assoc_tys { - write!(fmt, "type {} = ", ty.name)?; - ty.ty.fmt(fmt)?; - write!(fmt, ";\n")?; - } - } - - for (i, func) in self.fns.iter().enumerate() { - if i != 0 || !self.assoc_tys.is_empty() { - write!(fmt, "\n")?; - } - - func.fmt(false, fmt)?; - } - - Ok(()) - }) - } -} - -// ===== impl Import ===== - -impl Import { - /// Return a new import. - pub fn new(path: &str, ty: &str) -> Self { - Import { - line: format!("{}::{}", path, ty), - vis: None, - } - } - - /// Set the import visibility. - pub fn vis(&mut self, vis: &str) -> &mut Self { - self.vis = Some(vis.to_string()); - self - } -} - -// ===== impl Function ===== - -impl Function { - /// Return a new function definition. - pub fn new(name: &str) -> Self { - Function { - name: name.to_string(), - docs: None, - allow: None, - vis: None, - generics: vec![], - arg_self: None, - args: vec![], - ret: None, - bounds: vec![], - body: Some(vec![]), - attributes: vec![], - extern_abi: None, - r#async: false, - } - } - - /// Set the function documentation. - pub fn doc(&mut self, docs: &str) -> &mut Self { - self.docs = Some(Docs::new(docs)); - self - } - - /// Specify lint attribute to supress a warning or error. - pub fn allow(&mut self, allow: &str) -> &mut Self { - self.allow = Some(allow.to_string()); - self - } - - /// Set the function visibility. - pub fn vis(&mut self, vis: &str) -> &mut Self { - self.vis = Some(vis.to_string()); - self - } - - /// Set whether this function is async or not - pub fn set_async(&mut self, r#async: bool) -> &mut Self { - self.r#async = r#async; - self - } - - /// Add a generic to the function. - pub fn generic(&mut self, name: &str) -> &mut Self { - self.generics.push(name.to_string()); - self - } - - /// Add `self` as a function argument. - pub fn arg_self(&mut self) -> &mut Self { - self.arg_self = Some("self".to_string()); - self - } - - /// Add `&self` as a function argument. - pub fn arg_ref_self(&mut self) -> &mut Self { - self.arg_self = Some("&self".to_string()); - self - } - - /// Add `&mut self` as a function argument. - pub fn arg_mut_self(&mut self) -> &mut Self { - self.arg_self = Some("&mut self".to_string()); - self - } - - /// Add a function argument. - pub fn arg(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.args.push(Field { - name: name.to_string(), - ty: ty.into(), - // While a `Field` is used here, both `documentation` - // and `annotation` does not make sense for function arguments. - // Simply use empty strings. - documentation: Vec::new(), - annotation: Vec::new(), - }); - - self - } - - /// Set the function return type. - pub fn ret(&mut self, ty: T) -> &mut Self - where - T: Into, - { - self.ret = Some(ty.into()); - self - } - - /// Add a `where` bound to the function. - pub fn bound(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.bounds.push(Bound { - name: name.to_string(), - bound: vec![ty.into()], - }); - self - } - - /// Push a line to the function implementation. - pub fn line(&mut self, line: T) -> &mut Self - where - T: ToString, - { - self.body - .get_or_insert(vec![]) - .push(Body::String(line.to_string())); - - self - } - - /// Add an attribute to the function. - /// - /// ``` - /// use codegen::Function; - /// - /// let mut func = Function::new("test"); - /// - /// // add a `#[test]` attribute - /// func.attr("test"); - /// ``` - pub fn attr(&mut self, attribute: &str) -> &mut Self { - self.attributes.push(attribute.to_string()); - self - } - - /// Specify an `extern` ABI for the function. - /// ``` - /// use codegen::Function; - /// - /// let mut extern_func = Function::new("extern_func"); - /// - /// // use the "C" calling convention - /// extern_func.extern_abi("C"); - /// ``` - pub fn extern_abi(&mut self, abi: &str) -> &mut Self { - self.extern_abi.replace(abi.to_string()); - self - } - - /// Push a block to the function implementation - pub fn push_block(&mut self, block: Block) -> &mut Self { - self.body.get_or_insert(vec![]).push(Body::Block(block)); - - self - } - - /// Formats the function using the given formatter. - pub fn fmt(&self, is_trait: bool, fmt: &mut Formatter) -> fmt::Result { - if let Some(ref docs) = self.docs { - docs.fmt(fmt)?; - } - - if let Some(ref allow) = self.allow { - write!(fmt, "#[allow({})]\n", allow)?; - } - - for attr in self.attributes.iter() { - write!(fmt, "#[{}]\n", attr)?; - } - - if is_trait { - assert!( - self.vis.is_none(), - "trait fns do not have visibility modifiers" - ); - } - - if let Some(ref vis) = self.vis { - write!(fmt, "{} ", vis)?; - } - - if let Some(ref extern_abi) = self.extern_abi { - write!(fmt, "extern \"{extern_abi}\" ", extern_abi = extern_abi)?; - } - - if self.r#async { - write!(fmt, "async ")?; - } - - write!(fmt, "fn {}", self.name)?; - fmt_generics(&self.generics, fmt)?; - - write!(fmt, "(")?; - - if let Some(ref s) = self.arg_self { - write!(fmt, "{}", s)?; - } - - for (i, arg) in self.args.iter().enumerate() { - if i != 0 || self.arg_self.is_some() { - write!(fmt, ", ")?; - } - - write!(fmt, "{}: ", arg.name)?; - arg.ty.fmt(fmt)?; - } - - write!(fmt, ")")?; - - if let Some(ref ret) = self.ret { - write!(fmt, " -> ")?; - ret.fmt(fmt)?; - } - - fmt_bounds(&self.bounds, fmt)?; - - match self.body { - Some(ref body) => fmt.block(|fmt| { - for b in body { - b.fmt(fmt)?; - } - - Ok(()) - }), - None => { - if !is_trait { - panic!("impl blocks must define fn bodies"); - } - - write!(fmt, ";\n") - } - } - } -} - -// ===== impl Block ===== - -impl Block { - /// Returns an empty code block. - pub fn new(before: &str) -> Self { - Block { - before: Some(before.to_string()), - after: None, - body: vec![], - } - } - - /// Push a line to the code block. - pub fn line(&mut self, line: T) -> &mut Self - where - T: ToString, - { - self.body.push(Body::String(line.to_string())); - self - } - - /// Push a nested block to this block. - pub fn push_block(&mut self, block: Block) -> &mut Self { - self.body.push(Body::Block(block)); - self - } - - /// Add a snippet after the block. - pub fn after(&mut self, after: &str) -> &mut Self { - self.after = Some(after.to_string()); - self - } - - /// Formats the block using the given formatter. - pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - if let Some(ref before) = self.before { - write!(fmt, "{}", before)?; - } - - // Inlined `Formatter::fmt` - - if !fmt.is_start_of_line() { - write!(fmt, " ")?; - } - - write!(fmt, "{{\n")?; - - fmt.indent(|fmt| { - for b in &self.body { - b.fmt(fmt)?; - } - - Ok(()) - })?; - - write!(fmt, "}}")?; - - if let Some(ref after) = self.after { - write!(fmt, "{}", after)?; - } - - write!(fmt, "\n")?; - Ok(()) - } -} - -// ===== impl Body ===== - -impl Body { - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - match *self { - Body::String(ref s) => write!(fmt, "{}\n", s), - Body::Block(ref b) => b.fmt(fmt), - } - } -} - -// ===== impl Docs ===== - -impl Docs { - fn new(docs: &str) -> Self { - Docs { - docs: docs.to_string(), - } - } - - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - for line in self.docs.lines() { - write!(fmt, "/// {}\n", line)?; - } - - Ok(()) - } -} - -// ===== impl Formatter ===== - -impl<'a> Formatter<'a> { - /// Return a new formatter that writes to the given string. - pub fn new(dst: &'a mut String) -> Self { - Formatter { - dst, - spaces: 0, - indent: DEFAULT_INDENT, - } - } - - fn block(&mut self, f: F) -> fmt::Result - where - F: FnOnce(&mut Self) -> fmt::Result, - { - if !self.is_start_of_line() { - write!(self, " ")?; - } - - write!(self, "{{\n")?; - self.indent(f)?; - write!(self, "}}\n")?; - Ok(()) - } - - /// Call the given function with the indentation level incremented by one. - fn indent(&mut self, f: F) -> R - where - F: FnOnce(&mut Self) -> R, - { - self.spaces += self.indent; - let ret = f(self); - self.spaces -= self.indent; - ret - } - - fn is_start_of_line(&self) -> bool { - self.dst.is_empty() || self.dst.as_bytes().last() == Some(&b'\n') - } - - fn push_spaces(&mut self) { - for _ in 0..self.spaces { - self.dst.push_str(" "); - } - } -} - -impl<'a> fmt::Write for Formatter<'a> { - fn write_str(&mut self, s: &str) -> fmt::Result { - let mut first = true; - let mut should_indent = self.is_start_of_line(); - - for line in s.lines() { - if !first { - self.dst.push_str("\n"); - } - - first = false; - - let do_indent = should_indent && !line.is_empty() && line.as_bytes()[0] != b'\n'; - - if do_indent { - self.push_spaces(); - } - - // If this loops again, then we just wrote a new line - should_indent = true; - - self.dst.push_str(line); - } - - if s.as_bytes().last() == Some(&b'\n') { - self.dst.push_str("\n"); - } - - Ok(()) - } -} +mod associated_type; +mod block; +mod body; +mod bound; +mod docs; +mod field; +mod fields; +mod formatter; +mod function; +mod import; +mod item; +mod module; +mod scope; +mod type_def; +mod variant; + +mod r#enum; +mod r#impl; +mod r#struct; +mod r#trait; +mod r#type; + + +pub use associated_type::*; +pub use block::*; +pub use field::*; +pub use formatter::*; +pub use function::*; +pub use import::*; +pub use module::*; +pub use scope::*; +pub use variant::*; + +pub use r#enum::*; +pub use r#impl::*; +pub use r#struct::*; +pub use r#trait::*; +pub use r#type::*; diff --git a/src/module.rs b/src/module.rs new file mode 100644 index 0000000..da42968 --- /dev/null +++ b/src/module.rs @@ -0,0 +1,176 @@ +use std::fmt::{self, Write}; + +use docs::Docs; +use formatter::Formatter; +use function::Function; +use scope::Scope; + +use r#enum::Enum; +use r#impl::Impl; +use r#struct::Struct; +use r#trait::Trait; + + +/// Defines a module. +#[derive(Debug, Clone)] +pub struct Module { + /// Module name + pub name: String, + + /// Visibility + vis: Option, + + /// Module documentation + docs: Option, + + /// Contents of the module + scope: Scope, +} + + +impl Module { + /// Return a new, blank module + pub fn new(name: &str) -> Self { + Module { + name: name.to_string(), + vis: None, + docs: None, + scope: Scope::new(), + } + } + + /// Returns a mutable reference to the module's scope. + pub fn scope(&mut self) -> &mut Scope { + &mut self.scope + } + + /// Set the module visibility. + pub fn vis(&mut self, vis: &str) -> &mut Self { + self.vis = Some(vis.to_string()); + self + } + + /// Import a type into the module's scope. + /// + /// This results in a new `use` statement bein added to the beginning of the + /// module. + pub fn import(&mut self, path: &str, ty: &str) -> &mut Self { + self.scope.import(path, ty); + self + } + + /// Push a new module definition, returning a mutable reference to it. + /// + /// # Panics + /// + /// Since a module's name must uniquely identify it within the scope in + /// which it is defined, pushing a module whose name is already defined + /// in this scope will cause this function to panic. + /// + /// In many cases, the [`get_or_new_module`] function is preferrable, as it + /// will return the existing definition instead. + /// + /// [`get_or_new_module`]: #method.get_or_new_module + pub fn new_module(&mut self, name: &str) -> &mut Module { + self.scope.new_module(name) + } + + /// Returns a reference to a module if it is exists in this scope. + pub fn get_module(&self, name: &Q) -> Option<&Module> + where + String: PartialEq, + { + self.scope.get_module(name) + } + + /// Returns a mutable reference to a module if it is exists in this scope. + pub fn get_module_mut(&mut self, name: &Q) -> Option<&mut Module> + where + String: PartialEq, + { + self.scope.get_module_mut(name) + } + + /// Returns a mutable reference to a module, creating it if it does + /// not exist. + pub fn get_or_new_module(&mut self, name: &str) -> &mut Module { + self.scope.get_or_new_module(name) + } + + /// Push a module definition. + /// + /// # Panics + /// + /// Since a module's name must uniquely identify it within the scope in + /// which it is defined, pushing a module whose name is already defined + /// in this scope will cause this function to panic. + /// + /// In many cases, the [`get_or_new_module`] function is preferrable, as it will + /// return the existing definition instead. + /// + /// [`get_or_new_module`]: #method.get_or_new_module + pub fn push_module(&mut self, item: Module) -> &mut Self { + self.scope.push_module(item); + self + } + + /// Push a new struct definition, returning a mutable reference to it. + pub fn new_struct(&mut self, name: &str) -> &mut Struct { + self.scope.new_struct(name) + } + + /// Push a structure definition + pub fn push_struct(&mut self, item: Struct) -> &mut Self { + self.scope.push_struct(item); + self + } + + /// Push a new function definition, returning a mutable reference to it. + pub fn new_fn(&mut self, name: &str) -> &mut Function { + self.scope.new_fn(name) + } + + /// Push a function definition + pub fn push_fn(&mut self, item: Function) -> &mut Self { + self.scope.push_fn(item); + self + } + + /// Push a new enum definition, returning a mutable reference to it. + pub fn new_enum(&mut self, name: &str) -> &mut Enum { + self.scope.new_enum(name) + } + + /// Push an enum definition + pub fn push_enum(&mut self, item: Enum) -> &mut Self { + self.scope.push_enum(item); + self + } + + /// Push a new `impl` block, returning a mutable reference to it. + pub fn new_impl(&mut self, target: &str) -> &mut Impl { + self.scope.new_impl(target) + } + + /// Push an `impl` block. + pub fn push_impl(&mut self, item: Impl) -> &mut Self { + self.scope.push_impl(item); + self + } + + /// Push a trait definition + pub fn push_trait(&mut self, item: Trait) -> &mut Self { + self.scope.push_trait(item); + self + } + + /// Formats the module using the given formatter. + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + if let Some(ref vis) = self.vis { + write!(fmt, "{} ", vis)?; + } + + write!(fmt, "mod {}", self.name)?; + fmt.block(|fmt| self.scope.fmt(fmt)) + } +} diff --git a/src/scope.rs b/src/scope.rs new file mode 100644 index 0000000..aa7bd25 --- /dev/null +++ b/src/scope.rs @@ -0,0 +1,322 @@ +extern crate indexmap; + + +use std::fmt::{self, Write}; + +use self::indexmap::IndexMap; + +use docs::Docs; +use formatter::Formatter; +use function::Function; +use import::Import; +use item::Item; +use module::Module; + +use r#enum::Enum; +use r#impl::Impl; +use r#struct::Struct; +use r#trait::Trait; + + +/// Defines a scope. +/// +/// A scope contains modules, types, etc... +#[derive(Debug, Clone)] +pub struct Scope { + /// Scope documentation + docs: Option, + + /// Imports + imports: IndexMap>, + + /// Contents of the documentation, + items: Vec, +} + + +impl Scope { + /// Returns a new scope + pub fn new() -> Self { + Scope { + docs: None, + imports: IndexMap::new(), + items: vec![], + } + } + + /// Import a type into the scope. + /// + /// This results in a new `use` statement being added to the beginning of + /// the scope. + pub fn import(&mut self, path: &str, ty: &str) -> &mut Import { + // handle cases where the caller wants to refer to a type namespaced + // within the containing namespace, like "a::B". + let ty = ty.split("::").next().unwrap_or(ty); + self.imports + .entry(path.to_string()) + .or_insert(IndexMap::new()) + .entry(ty.to_string()) + .or_insert_with(|| Import::new(path, ty)) + } + + /// Push a new module definition, returning a mutable reference to it. + /// + /// # Panics + /// + /// Since a module's name must uniquely identify it within the scope in + /// which it is defined, pushing a module whose name is already defined + /// in this scope will cause this function to panic. + /// + /// In many cases, the [`get_or_new_module`] function is preferrable, as it + /// will return the existing definition instead. + /// + /// [`get_or_new_module`]: #method.get_or_new_module + pub fn new_module(&mut self, name: &str) -> &mut Module { + self.push_module(Module::new(name)); + + match *self.items.last_mut().unwrap() { + Item::Module(ref mut v) => v, + _ => unreachable!(), + } + } + + /// Returns a mutable reference to a module if it is exists in this scope. + pub fn get_module_mut(&mut self, name: &Q) -> Option<&mut Module> + where + String: PartialEq, + { + self.items + .iter_mut() + .filter_map(|item| match item { + &mut Item::Module(ref mut module) if module.name == *name => Some(module), + _ => None, + }) + .next() + } + + /// Returns a mutable reference to a module if it is exists in this scope. + pub fn get_module(&self, name: &Q) -> Option<&Module> + where + String: PartialEq, + { + self.items + .iter() + .filter_map(|item| match item { + &Item::Module(ref module) if module.name == *name => Some(module), + _ => None, + }) + .next() + } + + /// Returns a mutable reference to a module, creating it if it does + /// not exist. + pub fn get_or_new_module(&mut self, name: &str) -> &mut Module { + if self.get_module(name).is_some() { + self.get_module_mut(name).unwrap() + } else { + self.new_module(name) + } + } + + /// Push a module definition. + /// + /// # Panics + /// + /// Since a module's name must uniquely identify it within the scope in + /// which it is defined, pushing a module whose name is already defined + /// in this scope will cause this function to panic. + /// + /// In many cases, the [`get_or_new_module`] function is preferrable, as it will + /// return the existing definition instead. + /// + /// [`get_or_new_module`]: #method.get_or_new_module + pub fn push_module(&mut self, item: Module) -> &mut Self { + assert!(self.get_module(&item.name).is_none()); + self.items.push(Item::Module(item)); + self + } + + /// Push a new struct definition, returning a mutable reference to it. + pub fn new_struct(&mut self, name: &str) -> &mut Struct { + self.push_struct(Struct::new(name)); + + match *self.items.last_mut().unwrap() { + Item::Struct(ref mut v) => v, + _ => unreachable!(), + } + } + + /// Push a struct definition + pub fn push_struct(&mut self, item: Struct) -> &mut Self { + self.items.push(Item::Struct(item)); + self + } + + /// Push a new function definition, returning a mutable reference to it. + pub fn new_fn(&mut self, name: &str) -> &mut Function { + self.push_fn(Function::new(name)); + + match *self.items.last_mut().unwrap() { + Item::Function(ref mut v) => v, + _ => unreachable!(), + } + } + + /// Push a function definition + pub fn push_fn(&mut self, item: Function) -> &mut Self { + self.items.push(Item::Function(item)); + self + } + + /// Push a new trait definition, returning a mutable reference to it. + pub fn new_trait(&mut self, name: &str) -> &mut Trait { + self.push_trait(Trait::new(name)); + + match *self.items.last_mut().unwrap() { + Item::Trait(ref mut v) => v, + _ => unreachable!(), + } + } + + /// Push a trait definition + pub fn push_trait(&mut self, item: Trait) -> &mut Self { + self.items.push(Item::Trait(item)); + self + } + + /// Push a new struct definition, returning a mutable reference to it. + pub fn new_enum(&mut self, name: &str) -> &mut Enum { + self.push_enum(Enum::new(name)); + + match *self.items.last_mut().unwrap() { + Item::Enum(ref mut v) => v, + _ => unreachable!(), + } + } + + /// Push a structure definition + pub fn push_enum(&mut self, item: Enum) -> &mut Self { + self.items.push(Item::Enum(item)); + self + } + + /// Push a new `impl` block, returning a mutable reference to it. + pub fn new_impl(&mut self, target: &str) -> &mut Impl { + self.push_impl(Impl::new(target)); + + match *self.items.last_mut().unwrap() { + Item::Impl(ref mut v) => v, + _ => unreachable!(), + } + } + + /// Push an `impl` block. + pub fn push_impl(&mut self, item: Impl) -> &mut Self { + self.items.push(Item::Impl(item)); + self + } + + /// Push a raw string to the scope. + /// + /// This string will be included verbatim in the formatted string. + pub fn raw(&mut self, val: &str) -> &mut Self { + self.items.push(Item::Raw(val.to_string())); + self + } + + /// Return a string representation of the scope. + pub fn to_string(&self) -> String { + let mut ret = String::new(); + + self.fmt(&mut Formatter::new(&mut ret)).unwrap(); + + // Remove the trailing newline + if ret.as_bytes().last() == Some(&b'\n') { + ret.pop(); + } + + ret + } + + /// Formats the scope using the given formatter. + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + self.fmt_imports(fmt)?; + + if !self.imports.is_empty() { + write!(fmt, "\n")?; + } + + for (i, item) in self.items.iter().enumerate() { + if i != 0 { + write!(fmt, "\n")?; + } + + match *item { + Item::Module(ref v) => v.fmt(fmt)?, + Item::Struct(ref v) => v.fmt(fmt)?, + Item::Function(ref v) => v.fmt(false, fmt)?, + Item::Trait(ref v) => v.fmt(fmt)?, + Item::Enum(ref v) => v.fmt(fmt)?, + Item::Impl(ref v) => v.fmt(fmt)?, + Item::Raw(ref v) => { + write!(fmt, "{}\n", v)?; + } + } + } + + Ok(()) + } + + fn fmt_imports(&self, fmt: &mut Formatter) -> fmt::Result { + // First, collect all visibilities + let mut visibilities = vec![]; + + for (_, imports) in &self.imports { + for (_, import) in imports { + if !visibilities.contains(&import.vis) { + visibilities.push(import.vis.clone()); + } + } + } + + let mut tys = vec![]; + + // Loop over all visibilities and format the associated imports + for vis in &visibilities { + for (path, imports) in &self.imports { + tys.clear(); + + for (ty, import) in imports { + if *vis == import.vis { + tys.push(ty); + } + } + + if !tys.is_empty() { + if let Some(ref vis) = *vis { + write!(fmt, "{} ", vis)?; + } + + write!(fmt, "use {}::", path)?; + + if tys.len() > 1 { + write!(fmt, "{{")?; + + for (i, ty) in tys.iter().enumerate() { + if i != 0 { + write!(fmt, ", ")?; + } + write!(fmt, "{}", ty)?; + } + + write!(fmt, "}};\n")?; + } else if tys.len() == 1 { + write!(fmt, "{};\n", tys[0])?; + } + } + } + } + + Ok(()) + } +} diff --git a/src/struct.rs b/src/struct.rs new file mode 100644 index 0000000..ea50916 --- /dev/null +++ b/src/struct.rs @@ -0,0 +1,131 @@ +use std::fmt::{self, Write}; + +use field::Field; +use fields::Fields; +use formatter::Formatter; +use type_def::TypeDef; + +use r#type::Type; + + +/// Defines a struct. +#[derive(Debug, Clone)] +pub struct Struct { + type_def: TypeDef, + + /// Struct fields + fields: Fields, +} + + +impl Struct { + /// Return a structure definition with the provided name + pub fn new(name: &str) -> Self { + Struct { + type_def: TypeDef::new(name), + fields: Fields::Empty, + } + } + + /// Returns a reference to the type + pub fn ty(&self) -> &Type { + &self.type_def.ty + } + + /// Set the structure visibility. + pub fn vis(&mut self, vis: &str) -> &mut Self { + self.type_def.vis(vis); + self + } + + /// Add a generic to the struct. + pub fn generic(&mut self, name: &str) -> &mut Self { + self.type_def.ty.generic(name); + self + } + + /// Add a `where` bound to the struct. + pub fn bound(&mut self, name: &str, ty: T) -> &mut Self + where + T: Into, + { + self.type_def.bound(name, ty); + self + } + + /// Set the structure documentation. + pub fn doc(&mut self, docs: &str) -> &mut Self { + self.type_def.doc(docs); + self + } + + /// Add a new type that the struct should derive. + pub fn derive(&mut self, name: &str) -> &mut Self { + self.type_def.derive(name); + self + } + + /// Specify lint attribute to supress a warning or error. + pub fn allow(&mut self, allow: &str) -> &mut Self { + self.type_def.allow(allow); + self + } + + /// Specify representation. + pub fn repr(&mut self, repr: &str) -> &mut Self { + self.type_def.repr(repr); + self + } + + /// Push a named field to the struct. + /// + /// A struct can either set named fields with this function or tuple fields + /// with `push_tuple_field`, but not both. + pub fn push_field(&mut self, field: Field) -> &mut Self + { + self.fields.push_named(field); + self + } + + /// Add a named field to the struct. + /// + /// A struct can either set named fields with this function or tuple fields + /// with `tuple_field`, but not both. + pub fn field(&mut self, name: &str, ty: T) -> &mut Self + where + T: Into, + { + self.fields.named(name, ty); + self + } + + /// Add a tuple field to the struct. + /// + /// A struct can either set tuple fields with this function or named fields + /// with `field`, but not both. + pub fn tuple_field(&mut self, ty: T) -> &mut Self + where + T: Into, + { + self.fields.tuple(ty); + self + } + + /// Formats the struct using the given formatter. + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + self.type_def.fmt_head("struct", &[], fmt)?; + self.fields.fmt(fmt)?; + + match self.fields { + Fields::Empty => { + write!(fmt, ";\n")?; + } + Fields::Tuple(..) => { + write!(fmt, ";\n")?; + } + _ => {} + } + + Ok(()) + } +} diff --git a/src/trait.rs b/src/trait.rs new file mode 100644 index 0000000..1a100b1 --- /dev/null +++ b/src/trait.rs @@ -0,0 +1,142 @@ +use std::fmt::{self, Write}; + +use associated_type::AssociatedType; +use bound::Bound; +use formatter::{Formatter, fmt_bound_rhs}; +use function::Function; +use type_def::TypeDef; + +use r#type::Type; + + +/// Define a trait. +#[derive(Debug, Clone)] +pub struct Trait { + type_def: TypeDef, + parents: Vec, + associated_tys: Vec, + fns: Vec, + macros: Vec, +} + + +impl Trait { + /// Return a trait definition with the provided name + pub fn new(name: &str) -> Self { + Trait { + type_def: TypeDef::new(name), + parents: vec![], + associated_tys: vec![], + fns: vec![], + macros: vec![], + } + } + + /// Returns a reference to the type + pub fn ty(&self) -> &Type { + &self.type_def.ty + } + + /// Set the trait visibility. + pub fn vis(&mut self, vis: &str) -> &mut Self { + self.type_def.vis(vis); + self + } + + /// Add a generic to the trait + pub fn generic(&mut self, name: &str) -> &mut Self { + self.type_def.ty.generic(name); + self + } + + /// Add a `where` bound to the trait. + pub fn bound(&mut self, name: &str, ty: T) -> &mut Self + where + T: Into, + { + self.type_def.bound(name, ty); + self + } + + /// Add a macro to the trait def (e.g. `"#[async_trait]"`) + pub fn r#macro(&mut self, r#macro: &str) -> &mut Self { + self.type_def.r#macro(r#macro); + self + } + + /// Add a parent trait. + pub fn parent(&mut self, ty: T) -> &mut Self + where + T: Into, + { + self.parents.push(ty.into()); + self + } + + /// Set the trait documentation. + pub fn doc(&mut self, docs: &str) -> &mut Self { + self.type_def.doc(docs); + self + } + + /// Add an associated type. Returns a mutable reference to the new + /// associated type for futher configuration. + pub fn associated_type(&mut self, name: &str) -> &mut AssociatedType { + self.associated_tys.push(AssociatedType(Bound { + name: name.to_string(), + bound: vec![], + })); + + self.associated_tys.last_mut().unwrap() + } + + /// Push a new function definition, returning a mutable reference to it. + pub fn new_fn(&mut self, name: &str) -> &mut Function { + let mut func = Function::new(name); + func.body = None; + + self.push_fn(func); + self.fns.last_mut().unwrap() + } + + /// Push a function definition. + pub fn push_fn(&mut self, item: Function) -> &mut Self { + self.fns.push(item); + self + } + + /// Formats the scope using the given formatter. + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + self.type_def.fmt_head("trait", &self.parents, fmt)?; + + fmt.block(|fmt| { + let assoc = &self.associated_tys; + + // format associated types + if !assoc.is_empty() { + for ty in assoc { + let ty = &ty.0; + + write!(fmt, "type {}", ty.name)?; + + if !ty.bound.is_empty() { + write!(fmt, ": ")?; + fmt_bound_rhs(&ty.bound, fmt)?; + } + + write!(fmt, ";\n")?; + } + } + + for (i, func) in self.fns.iter().enumerate() { + if i != 0 || !assoc.is_empty() { + write!(fmt, "\n")?; + } + + func.fmt(true, fmt)?; + } + + Ok(()) + }) + } +} diff --git a/src/type.rs b/src/type.rs new file mode 100644 index 0000000..61c4637 --- /dev/null +++ b/src/type.rs @@ -0,0 +1,104 @@ +use std::fmt::{self, Write}; + +use formatter::Formatter; + + +/// Defines a type. +#[derive(Debug, Clone)] +pub struct Type { + name: String, + generics: Vec, +} + + +impl Type { + /// Return a new type with the given name. + pub fn new(name: &str) -> Self { + Type { + name: name.to_string(), + generics: vec![], + } + } + + /// Add a generic to the type. + pub fn generic(&mut self, ty: T) -> &mut Self + where + T: Into, + { + // Make sure that the name doesn't already include generics + assert!( + !self.name.contains("<"), + "type name already includes generics" + ); + + self.generics.push(ty.into()); + self + } + + /// Rewrite the `Type` with the provided path + /// + /// TODO: Is this needed? + pub fn path(&self, path: &str) -> Type { + // TODO: This isn't really correct + assert!(!self.name.contains("::")); + + let mut name = path.to_string(); + name.push_str("::"); + name.push_str(&self.name); + + Type { + name, + generics: self.generics.clone(), + } + } + + /// Formats the struct using the given formatter. + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, "{}", self.name)?; + Type::fmt_slice(&self.generics, fmt) + } + + fn fmt_slice(generics: &[Type], fmt: &mut Formatter) -> fmt::Result { + if !generics.is_empty() { + write!(fmt, "<")?; + + for (i, ty) in generics.iter().enumerate() { + if i != 0 { + write!(fmt, ", ")? + } + ty.fmt(fmt)?; + } + + write!(fmt, ">")?; + } + + Ok(()) + } + } + + impl<'a> From<&'a str> for Type { + fn from(src: &'a str) -> Self { + Type::new(src) + } + } + + impl From for Type { + fn from(src: String) -> Self { + Type { + name: src, + generics: vec![], + } + } + } + + impl<'a> From<&'a String> for Type { + fn from(src: &'a String) -> Self { + Type::new(src) + } + } + + impl<'a> From<&'a Type> for Type { + fn from(src: &'a Type) -> Self { + src.clone() + } +} diff --git a/src/type_def.rs b/src/type_def.rs new file mode 100644 index 0000000..c196cd1 --- /dev/null +++ b/src/type_def.rs @@ -0,0 +1,146 @@ +use std::fmt::{self, Write}; + +use bound::Bound; +use docs::Docs; +use formatter::{Formatter, fmt_bounds}; + +use r#type::Type; + + +/// Defines a type definition. +#[derive(Debug, Clone)] +pub struct TypeDef { + pub ty: Type, + vis: Option, + docs: Option, + derive: Vec, + allow: Option, + repr: Option, + bounds: Vec, + macros: Vec, +} + + +impl TypeDef { + /// Return a structure definition with the provided name + pub fn new(name: &str) -> Self { + TypeDef { + ty: Type::new(name), + vis: None, + docs: None, + derive: vec![], + allow: None, + repr: None, + bounds: vec![], + macros: vec![], + } + } + + pub fn vis(&mut self, vis: &str) { + self.vis = Some(vis.to_string()); + } + + pub fn bound(&mut self, name: &str, ty: T) + where + T: Into, + { + self.bounds.push(Bound { + name: name.to_string(), + bound: vec![ty.into()], + }); + } + + pub fn r#macro(&mut self, r#macro: &str) { + self.macros.push(r#macro.to_string()); + } + + pub fn doc(&mut self, docs: &str) { + self.docs = Some(Docs::new(docs)); + } + + pub fn derive(&mut self, name: &str) { + self.derive.push(name.to_string()); + } + + pub fn allow(&mut self, allow: &str) { + self.allow = Some(allow.to_string()); + } + + pub fn repr(&mut self, repr: &str) { + self.repr = Some(repr.to_string()); + } + + pub fn fmt_head(&self, keyword: &str, parents: &[Type], fmt: &mut Formatter) -> fmt::Result { + if let Some(ref docs) = self.docs { + docs.fmt(fmt)?; + } + + self.fmt_allow(fmt)?; + self.fmt_derive(fmt)?; + self.fmt_repr(fmt)?; + self.fmt_macros(fmt)?; + + if let Some(ref vis) = self.vis { + write!(fmt, "{} ", vis)?; + } + + write!(fmt, "{} ", keyword)?; + self.ty.fmt(fmt)?; + + if !parents.is_empty() { + for (i, ty) in parents.iter().enumerate() { + if i == 0 { + write!(fmt, ": ")?; + } else { + write!(fmt, " + ")?; + } + + ty.fmt(fmt)?; + } + } + + fmt_bounds(&self.bounds, fmt)?; + + Ok(()) + } + + fn fmt_allow(&self, fmt: &mut Formatter) -> fmt::Result { + if let Some(ref allow) = self.allow { + write!(fmt, "#[allow({})]\n", allow)?; + } + + Ok(()) + } + + fn fmt_repr(&self, fmt: &mut Formatter) -> fmt::Result { + if let Some(ref repr) = self.repr { + write!(fmt, "#[repr({})]\n", repr)?; + } + + Ok(()) + } + + fn fmt_derive(&self, fmt: &mut Formatter) -> fmt::Result { + if !self.derive.is_empty() { + write!(fmt, "#[derive(")?; + + for (i, name) in self.derive.iter().enumerate() { + if i != 0 { + write!(fmt, ", ")? + } + write!(fmt, "{}", name)?; + } + + write!(fmt, ")]\n")?; + } + + Ok(()) + } + + fn fmt_macros(&self, fmt: &mut Formatter) -> fmt::Result { + for m in self.macros.iter() { + write!(fmt, "{}\n", m)?; + } + Ok(()) + } +} diff --git a/src/variant.rs b/src/variant.rs new file mode 100644 index 0000000..b522a55 --- /dev/null +++ b/src/variant.rs @@ -0,0 +1,49 @@ +use std::fmt::{self, Write}; + +use fields::Fields; +use formatter::Formatter; + +use r#type::Type; + + +/// Defines an enum variant. +#[derive(Debug, Clone)] +pub struct Variant { + name: String, + fields: Fields, +} + + +impl Variant { + /// Return a new enum variant with the given name. + pub fn new(name: &str) -> Self { + Variant { + name: name.to_string(), + fields: Fields::Empty, + } + } + + /// Add a named field to the variant. + pub fn named(&mut self, name: &str, ty: T) -> &mut Self + where + T: Into, + { + self.fields.named(name, ty); + self + } + + /// Add a tuple field to the variant. + pub fn tuple(&mut self, ty: &str) -> &mut Self { + self.fields.tuple(ty); + self + } + + /// Formats the variant using the given formatter. + pub fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, "{}", self.name)?; + self.fields.fmt(fmt)?; + write!(fmt, ",\n")?; + + Ok(()) + } +} From 545a7374d718b375bf2d9e7a9c6614cc811d7cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s-Combarro=20=27piranna?= Date: Wed, 3 Jun 2020 00:33:10 +0200 Subject: [PATCH 2/4] Move common methods for Trait, Struct and Enum in common abstract Traits --- src/enum.rs | 61 +++++++--------------------------------- src/lib.rs | 2 +- src/struct.rs | 70 +++++++++++++++++---------------------------- src/trait.rs | 78 ++++++++++++++++++++++++++++++--------------------- 4 files changed, 82 insertions(+), 129 deletions(-) diff --git a/src/enum.rs b/src/enum.rs index 6e08906..f0f77d6 100644 --- a/src/enum.rs +++ b/src/enum.rs @@ -4,7 +4,8 @@ use formatter::Formatter; use type_def::TypeDef; use variant::Variant; -use r#type::Type; +use r#trait::AbsTrait; +use r#struct::AbsStruct; /// Defines an enumeration. @@ -15,6 +16,14 @@ pub struct Enum { } +impl AbsTrait for Enum{ + fn type_def(&mut self) -> &mut TypeDef { + &mut self.type_def + } +} +impl AbsStruct for Enum{} + + impl Enum { /// Return a enum definition with the provided name. pub fn new(name: &str) -> Self { @@ -24,56 +33,6 @@ impl Enum { } } - /// Returns a reference to the type. - pub fn ty(&self) -> &Type { - &self.type_def.ty - } - - /// Set the enum visibility. - pub fn vis(&mut self, vis: &str) -> &mut Self { - self.type_def.vis(vis); - self - } - - /// Add a generic to the enum. - pub fn generic(&mut self, name: &str) -> &mut Self { - self.type_def.ty.generic(name); - self - } - - /// Add a `where` bound to the enum. - pub fn bound(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.type_def.bound(name, ty); - self - } - - /// Set the enum documentation. - pub fn doc(&mut self, docs: &str) -> &mut Self { - self.type_def.doc(docs); - self - } - - /// Add a new type that the struct should derive. - pub fn derive(&mut self, name: &str) -> &mut Self { - self.type_def.derive(name); - self - } - - /// Specify lint attribute to supress a warning or error. - pub fn allow(&mut self, allow: &str) -> &mut Self { - self.type_def.allow(allow); - self - } - - /// Specify representation. - pub fn repr(&mut self, repr: &str) -> &mut Self { - self.type_def.repr(repr); - self - } - /// Push a variant to the enum, returning a mutable reference to it. pub fn new_variant(&mut self, name: &str) -> &mut Variant { self.push_variant(Variant::new(name)); diff --git a/src/lib.rs b/src/lib.rs index b722f4b..ef6f8e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ //! For example: //! //! ```rust -//! use codegen::Scope; +//! use codegen::{AbsStruct, Scope}; //! //! let mut scope = Scope::new(); //! diff --git a/src/struct.rs b/src/struct.rs index ea50916..75d113c 100644 --- a/src/struct.rs +++ b/src/struct.rs @@ -5,6 +5,7 @@ use fields::Fields; use formatter::Formatter; use type_def::TypeDef; +use r#trait::AbsTrait; use r#type::Type; @@ -18,63 +19,42 @@ pub struct Struct { } -impl Struct { - /// Return a structure definition with the provided name - pub fn new(name: &str) -> Self { - Struct { - type_def: TypeDef::new(name), - fields: Fields::Empty, - } - } - - /// Returns a reference to the type - pub fn ty(&self) -> &Type { - &self.type_def.ty - } - - /// Set the structure visibility. - pub fn vis(&mut self, vis: &str) -> &mut Self { - self.type_def.vis(vis); - self - } - - /// Add a generic to the struct. - pub fn generic(&mut self, name: &str) -> &mut Self { - self.type_def.ty.generic(name); +/// AbsStruct +pub trait AbsStruct : AbsTrait { + /// Specify lint attribute to supress a warning or error. + fn allow(&mut self, allow: &str) -> &mut Self { + self.type_def().allow(allow); self } - /// Add a `where` bound to the struct. - pub fn bound(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.type_def.bound(name, ty); + /// Add a new type that the struct should derive. + fn derive(&mut self, name: &str) -> &mut Self { + self.type_def().derive(name); self } - /// Set the structure documentation. - pub fn doc(&mut self, docs: &str) -> &mut Self { - self.type_def.doc(docs); + /// Specify representation. + fn repr(&mut self, repr: &str) -> &mut Self { + self.type_def().repr(repr); self } +} - /// Add a new type that the struct should derive. - pub fn derive(&mut self, name: &str) -> &mut Self { - self.type_def.derive(name); - self - } - /// Specify lint attribute to supress a warning or error. - pub fn allow(&mut self, allow: &str) -> &mut Self { - self.type_def.allow(allow); - self +impl AbsTrait for Struct{ + fn type_def(&mut self) -> &mut TypeDef { + &mut self.type_def } +} +impl AbsStruct for Struct{} - /// Specify representation. - pub fn repr(&mut self, repr: &str) -> &mut Self { - self.type_def.repr(repr); - self +impl Struct { + /// Return a structure definition with the provided name + pub fn new(name: &str) -> Self { + Struct { + type_def: TypeDef::new(name), + fields: Fields::Empty, + } } /// Push a named field to the struct. diff --git a/src/trait.rs b/src/trait.rs index 1a100b1..55ce2c8 100644 --- a/src/trait.rs +++ b/src/trait.rs @@ -20,43 +20,63 @@ pub struct Trait { } -impl Trait { - /// Return a trait definition with the provided name - pub fn new(name: &str) -> Self { - Trait { - type_def: TypeDef::new(name), - parents: vec![], - associated_tys: vec![], - fns: vec![], - macros: vec![], - } - } +/// AbsTrait +pub trait AbsTrait { + /// Get type_def instance. + fn type_def(&mut self) -> &mut TypeDef; - /// Returns a reference to the type - pub fn ty(&self) -> &Type { - &self.type_def.ty + /// Add a `where` bound. + fn bound(&mut self, name: &str, ty: T) -> &mut Self + where + T: Into, + { + self.type_def().bound(name, ty); + self } - /// Set the trait visibility. - pub fn vis(&mut self, vis: &str) -> &mut Self { - self.type_def.vis(vis); + /// Set the documentation. + fn doc(&mut self, docs: &str) -> &mut Self { + self.type_def().doc(docs); self } - /// Add a generic to the trait - pub fn generic(&mut self, name: &str) -> &mut Self { - self.type_def.ty.generic(name); + /// Add a generic. + fn generic(&mut self, name: &str) -> &mut Self { + self.type_def().ty.generic(name); self } - /// Add a `where` bound to the trait. - pub fn bound(&mut self, name: &str, ty: T) -> &mut Self - where - T: Into, - { - self.type_def.bound(name, ty); + /// Returns a reference to the type + fn ty(&mut self) -> &Type { + &self.type_def().ty + } + + /// Set the visibility. + fn vis(&mut self, vis: &str) -> &mut Self { + self.type_def().vis(vis); self } +} + + +impl AbsTrait for Trait +{ + fn type_def(&mut self) -> &mut TypeDef { + &mut self.type_def + } +} + +impl Trait { + /// Return a trait definition with the provided name + pub fn new(name: &str) -> Self { + Trait { + type_def: TypeDef::new(name), + parents: vec![], + associated_tys: vec![], + fns: vec![], + macros: vec![], + } + } /// Add a macro to the trait def (e.g. `"#[async_trait]"`) pub fn r#macro(&mut self, r#macro: &str) -> &mut Self { @@ -73,12 +93,6 @@ impl Trait { self } - /// Set the trait documentation. - pub fn doc(&mut self, docs: &str) -> &mut Self { - self.type_def.doc(docs); - self - } - /// Add an associated type. Returns a mutable reference to the new /// associated type for futher configuration. pub fn associated_type(&mut self, name: &str) -> &mut AssociatedType { From 4bf9eb6bdb54ecb1b2cfc6387840867fdb125b52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s-Combarro=20=27piranna?= Date: Wed, 3 Jun 2020 00:33:23 +0200 Subject: [PATCH 3/4] Fixed indenting --- src/type.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/type.rs b/src/type.rs index 61c4637..79469f7 100644 --- a/src/type.rs +++ b/src/type.rs @@ -74,30 +74,30 @@ impl Type { Ok(()) } - } +} - impl<'a> From<&'a str> for Type { +impl<'a> From<&'a str> for Type { fn from(src: &'a str) -> Self { Type::new(src) } - } +} - impl From for Type { +impl From for Type { fn from(src: String) -> Self { Type { name: src, generics: vec![], } } - } +} - impl<'a> From<&'a String> for Type { +impl<'a> From<&'a String> for Type { fn from(src: &'a String) -> Self { Type::new(src) } - } +} - impl<'a> From<&'a Type> for Type { +impl<'a> From<&'a Type> for Type { fn from(src: &'a Type) -> Self { src.clone() } From de1d76a4e5d28d662f2e9f6bc5fa244b253b5f54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Legan=C3=A9s-Combarro=20=27piranna?= Date: Wed, 3 Jun 2020 01:10:05 +0200 Subject: [PATCH 4/4] Re-use `fmt.block()` code & made `fmt.indent()` private --- src/block.rs | 11 +---------- src/formatter.rs | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/block.rs b/src/block.rs index 57d720e..45e0593 100644 --- a/src/block.rs +++ b/src/block.rs @@ -51,14 +51,7 @@ impl Block { } // Inlined `Formatter::fmt` - - if !fmt.is_start_of_line() { - write!(fmt, " ")?; - } - - write!(fmt, "{{\n")?; - - fmt.indent(|fmt| { + fmt.block(|fmt| { for b in &self.body { b.fmt(fmt)?; } @@ -66,8 +59,6 @@ impl Block { Ok(()) })?; - write!(fmt, "}}")?; - if let Some(ref after) = self.after { write!(fmt, "{}", after)?; } diff --git a/src/formatter.rs b/src/formatter.rs index aa06354..adda808 100644 --- a/src/formatter.rs +++ b/src/formatter.rs @@ -48,7 +48,7 @@ impl<'a> Formatter<'a> { } /// Call the given function with the indentation level incremented by one. - pub fn indent(&mut self, f: F) -> R + fn indent(&mut self, f: F) -> R where F: FnOnce(&mut Self) -> R, {