diff --git a/src/enum.rs b/src/enum.rs index 2636f62..b1a0d48 100644 --- a/src/enum.rs +++ b/src/enum.rs @@ -1,99 +1,105 @@ -use std::fmt; - -use crate::formatter::Formatter; -use crate::type_def::TypeDef; -use crate::variant::Variant; - -use crate::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(()) - }) - } -} +use std::fmt; + +use crate::formatter::Formatter; +use crate::type_def::TypeDef; +use crate::variant::Variant; + +use crate::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 + } + + /// Add an arbitrary macro. + pub fn r#macro(&mut self, r#macro: &str) -> &mut Self { + self.type_def.r#macro(r#macro); + 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/lib.rs b/src/lib.rs index 70b8675..09df21c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,65 +1,67 @@ -#![deny(missing_debug_implementations, missing_docs)] -#![doc(html_root_url = "https://docs.rs/codegen/0.1.1")] -#![warn(rust_2018_idioms)] - -//! Provides a builder API for generating Rust code. -//! -//! The general strategy for using the crate is as follows: -//! -//! 1. Create a `Scope` instance. -//! 2. Use the builder API to add elements to the scope. -//! 3. Call `Scope::to_string()` to get the generated code. -//! -//! For example: -//! -//! ```rust -//! use codegen::Scope; -//! -//! let mut scope = Scope::new(); -//! -//! scope.new_struct("Foo") -//! .derive("Debug") -//! .field("one", "usize") -//! .field("two", "String"); -//! -//! println!("{}", scope.to_string()); -//! ``` - -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::*; +#![deny(missing_debug_implementations)] +//#![deny(missing_debug_implementations, missing_docs)] +#![doc(html_root_url = "https://docs.rs/codegen/0.1.1")] +#![warn(rust_2018_idioms)] + +//! Provides a builder API for generating Rust code. +//! +//! The general strategy for using the crate is as follows: +//! +//! 1. Create a `Scope` instance. +//! 2. Use the builder API to add elements to the scope. +//! 3. Call `Scope::to_string()` to get the generated code. +//! +//! For example: +//! +//! ```rust +//! use codegen::Scope; +//! +//! let mut scope = Scope::new(); +//! +//! scope.new_struct("Foo") +//! .derive("Debug") +//! .field("one", "usize") +//! .field("two", "String"); +//! +//! println!("{}", scope.to_string()); +//! ``` + +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 item::*; +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 index 4846a61..038758f 100644 --- a/src/module.rs +++ b/src/module.rs @@ -1,174 +1,188 @@ -use std::fmt::{self, Write}; - -use crate::docs::Docs; -use crate::formatter::Formatter; -use crate::function::Function; -use crate::scope::Scope; - -use crate::r#enum::Enum; -use crate::r#impl::Impl; -use crate::r#struct::Struct; -use crate::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)) - } -} +use std::fmt::{self, Write}; + +use crate::docs::Docs; +use crate::formatter::Formatter; +use crate::function::Function; +use crate::scope::Scope; + +use crate::r#enum::Enum; +use crate::r#impl::Impl; +use crate::r#struct::Struct; +use crate::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, + + /// Allows for the module + allow: Vec, +} + +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(), + allow: Vec::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 + } + + /// Add an allow annotation to the module. + pub fn allow(&mut self, allow: &str) -> &mut Self { + self.allow.push(allow.to_string()); + 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 { + for allow in &self.allow { + write!(fmt, "#[allow({})]\n", allow)?; + } + + 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 index 1312139..776f139 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -1,317 +1,317 @@ -use std::fmt::{self, Write}; - -use indexmap::IndexMap; - -use crate::docs::Docs; -use crate::formatter::Formatter; -use crate::function::Function; -use crate::import::Import; -use crate::item::Item; -use crate::module::Module; - -use crate::r#enum::Enum; -use crate::r#impl::Impl; -use crate::r#struct::Struct; -use crate::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(()) - } -} +use std::fmt::{self, Write}; + +use indexmap::IndexMap; + +use crate::docs::Docs; +use crate::formatter::Formatter; +use crate::function::Function; +use crate::import::Import; +use crate::item::Item; +use crate::module::Module; + +use crate::r#enum::Enum; +use crate::r#impl::Impl; +use crate::r#struct::Struct; +use crate::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 index 8feae8a..9600142 100644 --- a/src/struct.rs +++ b/src/struct.rs @@ -1,128 +1,134 @@ -use std::fmt::{self, Write}; - -use crate::field::Field; -use crate::fields::Fields; -use crate::formatter::Formatter; -use crate::type_def::TypeDef; - -use crate::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(()) - } -} +use std::fmt::{self, Write}; + +use crate::field::Field; +use crate::fields::Fields; +use crate::formatter::Formatter; +use crate::type_def::TypeDef; + +use crate::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 + } + + /// Add an arbitrary macro. + pub fn r#macro(&mut self, r#macro: &str) -> &mut Self { + self.type_def.r#macro(r#macro); + 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/type_def.rs b/src/type_def.rs index be82737..97524ce 100644 --- a/src/type_def.rs +++ b/src/type_def.rs @@ -1,149 +1,149 @@ -use std::fmt::{self, Write}; - -use crate::bound::Bound; -use crate::docs::Docs; -use crate::formatter::{fmt_bounds, Formatter}; - -use crate::r#type::Type; - -/// Defines a type definition. -#[derive(Debug, Clone)] -pub struct TypeDef { - pub ty: Type, - vis: Option, - docs: Option, - derive: Vec, - allow: Vec, - 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: vec![], - 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.push(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 { - for allow in &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(()) - } -} +use std::fmt::{self, Write}; + +use crate::bound::Bound; +use crate::docs::Docs; +use crate::formatter::{fmt_bounds, Formatter}; + +use crate::r#type::Type; + +/// Defines a type definition. +#[derive(Debug, Clone)] +pub struct TypeDef { + pub ty: Type, + vis: Option, + docs: Option, + derive: Vec, + allow: Vec, + 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: vec![], + 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.push(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 { + for allow in &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 index 164f2e4..e36dee4 100644 --- a/src/variant.rs +++ b/src/variant.rs @@ -1,47 +1,59 @@ -use std::fmt::{self, Write}; - -use crate::fields::Fields; -use crate::formatter::Formatter; - -use crate::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(()) - } -} +use std::fmt::{self, Write}; + +use crate::fields::Fields; +use crate::formatter::Formatter; + +use crate::r#type::Type; + +/// Defines an enum variant. +#[derive(Debug, Clone)] +pub struct Variant { + name: String, + fields: Fields, + annotations: Vec, +} + +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, + annotations: Vec::new(), + } + } + + /// 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 + } + + /// Add an anotation to the variant. + pub fn annotation(&mut self, annotation: &str) -> &mut Self { + self.annotations.push(annotation.to_string()); + self + } + + /// Formats the variant using the given formatter. + pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + for a in &self.annotations { + write!(fmt, "{}", a)?; + write!(fmt, "\n")?; + } + write!(fmt, "{}", self.name)?; + self.fields.fmt(fmt)?; + write!(fmt, ",\n")?; + + Ok(()) + } +}