use alloc::{string::String, vec::Vec};
use sails_idl_ast::{
Annotation, EnumDef, EnumVariant, StructDef, StructField, Type, TypeDecl, TypeDef,
TypeParameter,
};
#[derive(Debug, Clone)]
pub struct FieldBuilder<P> {
parent: P,
name: Option<String>,
metadata: Metadata,
}
#[derive(Debug, Clone)]
pub struct VariantBuilder {
parent: VariantDefBuilder,
name: String,
metadata: Metadata,
fields: Vec<StructField>,
}
#[derive(Debug, Clone)]
pub struct CompositeBuilder {
type_builder: TypeBuilder,
fields: Vec<StructField>,
}
#[derive(Debug, Clone)]
pub struct VariantDefBuilder {
type_builder: TypeBuilder,
variants: Vec<EnumVariant>,
}
#[derive(Debug, Clone)]
pub struct ParamBuilder {
inner: TypeBuilder,
param_name: String,
}
#[derive(Debug, Clone, Default)]
pub struct TypeBuilder {
name: String,
type_params: Vec<TypeParameter>,
metadata: Metadata,
}
#[derive(Debug, Clone, Default)]
struct Metadata {
docs: Vec<String>,
annotations: Vec<Annotation>,
}
pub trait PushField: Sized {
fn push_field(&mut self, field: StructField);
}
impl<P: PushField> FieldBuilder<P> {
pub fn ty(mut self, type_decl: TypeDecl) -> P {
self.parent.push_field(StructField {
name: self.name,
type_decl,
docs: self.metadata.docs,
annotations: self.metadata.annotations,
});
self.parent
}
}
impl<P> FieldBuilder<P> {
pub fn doc(mut self, doc: impl Into<String>) -> Self {
self.metadata.doc(doc);
self
}
pub fn annotate(mut self, name: impl Into<String>) -> Self {
self.metadata.annotate(name);
self
}
pub fn value(mut self, value: impl Into<String>) -> Self {
self.metadata.value(value);
self
}
}
impl VariantBuilder {
pub fn field(self, name: impl Into<String>) -> FieldBuilder<Self> {
FieldBuilder {
parent: self,
name: Some(name.into()),
metadata: Metadata::default(),
}
}
pub fn unnamed(self) -> FieldBuilder<Self> {
FieldBuilder {
parent: self,
name: None,
metadata: Metadata::default(),
}
}
pub fn doc(mut self, doc: impl Into<String>) -> Self {
self.metadata.doc(doc);
self
}
pub fn annotate(mut self, name: impl Into<String>) -> Self {
self.metadata.annotate(name);
self
}
pub fn value(mut self, value: impl Into<String>) -> Self {
self.metadata.value(value);
self
}
pub fn finish_variant(mut self) -> VariantDefBuilder {
self.parent.variants.push(EnumVariant {
name: self.name,
def: StructDef {
fields: self.fields,
},
entry_id: 0,
docs: self.metadata.docs,
annotations: self.metadata.annotations,
});
self.parent
}
}
impl CompositeBuilder {
pub fn field(self, name: impl Into<String>) -> FieldBuilder<Self> {
FieldBuilder {
parent: self,
name: Some(name.into()),
metadata: Metadata::default(),
}
}
pub fn unnamed(self) -> FieldBuilder<Self> {
FieldBuilder {
parent: self,
name: None,
metadata: Metadata::default(),
}
}
pub fn doc(mut self, doc: impl Into<String>) -> Self {
self.type_builder.metadata.doc(doc);
self
}
pub fn annotate(mut self, name: impl Into<String>) -> Self {
self.type_builder.metadata.annotate(name);
self
}
pub fn value(mut self, value: impl Into<String>) -> Self {
self.type_builder.metadata.value(value);
self
}
pub fn build(self) -> Type {
self.type_builder.build(TypeDef::Struct(StructDef {
fields: self.fields,
}))
}
}
impl VariantDefBuilder {
pub fn add_variant(self, name: impl Into<String>) -> VariantBuilder {
VariantBuilder {
parent: self,
name: name.into(),
metadata: Metadata::default(),
fields: Vec::new(),
}
}
pub fn build(self) -> Type {
self.type_builder.build(TypeDef::Enum(EnumDef {
variants: self.variants,
}))
}
}
impl ParamBuilder {
pub fn default_ty(mut self, type_decl: TypeDecl) -> TypeBuilder {
self.inner.type_params.push(TypeParameter {
name: self.param_name,
ty: Some(type_decl),
});
self.inner
}
pub fn no_default(mut self) -> TypeBuilder {
self.inner.type_params.push(TypeParameter {
name: self.param_name,
ty: None,
});
self.inner
}
}
impl TypeBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = name.into();
self
}
pub fn param(mut self, name: impl Into<String>) -> Self {
self.type_params.push(TypeParameter {
name: name.into(),
ty: None,
});
self
}
pub fn param_with_default(mut self, name: impl Into<String>, type_decl: TypeDecl) -> Self {
self.type_params.push(TypeParameter {
name: name.into(),
ty: Some(type_decl),
});
self
}
pub fn doc(mut self, doc: impl Into<String>) -> Self {
self.metadata.doc(doc);
self
}
pub fn annotate(mut self, name: impl Into<String>) -> Self {
self.metadata.annotate(name);
self
}
pub fn value(mut self, value: impl Into<String>) -> Self {
self.metadata.value(value);
self
}
pub fn composite(self) -> CompositeBuilder {
CompositeBuilder {
type_builder: self,
fields: Vec::new(),
}
}
pub fn variant(self) -> VariantDefBuilder {
VariantDefBuilder {
type_builder: self,
variants: Vec::new(),
}
}
pub fn alias(self, target: TypeDecl) -> Type {
self.build(TypeDef::Alias(sails_idl_ast::AliasDef { target }))
}
fn build(self, def: TypeDef) -> Type {
Type {
name: self.name,
type_params: self.type_params,
def,
docs: self.metadata.docs,
annotations: self.metadata.annotations,
}
}
}
impl Metadata {
fn doc(&mut self, doc: impl Into<String>) {
self.docs.push(doc.into());
}
fn annotate(&mut self, name: impl Into<String>) {
self.annotations.push((name.into(), None));
}
fn value(&mut self, value: impl Into<String>) {
if let Some(ann) = self.annotations.last_mut() {
ann.1 = Some(value.into());
}
}
}
impl PushField for CompositeBuilder {
fn push_field(&mut self, field: StructField) {
self.fields.push(field);
}
}
impl PushField for VariantBuilder {
fn push_field(&mut self, field: StructField) {
self.fields.push(field);
}
}