Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions src/associated_constant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use std::fmt::{self, Write};
use crate::formatter::Formatter;

/// Defines an associated constant for use in impls and traits
#[derive(Clone, Debug)]
pub struct AssociatedConstant {
name: String,
datatype: crate::r#type::Type,
value: Option<String>,
}

impl AssociatedConstant {
/// Returns an associated constant with the given name and datatype
pub fn new<Datatype>(name: &str, datatype: Datatype) -> Self
where
Datatype: Into<crate::r#type::Type>
{
Self {
name: name.into(),
datatype: datatype.into(),
value: None,
}
}

/// Adds a value expression to the associated constant
pub fn value(&mut self, expression: &str) -> &mut Self {
self.value = Some(expression.to_string());
self
}

/// Formats the scope using the given formatter.
pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
let value_expression = match &self.value {
Some(expression) => format!(" = {};", expression),
None => ";".to_string(),
};
write!(fmt, "const {}: ", self.name)?;
self.datatype.fmt(fmt)?;
write!(fmt, "{}", value_expression)?;
Ok(())
}
}
30 changes: 30 additions & 0 deletions src/impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::bound::Bound;
use crate::field::Field;
use crate::formatter::{fmt_bounds, fmt_generics, Formatter};
use crate::function::Function;
use crate::associated_constant::AssociatedConstant;

use crate::r#type::Type;

Expand All @@ -19,6 +20,9 @@ pub struct Impl {
/// If implementing a trait
impl_trait: Option<Type>,

/// Associated constants
associated_constants: Vec<AssociatedConstant>,

/// Associated types
assoc_tys: Vec<Field>,

Expand All @@ -40,6 +44,7 @@ impl Impl {
target: target.into(),
generics: vec![],
impl_trait: None,
associated_constants: vec![],
assoc_tys: vec![],
bounds: vec![],
fns: vec![],
Expand Down Expand Up @@ -73,6 +78,24 @@ impl Impl {
self
}

/// Push an associated constant to the impl block
pub fn push_associated_constant(&mut self, constant: AssociatedConstant) -> &mut Self
{
self.associated_constants.push(constant);
self
}

/// Create an associated constant for the impl block
pub fn new_associated_constant<Type>(&mut self, name: &str, datatype: Type) -> &mut AssociatedConstant
where
Type: Into<crate::r#type::Type>
{
self.push_associated_constant(
AssociatedConstant::new(name, datatype));

self.associated_constants.last_mut().unwrap()
}

/// Add a macro to the impl block (e.g. `"#[async_trait]"`)
pub fn r#macro(&mut self, r#macro: &str) -> &mut Self {
self.macros.push(r#macro.to_string());
Expand Down Expand Up @@ -147,6 +170,13 @@ impl Impl {
}
}

if !self.associated_constants.is_empty() {
for constant in &self.associated_constants {
constant.fmt(fmt)?;
write!(fmt, "\n")?;
}
}

for (i, func) in self.fns.iter().enumerate() {
if i != 0 || !self.assoc_tys.is_empty() {
write!(fmt, "\n")?;
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
//! println!("{}", scope.to_string());
//! ```

mod associated_constant;
mod associated_type;
mod block;
mod body;
Expand All @@ -48,6 +49,7 @@ mod r#trait;
mod r#type;


pub use associated_constant::*;
pub use associated_type::*;
pub use block::*;
pub use field::*;
Expand Down
29 changes: 29 additions & 0 deletions src/trait.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fmt::{self, Write};

use crate::AssociatedConstant;
use crate::associated_type::AssociatedType;
use crate::bound::Bound;
use crate::formatter::{fmt_bound_rhs, Formatter};
Expand All @@ -14,6 +15,7 @@ pub struct Trait {
type_def: TypeDef,
parents: Vec<Type>,
associated_tys: Vec<AssociatedType>,
associated_constants: Vec<AssociatedConstant>,
fns: Vec<Function>,
macros: Vec<String>,
}
Expand All @@ -25,6 +27,7 @@ impl Trait {
type_def: TypeDef::new(name),
parents: vec![],
associated_tys: vec![],
associated_constants: vec![],
fns: vec![],
macros: vec![],
}
Expand Down Expand Up @@ -88,6 +91,25 @@ impl Trait {
self.associated_tys.last_mut().unwrap()
}

/// Push an associated constant to the trait block
pub fn push_associated_constant(&mut self, constant: AssociatedConstant) -> &mut Self
{
self.associated_constants.push(constant);
self
}


/// Create an associated constant for the trait block
pub fn new_associated_constant<Type>(&mut self, name: &str, datatype: Type) -> &mut AssociatedConstant
where
Type: Into<crate::r#type::Type>
{
self.push_associated_constant(
AssociatedConstant::new(name, datatype));

self.associated_constants.last_mut().unwrap()
}

/// Push a new function definition, returning a mutable reference to it.
pub fn new_fn(&mut self, name: &str) -> &mut Function {
let mut func = Function::new(name);
Expand Down Expand Up @@ -126,6 +148,13 @@ impl Trait {
}
}

if !self.associated_constants.is_empty() {
for constant in &self.associated_constants {
constant.fmt(fmt)?;
write!(fmt, "\n")?;
}
}

for (i, func) in self.fns.iter().enumerate() {
if i != 0 || !assoc.is_empty() {
write!(fmt, "\n")?;
Expand Down
48 changes: 48 additions & 0 deletions tests/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,5 +603,53 @@ enum IpAddrKind {
V6,
}"#;

assert_eq!(scope.to_string(), &expect[1..]);
}

#[test]
fn impl_with_associated_constants() {
let mut scope = Scope::new();

let constant1 = AssociatedConstant::new("BAR", "usize");
let mut constant2 = AssociatedConstant::new("BAZ", "i16");
constant2.value("22");

let current_impl = scope.new_impl("Foo")
.push_associated_constant(constant1)
.push_associated_constant(constant2);

current_impl.new_associated_constant("QUX", "usize").value("43");

let expect = r#"
impl Foo {
const BAR: usize;
const BAZ: i16 = 22;
const QUX: usize = 43;
}"#;

assert_eq!(scope.to_string(), &expect[1..]);
}

#[test]
fn trait_with_associated_constants() {
let mut scope = Scope::new();

let constant1 = AssociatedConstant::new("BAR", "usize");
let mut constant2 = AssociatedConstant::new("BAZ", "i16");
constant2.value("22");

let current_trait = scope.new_trait("Foo")
.push_associated_constant(constant1)
.push_associated_constant(constant2);

current_trait.new_associated_constant("QUX", "usize").value("43");

let expect = r#"
trait Foo {
const BAR: usize;
const BAZ: i16 = 22;
const QUX: usize = 43;
}"#;

assert_eq!(scope.to_string(), &expect[1..]);
}