├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── src ├── associated_type.rs ├── block.rs ├── body.rs ├── bound.rs ├── docs.rs ├── enum.rs ├── field.rs ├── fields.rs ├── formatter.rs ├── function.rs ├── impl.rs ├── import.rs ├── item.rs ├── lib.rs ├── module.rs ├── scope.rs ├── struct.rs ├── trait.rs ├── type.rs ├── type_def.rs └── variant.rs └── tests └── codegen.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: rust 3 | sudo: false 4 | 5 | rust: 6 | - stable 7 | 8 | before_script: 9 | - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH 10 | 11 | script: 12 | - cargo build 13 | - cargo test 14 | - cargo doc --no-deps 15 | 16 | after_success: 17 | - travis-cargo doc-upload 18 | 19 | notifications: 20 | email: 21 | on_success: never 22 | env: 23 | global: 24 | secure: l9a5EV2xm2N4oAph7HrcroFvO/zQdynyNV2phFmqUPLt7WIXq08pJLxcP7VXhwVoAi2pyM2jTTdyVEDclJQal7HQSfuAzboDMJWiX31+dfsdZBVLCkTD8Lk/elLWPigngDz5iqtYf1L8aAHHWpaM2qitSO+BaNLGRMkF48dz+Qu6Ly+9ygRf8XBUrXznZ6hWdKLF/9ULurLyMz/EtvhNRaJxd0Z3Og4Cw5izPw1ozYtvaAZIZg+BgrHx0gdGBNPjDnyeNimwU8wsi/fATH0aYcp9ybBXqD3UjLEXfBj5x0WX+Sp4cCZ5icazAqPrKWVHGz4sp25r8l7Pz2gr74oGtjBT6b5KufFW/Oj+zzx8MaxCFEJ8s8tbt8Kqe8iwjaT39aoIoXQ3jRHJhDgJBT1cImDlH1P59rOWkU787fOu9vEnVD303jIPsZQdmo+n6trrhznd06zT/nmrMrshA+TtLSDPjoVPVRCtoc758TuZBMJeYNdo4FF08tGFHdEpFnnzgltYErAaw5b5hFGTzyBegjTjxWW02Pjtt+eLf2EZafUKcnQqKgBFD7hgPbCEdqtZT96v5TgjOen+MphbKTuhhcodrQde8nIzYWWfwDjlXRP+sJ4e6gOzz20+8hpxeewv6fqjS2u9wveC+NyuEcC2CU0p66W62M62REEWseEI42I= 25 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 2 | 3 | ### Changed 4 | - updated the crate to rust 2018 edition 5 | 6 | # 0.1.3 (May 9, 2020) 7 | 8 | ### Added 9 | - Add support to define function attributes and extern functions 10 | - Add support to define async functions 11 | - Add support to add macros to traits and impls 12 | 13 | # 0.1.2 (May 9, 2020) 14 | 15 | ### Added 16 | - Add ability to add functions directly to scope 17 | - Add documentation comments and annotations to struct fields 18 | 19 | # 0.1.1 (March 15, 2019) 20 | 21 | ### Added 22 | - Specifying lint attributes (#13) 23 | - Specifying repr attribute on struct and enum (#12) 24 | 25 | # 0.1.0 (November 10, 2018) 26 | 27 | Initial release 28 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "codegen" 3 | # When releasing to crates.io: 4 | # - Update html_root_url. 5 | # - Update CHANGELOG.md. 6 | # - Update doc URL. 7 | # - Create "v0.1.x" git tag. 8 | version = "0.1.3" 9 | license = "MIT" 10 | authors = ["Carl Lerche "] 11 | description = "Library for generating Rust code" 12 | documentation = "https://docs.rs/codegen/0.1.3/codegen" 13 | homepage = "https://github.com/carllerche/codegen" 14 | repository = "https://github.com/carllerche/codegen" 15 | readme = "README.md" 16 | edition = "2018" 17 | 18 | [dependencies] 19 | indexmap = "1.0.2" 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Carl Lerche 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Codegen 2 | 3 | Provides an builder API to assist in generating Rust code. 4 | 5 | [![Build Status](https://travis-ci.org/carllerche/codegen.svg?branch=master)](https://travis-ci.org/carllerche/codegen) 6 | 7 | More information about this crate can be found in the [crate documentation][dox] 8 | 9 | [dox]: https://docs.rs/codegen/0.1.3/codegen/ 10 | 11 | ## Installation 12 | 13 | To use `codegen`, first add this to your `Cargo.toml`: 14 | 15 | ```toml 16 | [dependencies] 17 | codegen = "0.1.3" 18 | ``` 19 | 20 | Next, add this to your crate: 21 | 22 | ```rust 23 | extern crate codegen; 24 | ``` 25 | 26 | ## Usage 27 | 28 | 1) Create a `Scope` instance. 29 | 2) Use the builder API to add elements to the scope. 30 | 3) Call `Scope::to_string()` to get the generated code. 31 | 32 | For example: 33 | 34 | ```rust 35 | use codegen::Scope; 36 | 37 | let mut scope = Scope::new(); 38 | 39 | scope.new_struct("Foo") 40 | .derive("Debug") 41 | .field("one", "usize") 42 | .field("two", "String"); 43 | 44 | println!("{}", scope.to_string()); 45 | ``` 46 | 47 | ## Non-goals 48 | 49 | `codegen` will not attempt to perform anything beyond basic formatting. For 50 | improved formatting, the generated code can be passed to `rustfmt`. 51 | 52 | ## License 53 | 54 | This project is licensed under the [MIT license](LICENSE). 55 | 56 | ### Contribution 57 | 58 | Unless you explicitly state otherwise, any contribution intentionally submitted 59 | for inclusion in `codegen` by you, shall be licensed as MIT, without any 60 | additional terms or conditions. 61 | -------------------------------------------------------------------------------- /src/associated_type.rs: -------------------------------------------------------------------------------- 1 | use crate::bound::Bound; 2 | use crate::r#type::Type; 3 | 4 | /// Defines an associated type. 5 | #[derive(Debug, Clone)] 6 | pub struct AssociatedType(pub Bound); 7 | 8 | impl AssociatedType { 9 | /// Add a bound to the associated type. 10 | pub fn bound(&mut self, ty: T) -> &mut Self 11 | where 12 | T: Into, 13 | { 14 | self.0.bound.push(ty.into()); 15 | self 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/block.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::body::Body; 4 | use crate::formatter::Formatter; 5 | 6 | /// Defines a code block. This is used to define a function body. 7 | #[derive(Debug, Clone)] 8 | pub struct Block { 9 | before: Option, 10 | after: Option, 11 | body: Vec, 12 | } 13 | 14 | impl Block { 15 | /// Returns an empty code block. 16 | pub fn new(before: &str) -> Self { 17 | Block { 18 | before: Some(before.to_string()), 19 | after: None, 20 | body: vec![], 21 | } 22 | } 23 | 24 | /// Push a line to the code block. 25 | pub fn line(&mut self, line: T) -> &mut Self 26 | where 27 | T: ToString, 28 | { 29 | self.body.push(Body::String(line.to_string())); 30 | self 31 | } 32 | 33 | /// Push a nested block to this block. 34 | pub fn push_block(&mut self, block: Block) -> &mut Self { 35 | self.body.push(Body::Block(block)); 36 | self 37 | } 38 | 39 | /// Add a snippet after the block. 40 | pub fn after(&mut self, after: &str) -> &mut Self { 41 | self.after = Some(after.to_string()); 42 | self 43 | } 44 | 45 | /// Formats the block using the given formatter. 46 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 47 | if let Some(ref before) = self.before { 48 | write!(fmt, "{}", before)?; 49 | } 50 | 51 | // Inlined `Formatter::fmt` 52 | 53 | if !fmt.is_start_of_line() { 54 | write!(fmt, " ")?; 55 | } 56 | 57 | write!(fmt, "{{\n")?; 58 | 59 | fmt.indent(|fmt| { 60 | for b in &self.body { 61 | b.fmt(fmt)?; 62 | } 63 | 64 | Ok(()) 65 | })?; 66 | 67 | write!(fmt, "}}")?; 68 | 69 | if let Some(ref after) = self.after { 70 | write!(fmt, "{}", after)?; 71 | } 72 | 73 | write!(fmt, "\n")?; 74 | Ok(()) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/body.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::block::Block; 4 | use crate::formatter::Formatter; 5 | 6 | #[derive(Debug, Clone)] 7 | pub enum Body { 8 | String(String), 9 | Block(Block), 10 | } 11 | 12 | impl Body { 13 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 14 | match &self { 15 | Body::String(s) => write!(fmt, "{}\n", s), 16 | Body::Block(b) => b.fmt(fmt), 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/bound.rs: -------------------------------------------------------------------------------- 1 | use crate::r#type::Type; 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct Bound { 5 | pub name: String, 6 | pub bound: Vec, 7 | } 8 | -------------------------------------------------------------------------------- /src/docs.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::formatter::Formatter; 4 | 5 | #[derive(Debug, Clone)] 6 | pub struct Docs { 7 | docs: String, 8 | } 9 | 10 | impl Docs { 11 | pub fn new(docs: &str) -> Self { 12 | Docs { 13 | docs: docs.to_string(), 14 | } 15 | } 16 | 17 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 18 | for line in self.docs.lines() { 19 | write!(fmt, "/// {}\n", line)?; 20 | } 21 | 22 | Ok(()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/enum.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use crate::formatter::Formatter; 4 | use crate::type_def::TypeDef; 5 | use crate::variant::Variant; 6 | 7 | use crate::r#type::Type; 8 | 9 | /// Defines an enumeration. 10 | #[derive(Debug, Clone)] 11 | pub struct Enum { 12 | type_def: TypeDef, 13 | variants: Vec, 14 | } 15 | 16 | impl Enum { 17 | /// Return a enum definition with the provided name. 18 | pub fn new(name: &str) -> Self { 19 | Enum { 20 | type_def: TypeDef::new(name), 21 | variants: vec![], 22 | } 23 | } 24 | 25 | /// Returns a reference to the type. 26 | pub fn ty(&self) -> &Type { 27 | &self.type_def.ty 28 | } 29 | 30 | /// Set the enum visibility. 31 | pub fn vis(&mut self, vis: &str) -> &mut Self { 32 | self.type_def.vis(vis); 33 | self 34 | } 35 | 36 | /// Add a generic to the enum. 37 | pub fn generic(&mut self, name: &str) -> &mut Self { 38 | self.type_def.ty.generic(name); 39 | self 40 | } 41 | 42 | /// Add a `where` bound to the enum. 43 | pub fn bound(&mut self, name: &str, ty: T) -> &mut Self 44 | where 45 | T: Into, 46 | { 47 | self.type_def.bound(name, ty); 48 | self 49 | } 50 | 51 | /// Set the enum documentation. 52 | pub fn doc(&mut self, docs: &str) -> &mut Self { 53 | self.type_def.doc(docs); 54 | self 55 | } 56 | 57 | /// Add a new type that the struct should derive. 58 | pub fn derive(&mut self, name: &str) -> &mut Self { 59 | self.type_def.derive(name); 60 | self 61 | } 62 | 63 | /// Specify lint attribute to supress a warning or error. 64 | pub fn allow(&mut self, allow: &str) -> &mut Self { 65 | self.type_def.allow(allow); 66 | self 67 | } 68 | 69 | /// Specify representation. 70 | pub fn repr(&mut self, repr: &str) -> &mut Self { 71 | self.type_def.repr(repr); 72 | self 73 | } 74 | 75 | /// Push a variant to the enum, returning a mutable reference to it. 76 | pub fn new_variant(&mut self, name: &str) -> &mut Variant { 77 | self.push_variant(Variant::new(name)); 78 | self.variants.last_mut().unwrap() 79 | } 80 | 81 | /// Push a variant to the enum. 82 | pub fn push_variant(&mut self, item: Variant) -> &mut Self { 83 | self.variants.push(item); 84 | self 85 | } 86 | 87 | /// Formats the enum using the given formatter. 88 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 89 | self.type_def.fmt_head("enum", &[], fmt)?; 90 | 91 | fmt.block(|fmt| { 92 | for variant in &self.variants { 93 | variant.fmt(fmt)?; 94 | } 95 | 96 | Ok(()) 97 | }) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/field.rs: -------------------------------------------------------------------------------- 1 | use crate::r#type::Type; 2 | 3 | /// Defines a struct field. 4 | #[derive(Debug, Clone)] 5 | pub struct Field { 6 | /// Field name 7 | pub name: String, 8 | 9 | /// Field type 10 | pub ty: Type, 11 | 12 | /// Field documentation 13 | pub documentation: Vec, 14 | 15 | /// Field annotation 16 | pub annotation: Vec, 17 | } 18 | 19 | impl Field { 20 | /// Return a field definition with the provided name and type 21 | pub fn new(name: &str, ty: T) -> Self 22 | where 23 | T: Into, 24 | { 25 | Field { 26 | name: name.into(), 27 | ty: ty.into(), 28 | documentation: Vec::new(), 29 | annotation: Vec::new(), 30 | } 31 | } 32 | 33 | /// Set field's documentation. 34 | pub fn doc(&mut self, documentation: Vec<&str>) -> &mut Self { 35 | self.documentation = documentation.iter().map(|doc| doc.to_string()).collect(); 36 | self 37 | } 38 | 39 | /// Set field's annotation. 40 | pub fn annotation(&mut self, annotation: Vec<&str>) -> &mut Self { 41 | self.annotation = annotation.iter().map(|ann| ann.to_string()).collect(); 42 | self 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/fields.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::field::Field; 4 | use crate::formatter::Formatter; 5 | 6 | use crate::r#type::Type; 7 | 8 | /// Defines a set of fields. 9 | #[derive(Debug, Clone)] 10 | pub enum Fields { 11 | Empty, 12 | Tuple(Vec), 13 | Named(Vec), 14 | } 15 | 16 | impl Fields { 17 | pub fn push_named(&mut self, field: Field) -> &mut Self { 18 | match *self { 19 | Fields::Empty => { 20 | *self = Fields::Named(vec![field]); 21 | } 22 | Fields::Named(ref mut fields) => { 23 | fields.push(field); 24 | } 25 | _ => panic!("field list is named"), 26 | } 27 | 28 | self 29 | } 30 | 31 | pub fn named(&mut self, name: &str, ty: T) -> &mut Self 32 | where 33 | T: Into, 34 | { 35 | self.push_named(Field { 36 | name: name.to_string(), 37 | ty: ty.into(), 38 | documentation: Vec::new(), 39 | annotation: Vec::new(), 40 | }) 41 | } 42 | 43 | pub fn tuple(&mut self, ty: T) -> &mut Self 44 | where 45 | T: Into, 46 | { 47 | match *self { 48 | Fields::Empty => { 49 | *self = Fields::Tuple(vec![ty.into()]); 50 | } 51 | Fields::Tuple(ref mut fields) => { 52 | fields.push(ty.into()); 53 | } 54 | _ => panic!("field list is tuple"), 55 | } 56 | 57 | self 58 | } 59 | 60 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 61 | match *self { 62 | Fields::Named(ref fields) => { 63 | assert!(!fields.is_empty()); 64 | 65 | fmt.block(|fmt| { 66 | for f in fields { 67 | if !f.documentation.is_empty() { 68 | for doc in &f.documentation { 69 | write!(fmt, "/// {}\n", doc)?; 70 | } 71 | } 72 | if !f.annotation.is_empty() { 73 | for ann in &f.annotation { 74 | write!(fmt, "{}\n", ann)?; 75 | } 76 | } 77 | write!(fmt, "{}: ", f.name)?; 78 | f.ty.fmt(fmt)?; 79 | write!(fmt, ",\n")?; 80 | } 81 | 82 | Ok(()) 83 | })?; 84 | } 85 | Fields::Tuple(ref tys) => { 86 | assert!(!tys.is_empty()); 87 | 88 | write!(fmt, "(")?; 89 | 90 | for (i, ty) in tys.iter().enumerate() { 91 | if i != 0 { 92 | write!(fmt, ", ")?; 93 | } 94 | ty.fmt(fmt)?; 95 | } 96 | 97 | write!(fmt, ")")?; 98 | } 99 | Fields::Empty => {} 100 | } 101 | 102 | Ok(()) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/formatter.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::bound::Bound; 4 | 5 | use crate::r#type::Type; 6 | 7 | const DEFAULT_INDENT: usize = 4; 8 | 9 | /// Configures how a scope is formatted. 10 | #[derive(Debug)] 11 | pub struct Formatter<'a> { 12 | /// Write destination 13 | dst: &'a mut String, 14 | 15 | /// Number of spaces to start a new line with. 16 | spaces: usize, 17 | 18 | /// Number of spaces per indentiation 19 | indent: usize, 20 | } 21 | 22 | impl<'a> Formatter<'a> { 23 | /// Return a new formatter that writes to the given string. 24 | pub fn new(dst: &'a mut String) -> Self { 25 | Formatter { 26 | dst, 27 | spaces: 0, 28 | indent: DEFAULT_INDENT, 29 | } 30 | } 31 | 32 | /// Wrap the given function inside a block. 33 | pub fn block(&mut self, f: F) -> fmt::Result 34 | where 35 | F: FnOnce(&mut Self) -> fmt::Result, 36 | { 37 | if !self.is_start_of_line() { 38 | write!(self, " ")?; 39 | } 40 | 41 | write!(self, "{{\n")?; 42 | self.indent(f)?; 43 | write!(self, "}}\n")?; 44 | Ok(()) 45 | } 46 | 47 | /// Call the given function with the indentation level incremented by one. 48 | pub fn indent(&mut self, f: F) -> R 49 | where 50 | F: FnOnce(&mut Self) -> R, 51 | { 52 | self.spaces += self.indent; 53 | let ret = f(self); 54 | self.spaces -= self.indent; 55 | ret 56 | } 57 | 58 | /// Check if current destination is the start of a new line. 59 | pub fn is_start_of_line(&self) -> bool { 60 | self.dst.is_empty() || self.dst.as_bytes().last() == Some(&b'\n') 61 | } 62 | 63 | fn push_spaces(&mut self) { 64 | for _ in 0..self.spaces { 65 | self.dst.push_str(" "); 66 | } 67 | } 68 | } 69 | 70 | impl<'a> fmt::Write for Formatter<'a> { 71 | fn write_str(&mut self, s: &str) -> fmt::Result { 72 | let mut first = true; 73 | let mut should_indent = self.is_start_of_line(); 74 | 75 | for line in s.lines() { 76 | if !first { 77 | self.dst.push_str("\n"); 78 | } 79 | 80 | first = false; 81 | 82 | let do_indent = should_indent && !line.is_empty() && line.as_bytes()[0] != b'\n'; 83 | 84 | if do_indent { 85 | self.push_spaces(); 86 | } 87 | 88 | // If this loops again, then we just wrote a new line 89 | should_indent = true; 90 | 91 | self.dst.push_str(line); 92 | } 93 | 94 | if s.as_bytes().last() == Some(&b'\n') { 95 | self.dst.push_str("\n"); 96 | } 97 | 98 | Ok(()) 99 | } 100 | } 101 | 102 | /// Format generics. 103 | pub fn fmt_generics(generics: &[String], fmt: &mut Formatter<'_>) -> fmt::Result { 104 | if !generics.is_empty() { 105 | write!(fmt, "<")?; 106 | 107 | for (i, ty) in generics.iter().enumerate() { 108 | if i != 0 { 109 | write!(fmt, ", ")? 110 | } 111 | write!(fmt, "{}", ty)?; 112 | } 113 | 114 | write!(fmt, ">")?; 115 | } 116 | 117 | Ok(()) 118 | } 119 | 120 | /// Format generic bounds. 121 | pub fn fmt_bounds(bounds: &[Bound], fmt: &mut Formatter<'_>) -> fmt::Result { 122 | if !bounds.is_empty() { 123 | write!(fmt, "\n")?; 124 | 125 | // Write first bound 126 | write!(fmt, "where {}: ", bounds[0].name)?; 127 | fmt_bound_rhs(&bounds[0].bound, fmt)?; 128 | write!(fmt, ",\n")?; 129 | 130 | for bound in &bounds[1..] { 131 | write!(fmt, " {}: ", bound.name)?; 132 | fmt_bound_rhs(&bound.bound, fmt)?; 133 | write!(fmt, ",\n")?; 134 | } 135 | } 136 | 137 | Ok(()) 138 | } 139 | 140 | /// Format multiple generic bounds. 141 | pub fn fmt_bound_rhs(tys: &[Type], fmt: &mut Formatter<'_>) -> fmt::Result { 142 | for (i, ty) in tys.iter().enumerate() { 143 | if i != 0 { 144 | write!(fmt, " + ")? 145 | } 146 | ty.fmt(fmt)?; 147 | } 148 | 149 | Ok(()) 150 | } 151 | -------------------------------------------------------------------------------- /src/function.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::block::Block; 4 | use crate::body::Body; 5 | use crate::bound::Bound; 6 | use crate::docs::Docs; 7 | use crate::field::Field; 8 | use crate::formatter::Formatter; 9 | use crate::formatter::{fmt_bounds, fmt_generics}; 10 | 11 | use crate::r#type::Type; 12 | 13 | /// Defines a function. 14 | #[derive(Debug, Clone)] 15 | pub struct Function { 16 | /// Name of the function 17 | name: String, 18 | 19 | /// Function documentation 20 | docs: Option, 21 | 22 | /// A lint attribute used to suppress a warning or error 23 | allow: Option, 24 | 25 | /// Function visibility 26 | vis: Option, 27 | 28 | /// Function generics 29 | generics: Vec, 30 | 31 | /// If the function takes `&self` or `&mut self` 32 | arg_self: Option, 33 | 34 | /// Function arguments 35 | args: Vec, 36 | 37 | /// Return type 38 | ret: Option, 39 | 40 | /// Where bounds 41 | bounds: Vec, 42 | 43 | /// Body contents 44 | pub body: Option>, 45 | 46 | /// Function attributes, e.g., `#[no_mangle]`. 47 | attributes: Vec, 48 | 49 | /// Function `extern` ABI 50 | extern_abi: Option, 51 | 52 | /// Whether or not this function is `async` or not 53 | r#async: bool, 54 | } 55 | 56 | impl Function { 57 | /// Return a new function definition. 58 | pub fn new(name: &str) -> Self { 59 | Function { 60 | name: name.to_string(), 61 | docs: None, 62 | allow: None, 63 | vis: None, 64 | generics: vec![], 65 | arg_self: None, 66 | args: vec![], 67 | ret: None, 68 | bounds: vec![], 69 | body: Some(vec![]), 70 | attributes: vec![], 71 | extern_abi: None, 72 | r#async: false, 73 | } 74 | } 75 | 76 | /// Set the function documentation. 77 | pub fn doc(&mut self, docs: &str) -> &mut Self { 78 | self.docs = Some(Docs::new(docs)); 79 | self 80 | } 81 | 82 | /// Specify lint attribute to supress a warning or error. 83 | pub fn allow(&mut self, allow: &str) -> &mut Self { 84 | self.allow = Some(allow.to_string()); 85 | self 86 | } 87 | 88 | /// Set the function visibility. 89 | pub fn vis(&mut self, vis: &str) -> &mut Self { 90 | self.vis = Some(vis.to_string()); 91 | self 92 | } 93 | 94 | /// Set whether this function is async or not 95 | pub fn set_async(&mut self, r#async: bool) -> &mut Self { 96 | self.r#async = r#async; 97 | self 98 | } 99 | 100 | /// Add a generic to the function. 101 | pub fn generic(&mut self, name: &str) -> &mut Self { 102 | self.generics.push(name.to_string()); 103 | self 104 | } 105 | 106 | /// Add `self` as a function argument. 107 | pub fn arg_self(&mut self) -> &mut Self { 108 | self.arg_self = Some("self".to_string()); 109 | self 110 | } 111 | 112 | /// Add `&self` as a function argument. 113 | pub fn arg_ref_self(&mut self) -> &mut Self { 114 | self.arg_self = Some("&self".to_string()); 115 | self 116 | } 117 | 118 | /// Add `&mut self` as a function argument. 119 | pub fn arg_mut_self(&mut self) -> &mut Self { 120 | self.arg_self = Some("&mut self".to_string()); 121 | self 122 | } 123 | 124 | /// Add a function argument. 125 | pub fn arg(&mut self, name: &str, ty: T) -> &mut Self 126 | where 127 | T: Into, 128 | { 129 | self.args.push(Field { 130 | name: name.to_string(), 131 | ty: ty.into(), 132 | // While a `Field` is used here, both `documentation` 133 | // and `annotation` does not make sense for function arguments. 134 | // Simply use empty strings. 135 | documentation: Vec::new(), 136 | annotation: Vec::new(), 137 | }); 138 | 139 | self 140 | } 141 | 142 | /// Set the function return type. 143 | pub fn ret(&mut self, ty: T) -> &mut Self 144 | where 145 | T: Into, 146 | { 147 | self.ret = Some(ty.into()); 148 | self 149 | } 150 | 151 | /// Add a `where` bound to the function. 152 | pub fn bound(&mut self, name: &str, ty: T) -> &mut Self 153 | where 154 | T: Into, 155 | { 156 | self.bounds.push(Bound { 157 | name: name.to_string(), 158 | bound: vec![ty.into()], 159 | }); 160 | self 161 | } 162 | 163 | /// Push a line to the function implementation. 164 | pub fn line(&mut self, line: T) -> &mut Self 165 | where 166 | T: ToString, 167 | { 168 | self.body 169 | .get_or_insert(vec![]) 170 | .push(Body::String(line.to_string())); 171 | 172 | self 173 | } 174 | 175 | /// Add an attribute to the function. 176 | /// 177 | /// ``` 178 | /// use codegen::Function; 179 | /// 180 | /// let mut func = Function::new("test"); 181 | /// 182 | /// // add a `#[test]` attribute 183 | /// func.attr("test"); 184 | /// ``` 185 | pub fn attr(&mut self, attribute: &str) -> &mut Self { 186 | self.attributes.push(attribute.to_string()); 187 | self 188 | } 189 | 190 | /// Specify an `extern` ABI for the function. 191 | /// ``` 192 | /// use codegen::Function; 193 | /// 194 | /// let mut extern_func = Function::new("extern_func"); 195 | /// 196 | /// // use the "C" calling convention 197 | /// extern_func.extern_abi("C"); 198 | /// ``` 199 | pub fn extern_abi(&mut self, abi: &str) -> &mut Self { 200 | self.extern_abi.replace(abi.to_string()); 201 | self 202 | } 203 | 204 | /// Push a block to the function implementation 205 | pub fn push_block(&mut self, block: Block) -> &mut Self { 206 | self.body.get_or_insert(vec![]).push(Body::Block(block)); 207 | 208 | self 209 | } 210 | 211 | /// Formats the function using the given formatter. 212 | pub fn fmt(&self, is_trait: bool, fmt: &mut Formatter<'_>) -> fmt::Result { 213 | if let Some(ref docs) = self.docs { 214 | docs.fmt(fmt)?; 215 | } 216 | 217 | if let Some(ref allow) = self.allow { 218 | write!(fmt, "#[allow({})]\n", allow)?; 219 | } 220 | 221 | for attr in self.attributes.iter() { 222 | write!(fmt, "#[{}]\n", attr)?; 223 | } 224 | 225 | if is_trait { 226 | assert!( 227 | self.vis.is_none(), 228 | "trait fns do not have visibility modifiers" 229 | ); 230 | } 231 | 232 | if let Some(ref vis) = self.vis { 233 | write!(fmt, "{} ", vis)?; 234 | } 235 | 236 | if let Some(ref extern_abi) = self.extern_abi { 237 | write!(fmt, "extern \"{extern_abi}\" ", extern_abi = extern_abi)?; 238 | } 239 | 240 | if self.r#async { 241 | write!(fmt, "async ")?; 242 | } 243 | 244 | write!(fmt, "fn {}", self.name)?; 245 | fmt_generics(&self.generics, fmt)?; 246 | 247 | write!(fmt, "(")?; 248 | 249 | if let Some(ref s) = self.arg_self { 250 | write!(fmt, "{}", s)?; 251 | } 252 | 253 | for (i, arg) in self.args.iter().enumerate() { 254 | if i != 0 || self.arg_self.is_some() { 255 | write!(fmt, ", ")?; 256 | } 257 | 258 | write!(fmt, "{}: ", arg.name)?; 259 | arg.ty.fmt(fmt)?; 260 | } 261 | 262 | write!(fmt, ")")?; 263 | 264 | if let Some(ref ret) = self.ret { 265 | write!(fmt, " -> ")?; 266 | ret.fmt(fmt)?; 267 | } 268 | 269 | fmt_bounds(&self.bounds, fmt)?; 270 | 271 | match self.body { 272 | Some(ref body) => fmt.block(|fmt| { 273 | for b in body { 274 | b.fmt(fmt)?; 275 | } 276 | 277 | Ok(()) 278 | }), 279 | None => { 280 | if !is_trait { 281 | panic!("impl blocks must define fn bodies"); 282 | } 283 | 284 | write!(fmt, ";\n") 285 | } 286 | } 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /src/impl.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::bound::Bound; 4 | use crate::field::Field; 5 | use crate::formatter::{fmt_bounds, fmt_generics, Formatter}; 6 | use crate::function::Function; 7 | 8 | use crate::r#type::Type; 9 | 10 | /// Defines an impl block. 11 | #[derive(Debug, Clone)] 12 | pub struct Impl { 13 | /// The struct being implemented 14 | target: Type, 15 | 16 | /// Impl level generics 17 | generics: Vec, 18 | 19 | /// If implementing a trait 20 | impl_trait: Option, 21 | 22 | /// Associated types 23 | assoc_tys: Vec, 24 | 25 | /// Bounds 26 | bounds: Vec, 27 | 28 | fns: Vec, 29 | 30 | macros: Vec, 31 | } 32 | 33 | impl Impl { 34 | /// Return a new impl definition 35 | pub fn new(target: T) -> Self 36 | where 37 | T: Into, 38 | { 39 | Impl { 40 | target: target.into(), 41 | generics: vec![], 42 | impl_trait: None, 43 | assoc_tys: vec![], 44 | bounds: vec![], 45 | fns: vec![], 46 | macros: vec![], 47 | } 48 | } 49 | 50 | /// Add a generic to the impl block. 51 | /// 52 | /// This adds the generic for the block (`impl`) and not the target type. 53 | pub fn generic(&mut self, name: &str) -> &mut Self { 54 | self.generics.push(name.to_string()); 55 | self 56 | } 57 | 58 | /// Add a generic to the target type. 59 | pub fn target_generic(&mut self, ty: T) -> &mut Self 60 | where 61 | T: Into, 62 | { 63 | self.target.generic(ty); 64 | self 65 | } 66 | 67 | /// Set the trait that the impl block is implementing. 68 | pub fn impl_trait(&mut self, ty: T) -> &mut Self 69 | where 70 | T: Into, 71 | { 72 | self.impl_trait = Some(ty.into()); 73 | self 74 | } 75 | 76 | /// Add a macro to the impl block (e.g. `"#[async_trait]"`) 77 | pub fn r#macro(&mut self, r#macro: &str) -> &mut Self { 78 | self.macros.push(r#macro.to_string()); 79 | self 80 | } 81 | 82 | /// Set an associated type. 83 | pub fn associate_type(&mut self, name: &str, ty: T) -> &mut Self 84 | where 85 | T: Into, 86 | { 87 | self.assoc_tys.push(Field { 88 | name: name.to_string(), 89 | ty: ty.into(), 90 | documentation: Vec::new(), 91 | annotation: Vec::new(), 92 | }); 93 | 94 | self 95 | } 96 | 97 | /// Add a `where` bound to the impl block. 98 | pub fn bound(&mut self, name: &str, ty: T) -> &mut Self 99 | where 100 | T: Into, 101 | { 102 | self.bounds.push(Bound { 103 | name: name.to_string(), 104 | bound: vec![ty.into()], 105 | }); 106 | self 107 | } 108 | 109 | /// Push a new function definition, returning a mutable reference to it. 110 | pub fn new_fn(&mut self, name: &str) -> &mut Function { 111 | self.push_fn(Function::new(name)); 112 | self.fns.last_mut().unwrap() 113 | } 114 | 115 | /// Push a function definition. 116 | pub fn push_fn(&mut self, item: Function) -> &mut Self { 117 | self.fns.push(item); 118 | self 119 | } 120 | 121 | /// Formats the impl block using the given formatter. 122 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 123 | for m in self.macros.iter() { 124 | write!(fmt, "{}\n", m)?; 125 | } 126 | write!(fmt, "impl")?; 127 | fmt_generics(&self.generics[..], fmt)?; 128 | 129 | if let Some(ref t) = self.impl_trait { 130 | write!(fmt, " ")?; 131 | t.fmt(fmt)?; 132 | write!(fmt, " for")?; 133 | } 134 | 135 | write!(fmt, " ")?; 136 | self.target.fmt(fmt)?; 137 | 138 | fmt_bounds(&self.bounds, fmt)?; 139 | 140 | fmt.block(|fmt| { 141 | // format associated types 142 | if !self.assoc_tys.is_empty() { 143 | for ty in &self.assoc_tys { 144 | write!(fmt, "type {} = ", ty.name)?; 145 | ty.ty.fmt(fmt)?; 146 | write!(fmt, ";\n")?; 147 | } 148 | } 149 | 150 | for (i, func) in self.fns.iter().enumerate() { 151 | if i != 0 || !self.assoc_tys.is_empty() { 152 | write!(fmt, "\n")?; 153 | } 154 | 155 | func.fmt(false, fmt)?; 156 | } 157 | 158 | Ok(()) 159 | }) 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/import.rs: -------------------------------------------------------------------------------- 1 | /// Defines an import (`use` statement). 2 | #[derive(Debug, Clone)] 3 | pub struct Import { 4 | line: String, 5 | 6 | /// Function visibility 7 | pub vis: Option, 8 | } 9 | 10 | impl Import { 11 | /// Return a new import. 12 | pub fn new(path: &str, ty: &str) -> Self { 13 | Import { 14 | line: format!("{}::{}", path, ty), 15 | vis: None, 16 | } 17 | } 18 | 19 | /// Set the import visibility. 20 | pub fn vis(&mut self, vis: &str) -> &mut Self { 21 | self.vis = Some(vis.to_string()); 22 | self 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/item.rs: -------------------------------------------------------------------------------- 1 | use crate::function::Function; 2 | use crate::module::Module; 3 | 4 | use crate::r#enum::Enum; 5 | use crate::r#impl::Impl; 6 | use crate::r#struct::Struct; 7 | use crate::r#trait::Trait; 8 | 9 | #[derive(Debug, Clone)] 10 | pub enum Item { 11 | Module(Module), 12 | Struct(Struct), 13 | Function(Function), 14 | Trait(Trait), 15 | Enum(Enum), 16 | Impl(Impl), 17 | Raw(String), 18 | } 19 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_debug_implementations, missing_docs)] 2 | #![doc(html_root_url = "https://docs.rs/codegen/0.1.1")] 3 | #![warn(rust_2018_idioms)] 4 | 5 | //! Provides a builder API for generating Rust code. 6 | //! 7 | //! The general strategy for using the crate is as follows: 8 | //! 9 | //! 1. Create a `Scope` instance. 10 | //! 2. Use the builder API to add elements to the scope. 11 | //! 3. Call `Scope::to_string()` to get the generated code. 12 | //! 13 | //! For example: 14 | //! 15 | //! ```rust 16 | //! use codegen::Scope; 17 | //! 18 | //! let mut scope = Scope::new(); 19 | //! 20 | //! scope.new_struct("Foo") 21 | //! .derive("Debug") 22 | //! .field("one", "usize") 23 | //! .field("two", "String"); 24 | //! 25 | //! println!("{}", scope.to_string()); 26 | //! ``` 27 | 28 | mod associated_type; 29 | mod block; 30 | mod body; 31 | mod bound; 32 | mod docs; 33 | mod field; 34 | mod fields; 35 | mod formatter; 36 | mod function; 37 | mod import; 38 | mod item; 39 | mod module; 40 | mod scope; 41 | mod type_def; 42 | mod variant; 43 | 44 | mod r#enum; 45 | mod r#impl; 46 | mod r#struct; 47 | mod r#trait; 48 | mod r#type; 49 | 50 | 51 | pub use associated_type::*; 52 | pub use block::*; 53 | pub use field::*; 54 | pub use formatter::*; 55 | pub use function::*; 56 | pub use import::*; 57 | pub use module::*; 58 | pub use scope::*; 59 | pub use variant::*; 60 | 61 | pub use r#enum::*; 62 | pub use r#impl::*; 63 | pub use r#struct::*; 64 | pub use r#trait::*; 65 | pub use r#type::*; 66 | -------------------------------------------------------------------------------- /src/module.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::docs::Docs; 4 | use crate::formatter::Formatter; 5 | use crate::function::Function; 6 | use crate::scope::Scope; 7 | 8 | use crate::r#enum::Enum; 9 | use crate::r#impl::Impl; 10 | use crate::r#struct::Struct; 11 | use crate::r#trait::Trait; 12 | 13 | /// Defines a module. 14 | #[derive(Debug, Clone)] 15 | pub struct Module { 16 | /// Module name 17 | pub name: String, 18 | 19 | /// Visibility 20 | vis: Option, 21 | 22 | /// Module documentation 23 | docs: Option, 24 | 25 | /// Contents of the module 26 | scope: Scope, 27 | } 28 | 29 | impl Module { 30 | /// Return a new, blank module 31 | pub fn new(name: &str) -> Self { 32 | Module { 33 | name: name.to_string(), 34 | vis: None, 35 | docs: None, 36 | scope: Scope::new(), 37 | } 38 | } 39 | 40 | /// Returns a mutable reference to the module's scope. 41 | pub fn scope(&mut self) -> &mut Scope { 42 | &mut self.scope 43 | } 44 | 45 | /// Set the module visibility. 46 | pub fn vis(&mut self, vis: &str) -> &mut Self { 47 | self.vis = Some(vis.to_string()); 48 | self 49 | } 50 | 51 | /// Import a type into the module's scope. 52 | /// 53 | /// This results in a new `use` statement bein added to the beginning of the 54 | /// module. 55 | pub fn import(&mut self, path: &str, ty: &str) -> &mut Self { 56 | self.scope.import(path, ty); 57 | self 58 | } 59 | 60 | /// Push a new module definition, returning a mutable reference to it. 61 | /// 62 | /// # Panics 63 | /// 64 | /// Since a module's name must uniquely identify it within the scope in 65 | /// which it is defined, pushing a module whose name is already defined 66 | /// in this scope will cause this function to panic. 67 | /// 68 | /// In many cases, the [`get_or_new_module`] function is preferrable, as it 69 | /// will return the existing definition instead. 70 | /// 71 | /// [`get_or_new_module`]: #method.get_or_new_module 72 | pub fn new_module(&mut self, name: &str) -> &mut Module { 73 | self.scope.new_module(name) 74 | } 75 | 76 | /// Returns a reference to a module if it is exists in this scope. 77 | pub fn get_module(&self, name: &Q) -> Option<&Module> 78 | where 79 | String: PartialEq, 80 | { 81 | self.scope.get_module(name) 82 | } 83 | 84 | /// Returns a mutable reference to a module if it is exists in this scope. 85 | pub fn get_module_mut(&mut self, name: &Q) -> Option<&mut Module> 86 | where 87 | String: PartialEq, 88 | { 89 | self.scope.get_module_mut(name) 90 | } 91 | 92 | /// Returns a mutable reference to a module, creating it if it does 93 | /// not exist. 94 | pub fn get_or_new_module(&mut self, name: &str) -> &mut Module { 95 | self.scope.get_or_new_module(name) 96 | } 97 | 98 | /// Push a module definition. 99 | /// 100 | /// # Panics 101 | /// 102 | /// Since a module's name must uniquely identify it within the scope in 103 | /// which it is defined, pushing a module whose name is already defined 104 | /// in this scope will cause this function to panic. 105 | /// 106 | /// In many cases, the [`get_or_new_module`] function is preferrable, as it will 107 | /// return the existing definition instead. 108 | /// 109 | /// [`get_or_new_module`]: #method.get_or_new_module 110 | pub fn push_module(&mut self, item: Module) -> &mut Self { 111 | self.scope.push_module(item); 112 | self 113 | } 114 | 115 | /// Push a new struct definition, returning a mutable reference to it. 116 | pub fn new_struct(&mut self, name: &str) -> &mut Struct { 117 | self.scope.new_struct(name) 118 | } 119 | 120 | /// Push a structure definition 121 | pub fn push_struct(&mut self, item: Struct) -> &mut Self { 122 | self.scope.push_struct(item); 123 | self 124 | } 125 | 126 | /// Push a new function definition, returning a mutable reference to it. 127 | pub fn new_fn(&mut self, name: &str) -> &mut Function { 128 | self.scope.new_fn(name) 129 | } 130 | 131 | /// Push a function definition 132 | pub fn push_fn(&mut self, item: Function) -> &mut Self { 133 | self.scope.push_fn(item); 134 | self 135 | } 136 | 137 | /// Push a new enum definition, returning a mutable reference to it. 138 | pub fn new_enum(&mut self, name: &str) -> &mut Enum { 139 | self.scope.new_enum(name) 140 | } 141 | 142 | /// Push an enum definition 143 | pub fn push_enum(&mut self, item: Enum) -> &mut Self { 144 | self.scope.push_enum(item); 145 | self 146 | } 147 | 148 | /// Push a new `impl` block, returning a mutable reference to it. 149 | pub fn new_impl(&mut self, target: &str) -> &mut Impl { 150 | self.scope.new_impl(target) 151 | } 152 | 153 | /// Push an `impl` block. 154 | pub fn push_impl(&mut self, item: Impl) -> &mut Self { 155 | self.scope.push_impl(item); 156 | self 157 | } 158 | 159 | /// Push a trait definition 160 | pub fn push_trait(&mut self, item: Trait) -> &mut Self { 161 | self.scope.push_trait(item); 162 | self 163 | } 164 | 165 | /// Formats the module using the given formatter. 166 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 167 | if let Some(ref vis) = self.vis { 168 | write!(fmt, "{} ", vis)?; 169 | } 170 | 171 | write!(fmt, "mod {}", self.name)?; 172 | fmt.block(|fmt| self.scope.fmt(fmt)) 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/scope.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use indexmap::IndexMap; 4 | 5 | use crate::docs::Docs; 6 | use crate::formatter::Formatter; 7 | use crate::function::Function; 8 | use crate::import::Import; 9 | use crate::item::Item; 10 | use crate::module::Module; 11 | 12 | use crate::r#enum::Enum; 13 | use crate::r#impl::Impl; 14 | use crate::r#struct::Struct; 15 | use crate::r#trait::Trait; 16 | 17 | /// Defines a scope. 18 | /// 19 | /// A scope contains modules, types, etc... 20 | #[derive(Debug, Clone)] 21 | pub struct Scope { 22 | /// Scope documentation 23 | docs: Option, 24 | 25 | /// Imports 26 | imports: IndexMap>, 27 | 28 | /// Contents of the documentation, 29 | items: Vec, 30 | } 31 | 32 | impl Scope { 33 | /// Returns a new scope 34 | pub fn new() -> Self { 35 | Scope { 36 | docs: None, 37 | imports: IndexMap::new(), 38 | items: vec![], 39 | } 40 | } 41 | 42 | /// Import a type into the scope. 43 | /// 44 | /// This results in a new `use` statement being added to the beginning of 45 | /// the scope. 46 | pub fn import(&mut self, path: &str, ty: &str) -> &mut Import { 47 | // handle cases where the caller wants to refer to a type namespaced 48 | // within the containing namespace, like "a::B". 49 | let ty = ty.split("::").next().unwrap_or(ty); 50 | self.imports 51 | .entry(path.to_string()) 52 | .or_insert(IndexMap::new()) 53 | .entry(ty.to_string()) 54 | .or_insert_with(|| Import::new(path, ty)) 55 | } 56 | 57 | /// Push a new module definition, returning a mutable reference to it. 58 | /// 59 | /// # Panics 60 | /// 61 | /// Since a module's name must uniquely identify it within the scope in 62 | /// which it is defined, pushing a module whose name is already defined 63 | /// in this scope will cause this function to panic. 64 | /// 65 | /// In many cases, the [`get_or_new_module`] function is preferrable, as it 66 | /// will return the existing definition instead. 67 | /// 68 | /// [`get_or_new_module`]: #method.get_or_new_module 69 | pub fn new_module(&mut self, name: &str) -> &mut Module { 70 | self.push_module(Module::new(name)); 71 | 72 | match *self.items.last_mut().unwrap() { 73 | Item::Module(ref mut v) => v, 74 | _ => unreachable!(), 75 | } 76 | } 77 | 78 | /// Returns a mutable reference to a module if it is exists in this scope. 79 | pub fn get_module_mut(&mut self, name: &Q) -> Option<&mut Module> 80 | where 81 | String: PartialEq, 82 | { 83 | self.items 84 | .iter_mut() 85 | .filter_map(|item| match item { 86 | &mut Item::Module(ref mut module) if module.name == *name => Some(module), 87 | _ => None, 88 | }) 89 | .next() 90 | } 91 | 92 | /// Returns a mutable reference to a module if it is exists in this scope. 93 | pub fn get_module(&self, name: &Q) -> Option<&Module> 94 | where 95 | String: PartialEq, 96 | { 97 | self.items 98 | .iter() 99 | .filter_map(|item| match item { 100 | &Item::Module(ref module) if module.name == *name => Some(module), 101 | _ => None, 102 | }) 103 | .next() 104 | } 105 | 106 | /// Returns a mutable reference to a module, creating it if it does 107 | /// not exist. 108 | pub fn get_or_new_module(&mut self, name: &str) -> &mut Module { 109 | if self.get_module(name).is_some() { 110 | self.get_module_mut(name).unwrap() 111 | } else { 112 | self.new_module(name) 113 | } 114 | } 115 | 116 | /// Push a module definition. 117 | /// 118 | /// # Panics 119 | /// 120 | /// Since a module's name must uniquely identify it within the scope in 121 | /// which it is defined, pushing a module whose name is already defined 122 | /// in this scope will cause this function to panic. 123 | /// 124 | /// In many cases, the [`get_or_new_module`] function is preferrable, as it will 125 | /// return the existing definition instead. 126 | /// 127 | /// [`get_or_new_module`]: #method.get_or_new_module 128 | pub fn push_module(&mut self, item: Module) -> &mut Self { 129 | assert!(self.get_module(&item.name).is_none()); 130 | self.items.push(Item::Module(item)); 131 | self 132 | } 133 | 134 | /// Push a new struct definition, returning a mutable reference to it. 135 | pub fn new_struct(&mut self, name: &str) -> &mut Struct { 136 | self.push_struct(Struct::new(name)); 137 | 138 | match *self.items.last_mut().unwrap() { 139 | Item::Struct(ref mut v) => v, 140 | _ => unreachable!(), 141 | } 142 | } 143 | 144 | /// Push a struct definition 145 | pub fn push_struct(&mut self, item: Struct) -> &mut Self { 146 | self.items.push(Item::Struct(item)); 147 | self 148 | } 149 | 150 | /// Push a new function definition, returning a mutable reference to it. 151 | pub fn new_fn(&mut self, name: &str) -> &mut Function { 152 | self.push_fn(Function::new(name)); 153 | 154 | match *self.items.last_mut().unwrap() { 155 | Item::Function(ref mut v) => v, 156 | _ => unreachable!(), 157 | } 158 | } 159 | 160 | /// Push a function definition 161 | pub fn push_fn(&mut self, item: Function) -> &mut Self { 162 | self.items.push(Item::Function(item)); 163 | self 164 | } 165 | 166 | /// Push a new trait definition, returning a mutable reference to it. 167 | pub fn new_trait(&mut self, name: &str) -> &mut Trait { 168 | self.push_trait(Trait::new(name)); 169 | 170 | match *self.items.last_mut().unwrap() { 171 | Item::Trait(ref mut v) => v, 172 | _ => unreachable!(), 173 | } 174 | } 175 | 176 | /// Push a trait definition 177 | pub fn push_trait(&mut self, item: Trait) -> &mut Self { 178 | self.items.push(Item::Trait(item)); 179 | self 180 | } 181 | 182 | /// Push a new struct definition, returning a mutable reference to it. 183 | pub fn new_enum(&mut self, name: &str) -> &mut Enum { 184 | self.push_enum(Enum::new(name)); 185 | 186 | match *self.items.last_mut().unwrap() { 187 | Item::Enum(ref mut v) => v, 188 | _ => unreachable!(), 189 | } 190 | } 191 | 192 | /// Push a structure definition 193 | pub fn push_enum(&mut self, item: Enum) -> &mut Self { 194 | self.items.push(Item::Enum(item)); 195 | self 196 | } 197 | 198 | /// Push a new `impl` block, returning a mutable reference to it. 199 | pub fn new_impl(&mut self, target: &str) -> &mut Impl { 200 | self.push_impl(Impl::new(target)); 201 | 202 | match *self.items.last_mut().unwrap() { 203 | Item::Impl(ref mut v) => v, 204 | _ => unreachable!(), 205 | } 206 | } 207 | 208 | /// Push an `impl` block. 209 | pub fn push_impl(&mut self, item: Impl) -> &mut Self { 210 | self.items.push(Item::Impl(item)); 211 | self 212 | } 213 | 214 | /// Push a raw string to the scope. 215 | /// 216 | /// This string will be included verbatim in the formatted string. 217 | pub fn raw(&mut self, val: &str) -> &mut Self { 218 | self.items.push(Item::Raw(val.to_string())); 219 | self 220 | } 221 | 222 | /// Return a string representation of the scope. 223 | pub fn to_string(&self) -> String { 224 | let mut ret = String::new(); 225 | 226 | self.fmt(&mut Formatter::new(&mut ret)).unwrap(); 227 | 228 | // Remove the trailing newline 229 | if ret.as_bytes().last() == Some(&b'\n') { 230 | ret.pop(); 231 | } 232 | 233 | ret 234 | } 235 | 236 | /// Formats the scope using the given formatter. 237 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 238 | self.fmt_imports(fmt)?; 239 | 240 | if !self.imports.is_empty() { 241 | write!(fmt, "\n")?; 242 | } 243 | 244 | for (i, item) in self.items.iter().enumerate() { 245 | if i != 0 { 246 | write!(fmt, "\n")?; 247 | } 248 | 249 | match *item { 250 | Item::Module(ref v) => v.fmt(fmt)?, 251 | Item::Struct(ref v) => v.fmt(fmt)?, 252 | Item::Function(ref v) => v.fmt(false, fmt)?, 253 | Item::Trait(ref v) => v.fmt(fmt)?, 254 | Item::Enum(ref v) => v.fmt(fmt)?, 255 | Item::Impl(ref v) => v.fmt(fmt)?, 256 | Item::Raw(ref v) => { 257 | write!(fmt, "{}\n", v)?; 258 | } 259 | } 260 | } 261 | 262 | Ok(()) 263 | } 264 | 265 | fn fmt_imports(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 266 | // First, collect all visibilities 267 | let mut visibilities = vec![]; 268 | 269 | for (_, imports) in &self.imports { 270 | for (_, import) in imports { 271 | if !visibilities.contains(&import.vis) { 272 | visibilities.push(import.vis.clone()); 273 | } 274 | } 275 | } 276 | 277 | let mut tys = vec![]; 278 | 279 | // Loop over all visibilities and format the associated imports 280 | for vis in &visibilities { 281 | for (path, imports) in &self.imports { 282 | tys.clear(); 283 | 284 | for (ty, import) in imports { 285 | if *vis == import.vis { 286 | tys.push(ty); 287 | } 288 | } 289 | 290 | if !tys.is_empty() { 291 | if let Some(ref vis) = *vis { 292 | write!(fmt, "{} ", vis)?; 293 | } 294 | 295 | write!(fmt, "use {}::", path)?; 296 | 297 | if tys.len() > 1 { 298 | write!(fmt, "{{")?; 299 | 300 | for (i, ty) in tys.iter().enumerate() { 301 | if i != 0 { 302 | write!(fmt, ", ")?; 303 | } 304 | write!(fmt, "{}", ty)?; 305 | } 306 | 307 | write!(fmt, "}};\n")?; 308 | } else if tys.len() == 1 { 309 | write!(fmt, "{};\n", tys[0])?; 310 | } 311 | } 312 | } 313 | } 314 | 315 | Ok(()) 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /src/struct.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::field::Field; 4 | use crate::fields::Fields; 5 | use crate::formatter::Formatter; 6 | use crate::type_def::TypeDef; 7 | 8 | use crate::r#type::Type; 9 | 10 | /// Defines a struct. 11 | #[derive(Debug, Clone)] 12 | pub struct Struct { 13 | type_def: TypeDef, 14 | 15 | /// Struct fields 16 | fields: Fields, 17 | } 18 | 19 | impl Struct { 20 | /// Return a structure definition with the provided name 21 | pub fn new(name: &str) -> Self { 22 | Struct { 23 | type_def: TypeDef::new(name), 24 | fields: Fields::Empty, 25 | } 26 | } 27 | 28 | /// Returns a reference to the type 29 | pub fn ty(&self) -> &Type { 30 | &self.type_def.ty 31 | } 32 | 33 | /// Set the structure visibility. 34 | pub fn vis(&mut self, vis: &str) -> &mut Self { 35 | self.type_def.vis(vis); 36 | self 37 | } 38 | 39 | /// Add a generic to the struct. 40 | pub fn generic(&mut self, name: &str) -> &mut Self { 41 | self.type_def.ty.generic(name); 42 | self 43 | } 44 | 45 | /// Add a `where` bound to the struct. 46 | pub fn bound(&mut self, name: &str, ty: T) -> &mut Self 47 | where 48 | T: Into, 49 | { 50 | self.type_def.bound(name, ty); 51 | self 52 | } 53 | 54 | /// Set the structure documentation. 55 | pub fn doc(&mut self, docs: &str) -> &mut Self { 56 | self.type_def.doc(docs); 57 | self 58 | } 59 | 60 | /// Add a new type that the struct should derive. 61 | pub fn derive(&mut self, name: &str) -> &mut Self { 62 | self.type_def.derive(name); 63 | self 64 | } 65 | 66 | /// Specify lint attribute to supress a warning or error. 67 | pub fn allow(&mut self, allow: &str) -> &mut Self { 68 | self.type_def.allow(allow); 69 | self 70 | } 71 | 72 | /// Specify representation. 73 | pub fn repr(&mut self, repr: &str) -> &mut Self { 74 | self.type_def.repr(repr); 75 | self 76 | } 77 | 78 | /// Push a named field to the struct. 79 | /// 80 | /// A struct can either set named fields with this function or tuple fields 81 | /// with `push_tuple_field`, but not both. 82 | pub fn push_field(&mut self, field: Field) -> &mut Self { 83 | self.fields.push_named(field); 84 | self 85 | } 86 | 87 | /// Add a named field to the struct. 88 | /// 89 | /// A struct can either set named fields with this function or tuple fields 90 | /// with `tuple_field`, but not both. 91 | pub fn field(&mut self, name: &str, ty: T) -> &mut Self 92 | where 93 | T: Into, 94 | { 95 | self.fields.named(name, ty); 96 | self 97 | } 98 | 99 | /// Add a tuple field to the struct. 100 | /// 101 | /// A struct can either set tuple fields with this function or named fields 102 | /// with `field`, but not both. 103 | pub fn tuple_field(&mut self, ty: T) -> &mut Self 104 | where 105 | T: Into, 106 | { 107 | self.fields.tuple(ty); 108 | self 109 | } 110 | 111 | /// Formats the struct using the given formatter. 112 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 113 | self.type_def.fmt_head("struct", &[], fmt)?; 114 | self.fields.fmt(fmt)?; 115 | 116 | match self.fields { 117 | Fields::Empty => { 118 | write!(fmt, ";\n")?; 119 | } 120 | Fields::Tuple(..) => { 121 | write!(fmt, ";\n")?; 122 | } 123 | _ => {} 124 | } 125 | 126 | Ok(()) 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/trait.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::associated_type::AssociatedType; 4 | use crate::bound::Bound; 5 | use crate::formatter::{fmt_bound_rhs, Formatter}; 6 | use crate::function::Function; 7 | use crate::type_def::TypeDef; 8 | 9 | use crate::r#type::Type; 10 | 11 | /// Define a trait. 12 | #[derive(Debug, Clone)] 13 | pub struct Trait { 14 | type_def: TypeDef, 15 | parents: Vec, 16 | associated_tys: Vec, 17 | fns: Vec, 18 | macros: Vec, 19 | } 20 | 21 | impl Trait { 22 | /// Return a trait definition with the provided name 23 | pub fn new(name: &str) -> Self { 24 | Trait { 25 | type_def: TypeDef::new(name), 26 | parents: vec![], 27 | associated_tys: vec![], 28 | fns: vec![], 29 | macros: vec![], 30 | } 31 | } 32 | 33 | /// Returns a reference to the type 34 | pub fn ty(&self) -> &Type { 35 | &self.type_def.ty 36 | } 37 | 38 | /// Set the trait visibility. 39 | pub fn vis(&mut self, vis: &str) -> &mut Self { 40 | self.type_def.vis(vis); 41 | self 42 | } 43 | 44 | /// Add a generic to the trait 45 | pub fn generic(&mut self, name: &str) -> &mut Self { 46 | self.type_def.ty.generic(name); 47 | self 48 | } 49 | 50 | /// Add a `where` bound to the trait. 51 | pub fn bound(&mut self, name: &str, ty: T) -> &mut Self 52 | where 53 | T: Into, 54 | { 55 | self.type_def.bound(name, ty); 56 | self 57 | } 58 | 59 | /// Add a macro to the trait def (e.g. `"#[async_trait]"`) 60 | pub fn r#macro(&mut self, r#macro: &str) -> &mut Self { 61 | self.type_def.r#macro(r#macro); 62 | self 63 | } 64 | 65 | /// Add a parent trait. 66 | pub fn parent(&mut self, ty: T) -> &mut Self 67 | where 68 | T: Into, 69 | { 70 | self.parents.push(ty.into()); 71 | self 72 | } 73 | 74 | /// Set the trait documentation. 75 | pub fn doc(&mut self, docs: &str) -> &mut Self { 76 | self.type_def.doc(docs); 77 | self 78 | } 79 | 80 | /// Add an associated type. Returns a mutable reference to the new 81 | /// associated type for futher configuration. 82 | pub fn associated_type(&mut self, name: &str) -> &mut AssociatedType { 83 | self.associated_tys.push(AssociatedType(Bound { 84 | name: name.to_string(), 85 | bound: vec![], 86 | })); 87 | 88 | self.associated_tys.last_mut().unwrap() 89 | } 90 | 91 | /// Push a new function definition, returning a mutable reference to it. 92 | pub fn new_fn(&mut self, name: &str) -> &mut Function { 93 | let mut func = Function::new(name); 94 | func.body = None; 95 | 96 | self.push_fn(func); 97 | self.fns.last_mut().unwrap() 98 | } 99 | 100 | /// Push a function definition. 101 | pub fn push_fn(&mut self, item: Function) -> &mut Self { 102 | self.fns.push(item); 103 | self 104 | } 105 | 106 | /// Formats the scope using the given formatter. 107 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 108 | self.type_def.fmt_head("trait", &self.parents, fmt)?; 109 | 110 | fmt.block(|fmt| { 111 | let assoc = &self.associated_tys; 112 | 113 | // format associated types 114 | if !assoc.is_empty() { 115 | for ty in assoc { 116 | let ty = &ty.0; 117 | 118 | write!(fmt, "type {}", ty.name)?; 119 | 120 | if !ty.bound.is_empty() { 121 | write!(fmt, ": ")?; 122 | fmt_bound_rhs(&ty.bound, fmt)?; 123 | } 124 | 125 | write!(fmt, ";\n")?; 126 | } 127 | } 128 | 129 | for (i, func) in self.fns.iter().enumerate() { 130 | if i != 0 || !assoc.is_empty() { 131 | write!(fmt, "\n")?; 132 | } 133 | 134 | func.fmt(true, fmt)?; 135 | } 136 | 137 | Ok(()) 138 | }) 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/type.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::formatter::Formatter; 4 | 5 | /// Defines a type. 6 | #[derive(Debug, Clone)] 7 | pub struct Type { 8 | name: String, 9 | generics: Vec, 10 | } 11 | 12 | impl Type { 13 | /// Return a new type with the given name. 14 | pub fn new(name: &str) -> Self { 15 | Type { 16 | name: name.to_string(), 17 | generics: vec![], 18 | } 19 | } 20 | 21 | /// Add a generic to the type. 22 | pub fn generic(&mut self, ty: T) -> &mut Self 23 | where 24 | T: Into, 25 | { 26 | // Make sure that the name doesn't already include generics 27 | assert!( 28 | !self.name.contains("<"), 29 | "type name already includes generics" 30 | ); 31 | 32 | self.generics.push(ty.into()); 33 | self 34 | } 35 | 36 | /// Rewrite the `Type` with the provided path 37 | /// 38 | /// TODO: Is this needed? 39 | pub fn path(&self, path: &str) -> Type { 40 | // TODO: This isn't really correct 41 | assert!(!self.name.contains("::")); 42 | 43 | let mut name = path.to_string(); 44 | name.push_str("::"); 45 | name.push_str(&self.name); 46 | 47 | Type { 48 | name, 49 | generics: self.generics.clone(), 50 | } 51 | } 52 | 53 | /// Formats the struct using the given formatter. 54 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 55 | write!(fmt, "{}", self.name)?; 56 | Type::fmt_slice(&self.generics, fmt) 57 | } 58 | 59 | fn fmt_slice(generics: &[Type], fmt: &mut Formatter<'_>) -> fmt::Result { 60 | if !generics.is_empty() { 61 | write!(fmt, "<")?; 62 | 63 | for (i, ty) in generics.iter().enumerate() { 64 | if i != 0 { 65 | write!(fmt, ", ")? 66 | } 67 | ty.fmt(fmt)?; 68 | } 69 | 70 | write!(fmt, ">")?; 71 | } 72 | 73 | Ok(()) 74 | } 75 | } 76 | 77 | impl<'a> From<&'a str> for Type { 78 | fn from(src: &'a str) -> Self { 79 | Type::new(src) 80 | } 81 | } 82 | 83 | impl From for Type { 84 | fn from(src: String) -> Self { 85 | Type { 86 | name: src, 87 | generics: vec![], 88 | } 89 | } 90 | } 91 | 92 | impl<'a> From<&'a String> for Type { 93 | fn from(src: &'a String) -> Self { 94 | Type::new(src) 95 | } 96 | } 97 | 98 | impl<'a> From<&'a Type> for Type { 99 | fn from(src: &'a Type) -> Self { 100 | src.clone() 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/type_def.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::bound::Bound; 4 | use crate::docs::Docs; 5 | use crate::formatter::{fmt_bounds, Formatter}; 6 | 7 | use crate::r#type::Type; 8 | 9 | /// Defines a type definition. 10 | #[derive(Debug, Clone)] 11 | pub struct TypeDef { 12 | pub ty: Type, 13 | vis: Option, 14 | docs: Option, 15 | derive: Vec, 16 | allow: Vec, 17 | repr: Option, 18 | bounds: Vec, 19 | macros: Vec, 20 | } 21 | 22 | impl TypeDef { 23 | /// Return a structure definition with the provided name 24 | pub fn new(name: &str) -> Self { 25 | TypeDef { 26 | ty: Type::new(name), 27 | vis: None, 28 | docs: None, 29 | derive: vec![], 30 | allow: vec![], 31 | repr: None, 32 | bounds: vec![], 33 | macros: vec![], 34 | } 35 | } 36 | 37 | pub fn vis(&mut self, vis: &str) { 38 | self.vis = Some(vis.to_string()); 39 | } 40 | 41 | pub fn bound(&mut self, name: &str, ty: T) 42 | where 43 | T: Into, 44 | { 45 | self.bounds.push(Bound { 46 | name: name.to_string(), 47 | bound: vec![ty.into()], 48 | }); 49 | } 50 | 51 | pub fn r#macro(&mut self, r#macro: &str) { 52 | self.macros.push(r#macro.to_string()); 53 | } 54 | 55 | pub fn doc(&mut self, docs: &str) { 56 | self.docs = Some(Docs::new(docs)); 57 | } 58 | 59 | pub fn derive(&mut self, name: &str) { 60 | self.derive.push(name.to_string()); 61 | } 62 | 63 | pub fn allow(&mut self, allow: &str) { 64 | self.allow.push(allow.to_string()); 65 | } 66 | 67 | pub fn repr(&mut self, repr: &str) { 68 | self.repr = Some(repr.to_string()); 69 | } 70 | 71 | pub fn fmt_head( 72 | &self, 73 | keyword: &str, 74 | parents: &[Type], 75 | fmt: &mut Formatter<'_>, 76 | ) -> fmt::Result { 77 | if let Some(ref docs) = self.docs { 78 | docs.fmt(fmt)?; 79 | } 80 | 81 | self.fmt_allow(fmt)?; 82 | self.fmt_derive(fmt)?; 83 | self.fmt_repr(fmt)?; 84 | self.fmt_macros(fmt)?; 85 | 86 | if let Some(ref vis) = self.vis { 87 | write!(fmt, "{} ", vis)?; 88 | } 89 | 90 | write!(fmt, "{} ", keyword)?; 91 | self.ty.fmt(fmt)?; 92 | 93 | if !parents.is_empty() { 94 | for (i, ty) in parents.iter().enumerate() { 95 | if i == 0 { 96 | write!(fmt, ": ")?; 97 | } else { 98 | write!(fmt, " + ")?; 99 | } 100 | 101 | ty.fmt(fmt)?; 102 | } 103 | } 104 | 105 | fmt_bounds(&self.bounds, fmt)?; 106 | 107 | Ok(()) 108 | } 109 | 110 | fn fmt_allow(&self, fmt: &mut Formatter) -> fmt::Result { 111 | for allow in &self.allow { 112 | write!(fmt, "#[allow({})]\n", allow)?; 113 | } 114 | 115 | Ok(()) 116 | } 117 | 118 | fn fmt_repr(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 119 | if let Some(ref repr) = self.repr { 120 | write!(fmt, "#[repr({})]\n", repr)?; 121 | } 122 | 123 | Ok(()) 124 | } 125 | 126 | fn fmt_derive(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 127 | if !self.derive.is_empty() { 128 | write!(fmt, "#[derive(")?; 129 | 130 | for (i, name) in self.derive.iter().enumerate() { 131 | if i != 0 { 132 | write!(fmt, ", ")? 133 | } 134 | write!(fmt, "{}", name)?; 135 | } 136 | 137 | write!(fmt, ")]\n")?; 138 | } 139 | 140 | Ok(()) 141 | } 142 | 143 | fn fmt_macros(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 144 | for m in self.macros.iter() { 145 | write!(fmt, "{}\n", m)?; 146 | } 147 | Ok(()) 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/variant.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Write}; 2 | 3 | use crate::fields::Fields; 4 | use crate::formatter::Formatter; 5 | 6 | use crate::r#type::Type; 7 | 8 | /// Defines an enum variant. 9 | #[derive(Debug, Clone)] 10 | pub struct Variant { 11 | name: String, 12 | fields: Fields, 13 | } 14 | 15 | impl Variant { 16 | /// Return a new enum variant with the given name. 17 | pub fn new(name: &str) -> Self { 18 | Variant { 19 | name: name.to_string(), 20 | fields: Fields::Empty, 21 | } 22 | } 23 | 24 | /// Add a named field to the variant. 25 | pub fn named(&mut self, name: &str, ty: T) -> &mut Self 26 | where 27 | T: Into, 28 | { 29 | self.fields.named(name, ty); 30 | self 31 | } 32 | 33 | /// Add a tuple field to the variant. 34 | pub fn tuple(&mut self, ty: &str) -> &mut Self { 35 | self.fields.tuple(ty); 36 | self 37 | } 38 | 39 | /// Formats the variant using the given formatter. 40 | pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { 41 | write!(fmt, "{}", self.name)?; 42 | self.fields.fmt(fmt)?; 43 | write!(fmt, ",\n")?; 44 | 45 | Ok(()) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/codegen.rs: -------------------------------------------------------------------------------- 1 | use codegen::*; 2 | 3 | #[test] 4 | fn empty_scope() { 5 | let scope = Scope::new(); 6 | 7 | assert_eq!(scope.to_string(), ""); 8 | } 9 | 10 | #[test] 11 | fn single_struct() { 12 | let mut scope = Scope::new(); 13 | 14 | scope 15 | .new_struct("Foo") 16 | .field("one", "usize") 17 | .field("two", "String"); 18 | 19 | let expect = r#" 20 | struct Foo { 21 | one: usize, 22 | two: String, 23 | }"#; 24 | 25 | assert_eq!(scope.to_string(), &expect[1..]); 26 | } 27 | 28 | #[test] 29 | fn struct_with_pushed_field() { 30 | let mut scope = Scope::new(); 31 | let mut struct_ = Struct::new("Foo"); 32 | let field = Field::new("one", "usize"); 33 | struct_.push_field(field); 34 | scope.push_struct(struct_); 35 | 36 | let expect = r#" 37 | struct Foo { 38 | one: usize, 39 | }"#; 40 | 41 | assert_eq!(scope.to_string(), &expect[1..]); 42 | } 43 | 44 | #[test] 45 | fn single_struct_documented_field() { 46 | let mut scope = Scope::new(); 47 | 48 | let doc = vec!["Field's documentation", "Second line"]; 49 | 50 | let mut struct_ = Struct::new("Foo"); 51 | 52 | let mut field1 = Field::new("one", "usize"); 53 | field1.doc(doc.clone()); 54 | struct_.push_field(field1); 55 | 56 | let mut field2 = Field::new("two", "usize"); 57 | field2.annotation(vec![r#"#[serde(rename = "bar")]"#]); 58 | struct_.push_field(field2); 59 | 60 | let mut field3 = Field::new("three", "usize"); 61 | field3.doc(doc).annotation(vec![ 62 | r#"#[serde(skip_serializing)]"#, 63 | r#"#[serde(skip_deserializing)]"#, 64 | ]); 65 | struct_.push_field(field3); 66 | 67 | scope.push_struct(struct_); 68 | 69 | let expect = r#" 70 | struct Foo { 71 | /// Field's documentation 72 | /// Second line 73 | one: usize, 74 | #[serde(rename = "bar")] 75 | two: usize, 76 | /// Field's documentation 77 | /// Second line 78 | #[serde(skip_serializing)] 79 | #[serde(skip_deserializing)] 80 | three: usize, 81 | }"#; 82 | 83 | assert_eq!(scope.to_string(), &expect[1..]); 84 | } 85 | 86 | #[test] 87 | fn single_fn() { 88 | let mut scope = Scope::new(); 89 | scope 90 | .new_fn("my_fn") 91 | .vis("pub") 92 | .arg("foo", Type::new("uint")) 93 | .ret(Type::new("uint")) 94 | .line("let res = foo + 1;") 95 | .line("res"); 96 | 97 | let expect = r#" 98 | pub fn my_fn(foo: uint) -> uint { 99 | let res = foo + 1; 100 | res 101 | }"#; 102 | 103 | assert_eq!(scope.to_string(), &expect[1..]); 104 | } 105 | 106 | #[test] 107 | fn empty_struct() { 108 | let mut scope = Scope::new(); 109 | 110 | scope.new_struct("Foo"); 111 | 112 | let expect = r#" 113 | struct Foo;"#; 114 | 115 | assert_eq!(scope.to_string(), &expect[1..]); 116 | } 117 | 118 | #[test] 119 | fn two_structs() { 120 | let mut scope = Scope::new(); 121 | 122 | scope 123 | .new_struct("Foo") 124 | .field("one", "usize") 125 | .field("two", "String"); 126 | 127 | scope.new_struct("Bar").field("hello", "World"); 128 | 129 | let expect = r#" 130 | struct Foo { 131 | one: usize, 132 | two: String, 133 | } 134 | 135 | struct Bar { 136 | hello: World, 137 | }"#; 138 | 139 | assert_eq!(scope.to_string(), &expect[1..]); 140 | } 141 | 142 | #[test] 143 | fn struct_with_derive() { 144 | let mut scope = Scope::new(); 145 | 146 | scope 147 | .new_struct("Foo") 148 | .derive("Debug") 149 | .derive("Clone") 150 | .field("one", "usize") 151 | .field("two", "String"); 152 | 153 | let expect = r#" 154 | #[derive(Debug, Clone)] 155 | struct Foo { 156 | one: usize, 157 | two: String, 158 | }"#; 159 | 160 | assert_eq!(scope.to_string(), &expect[1..]); 161 | } 162 | 163 | #[test] 164 | fn struct_with_repr() { 165 | let mut scope = Scope::new(); 166 | 167 | scope 168 | .new_struct("Foo") 169 | .repr("C") 170 | .field("one", "u8") 171 | .field("two", "u8"); 172 | 173 | let expect = r#" 174 | #[repr(C)] 175 | struct Foo { 176 | one: u8, 177 | two: u8, 178 | }"#; 179 | 180 | assert_eq!(scope.to_string(), &expect[1..]); 181 | } 182 | 183 | #[test] 184 | fn struct_with_allow() { 185 | let mut scope = Scope::new(); 186 | 187 | scope 188 | .new_struct("Foo") 189 | .allow("dead_code") 190 | .field("one", "u8") 191 | .field("two", "u8"); 192 | 193 | let expect = r#" 194 | #[allow(dead_code)] 195 | struct Foo { 196 | one: u8, 197 | two: u8, 198 | }"#; 199 | 200 | assert_eq!(scope.to_string(), &expect[1..]); 201 | } 202 | 203 | #[test] 204 | fn struct_with_generics_1() { 205 | let mut scope = Scope::new(); 206 | 207 | scope 208 | .new_struct("Foo") 209 | .generic("T") 210 | .generic("U") 211 | .field("one", "T") 212 | .field("two", "U"); 213 | 214 | let expect = r#" 215 | struct Foo { 216 | one: T, 217 | two: U, 218 | }"#; 219 | 220 | assert_eq!(scope.to_string(), &expect[1..]); 221 | } 222 | 223 | #[test] 224 | fn struct_with_generics_2() { 225 | let mut scope = Scope::new(); 226 | 227 | scope 228 | .new_struct("Foo") 229 | .generic("T, U") 230 | .field("one", "T") 231 | .field("two", "U"); 232 | 233 | let expect = r#" 234 | struct Foo { 235 | one: T, 236 | two: U, 237 | }"#; 238 | 239 | assert_eq!(scope.to_string(), &expect[1..]); 240 | } 241 | 242 | #[test] 243 | fn struct_with_generics_3() { 244 | let mut scope = Scope::new(); 245 | 246 | scope 247 | .new_struct("Foo") 248 | .generic("T: Win, U") 249 | .field("one", "T") 250 | .field("two", "U"); 251 | 252 | let expect = r#" 253 | struct Foo { 254 | one: T, 255 | two: U, 256 | }"#; 257 | 258 | assert_eq!(scope.to_string(), &expect[1..]); 259 | } 260 | 261 | #[test] 262 | fn struct_where_clause_1() { 263 | let mut scope = Scope::new(); 264 | 265 | scope 266 | .new_struct("Foo") 267 | .generic("T") 268 | .bound("T", "Foo") 269 | .field("one", "T"); 270 | 271 | let expect = r#" 272 | struct Foo 273 | where T: Foo, 274 | { 275 | one: T, 276 | }"#; 277 | 278 | assert_eq!(scope.to_string(), &expect[1..]); 279 | } 280 | 281 | #[test] 282 | fn struct_where_clause_2() { 283 | let mut scope = Scope::new(); 284 | 285 | scope 286 | .new_struct("Foo") 287 | .generic("T, U") 288 | .bound("T", "Foo") 289 | .bound("U", "Baz") 290 | .field("one", "T") 291 | .field("two", "U"); 292 | 293 | let expect = r#" 294 | struct Foo 295 | where T: Foo, 296 | U: Baz, 297 | { 298 | one: T, 299 | two: U, 300 | }"#; 301 | 302 | assert_eq!(scope.to_string(), &expect[1..]); 303 | } 304 | 305 | #[test] 306 | fn struct_doc() { 307 | let mut scope = Scope::new(); 308 | 309 | scope 310 | .new_struct("Foo") 311 | .doc( 312 | "Hello, this is a doc string\n\ 313 | that continues on another line.", 314 | ) 315 | .field("one", "T"); 316 | 317 | let expect = r#" 318 | /// Hello, this is a doc string 319 | /// that continues on another line. 320 | struct Foo { 321 | one: T, 322 | }"#; 323 | 324 | assert_eq!(scope.to_string(), &expect[1..]); 325 | } 326 | 327 | #[test] 328 | fn struct_in_mod() { 329 | let mut scope = Scope::new(); 330 | 331 | { 332 | let module = scope.new_module("foo"); 333 | module 334 | .new_struct("Foo") 335 | .doc("Hello some docs") 336 | .derive("Debug") 337 | .generic("T, U") 338 | .bound("T", "SomeBound") 339 | .bound("U", "SomeOtherBound") 340 | .field("one", "T") 341 | .field("two", "U"); 342 | } 343 | 344 | let expect = r#" 345 | mod foo { 346 | /// Hello some docs 347 | #[derive(Debug)] 348 | struct Foo 349 | where T: SomeBound, 350 | U: SomeOtherBound, 351 | { 352 | one: T, 353 | two: U, 354 | } 355 | }"#; 356 | 357 | assert_eq!(scope.to_string(), &expect[1..]); 358 | } 359 | 360 | #[test] 361 | fn struct_mod_import() { 362 | let mut scope = Scope::new(); 363 | scope 364 | .new_module("foo") 365 | .import("bar", "Bar") 366 | .new_struct("Foo") 367 | .field("bar", "Bar"); 368 | 369 | let expect = r#" 370 | mod foo { 371 | use bar::Bar; 372 | 373 | struct Foo { 374 | bar: Bar, 375 | } 376 | }"#; 377 | 378 | assert_eq!(scope.to_string(), &expect[1..]); 379 | } 380 | 381 | #[test] 382 | fn enum_with_repr() { 383 | let mut scope = Scope::new(); 384 | 385 | scope 386 | .new_enum("IpAddrKind") 387 | .repr("u8") 388 | .push_variant(Variant::new("V4")) 389 | .push_variant(Variant::new("V6")); 390 | 391 | let expect = r#" 392 | #[repr(u8)] 393 | enum IpAddrKind { 394 | V4, 395 | V6, 396 | }"#; 397 | 398 | assert_eq!(scope.to_string(), &expect[1..]); 399 | } 400 | 401 | #[test] 402 | fn enum_with_allow() { 403 | let mut scope = Scope::new(); 404 | 405 | scope 406 | .new_enum("IpAddrKind") 407 | .allow("dead_code") 408 | .push_variant(Variant::new("V4")) 409 | .push_variant(Variant::new("V6")); 410 | 411 | let expect = r#" 412 | #[allow(dead_code)] 413 | enum IpAddrKind { 414 | V4, 415 | V6, 416 | }"#; 417 | 418 | assert_eq!(scope.to_string(), &expect[1..]); 419 | } 420 | 421 | #[test] 422 | fn scoped_imports() { 423 | let mut scope = Scope::new(); 424 | scope 425 | .new_module("foo") 426 | .import("bar", "Bar") 427 | .import("bar", "baz::Baz") 428 | .import("bar::quux", "quuux::Quuuux") 429 | .new_struct("Foo") 430 | .field("bar", "Bar") 431 | .field("baz", "baz::Baz") 432 | .field("quuuux", "quuux::Quuuux"); 433 | 434 | let expect = r#" 435 | mod foo { 436 | use bar::{Bar, baz}; 437 | use bar::quux::quuux; 438 | 439 | struct Foo { 440 | bar: Bar, 441 | baz: baz::Baz, 442 | quuuux: quuux::Quuuux, 443 | } 444 | }"#; 445 | 446 | assert_eq!(scope.to_string(), &expect[1..]); 447 | } 448 | 449 | #[test] 450 | fn module_mut() { 451 | let mut scope = Scope::new(); 452 | scope.new_module("foo").import("bar", "Bar"); 453 | 454 | scope 455 | .get_module_mut("foo") 456 | .expect("module_mut") 457 | .new_struct("Foo") 458 | .field("bar", "Bar"); 459 | 460 | let expect = r#" 461 | mod foo { 462 | use bar::Bar; 463 | 464 | struct Foo { 465 | bar: Bar, 466 | } 467 | }"#; 468 | 469 | assert_eq!(scope.to_string(), &expect[1..]); 470 | } 471 | 472 | #[test] 473 | fn get_or_new_module() { 474 | let mut scope = Scope::new(); 475 | assert!(scope.get_module("foo").is_none()); 476 | 477 | scope.get_or_new_module("foo").import("bar", "Bar"); 478 | 479 | scope 480 | .get_or_new_module("foo") 481 | .new_struct("Foo") 482 | .field("bar", "Bar"); 483 | 484 | let expect = r#" 485 | mod foo { 486 | use bar::Bar; 487 | 488 | struct Foo { 489 | bar: Bar, 490 | } 491 | }"#; 492 | 493 | assert_eq!(scope.to_string(), &expect[1..]); 494 | } 495 | 496 | #[test] 497 | fn function_with_async() { 498 | let mut scope = Scope::new(); 499 | let trt = scope.new_trait("Foo"); 500 | 501 | let f = trt.new_fn("pet_toby"); 502 | f.set_async(true); 503 | f.line("println!(\"petting toby because he is a good boi\");"); 504 | 505 | let expect = r#" 506 | trait Foo { 507 | async fn pet_toby() { 508 | println!("petting toby because he is a good boi"); 509 | } 510 | }"#; 511 | 512 | assert_eq!(scope.to_string(), &expect[1..]); 513 | } 514 | 515 | #[test] 516 | fn trait_with_macros() { 517 | let mut scope = Scope::new(); 518 | let trt = scope.new_trait("Foo"); 519 | trt.r#macro("#[async_trait]"); 520 | trt.r#macro("#[toby_is_cute]"); 521 | 522 | let f = trt.new_fn("pet_toby"); 523 | f.set_async(true); 524 | f.line("println!(\"petting toby because he is a good boi\");"); 525 | 526 | let expect = r#" 527 | #[async_trait] 528 | #[toby_is_cute] 529 | trait Foo { 530 | async fn pet_toby() { 531 | println!("petting toby because he is a good boi"); 532 | } 533 | }"#; 534 | 535 | assert_eq!(scope.to_string(), &expect[1..]); 536 | } 537 | 538 | #[test] 539 | fn impl_with_macros() { 540 | let mut scope = Scope::new(); 541 | scope.new_struct("Bar"); 542 | let imp = scope.new_impl("Bar"); 543 | imp.impl_trait("Foo"); 544 | imp.r#macro("#[async_trait]"); 545 | imp.r#macro("#[toby_is_cute]"); 546 | 547 | let f = imp.new_fn("pet_toby"); 548 | f.set_async(true); 549 | f.line("println!(\"petting Toby many times because he is such a good boi\");"); 550 | 551 | let expect = r#" 552 | struct Bar; 553 | 554 | #[async_trait] 555 | #[toby_is_cute] 556 | impl Foo for Bar { 557 | async fn pet_toby() { 558 | println!("petting Toby many times because he is such a good boi"); 559 | } 560 | }"#; 561 | 562 | assert_eq!(scope.to_string(), &expect[1..]); 563 | } 564 | 565 | #[test] 566 | fn struct_with_multiple_allow() { 567 | let mut scope = Scope::new(); 568 | 569 | scope 570 | .new_struct("Foo") 571 | .allow("dead_code") 572 | .allow("clippy::all") 573 | .field("one", "u8") 574 | .field("two", "u8"); 575 | 576 | let expect = r#" 577 | #[allow(dead_code)] 578 | #[allow(clippy::all)] 579 | struct Foo { 580 | one: u8, 581 | two: u8, 582 | }"#; 583 | 584 | assert_eq!(scope.to_string(), &expect[1..]); 585 | } 586 | 587 | #[test] 588 | fn enum_with_multiple_allow() { 589 | let mut scope = Scope::new(); 590 | 591 | scope 592 | .new_enum("IpAddrKind") 593 | .allow("dead_code") 594 | .allow("clippy::all") 595 | .push_variant(Variant::new("V4")) 596 | .push_variant(Variant::new("V6")); 597 | 598 | let expect = r#" 599 | #[allow(dead_code)] 600 | #[allow(clippy::all)] 601 | enum IpAddrKind { 602 | V4, 603 | V6, 604 | }"#; 605 | 606 | assert_eq!(scope.to_string(), &expect[1..]); 607 | } --------------------------------------------------------------------------------