use crate::prelude::{
marker::PhantomData,
vec::Vec,
};
use crate::{
form::MetaForm,
Field,
MetaType,
Path,
Type,
TypeDef,
TypeDefComposite,
TypeDefVariant,
TypeInfo,
TypeParameter,
Variant,
};
pub mod state {
pub enum PathNotAssigned {}
pub enum PathAssigned {}
}
#[must_use]
pub struct TypeBuilder<S = state::PathNotAssigned> {
path: Option<Path>,
type_params: Vec<TypeParameter>,
docs: Vec<&'static str>,
marker: PhantomData<fn() -> S>,
}
impl<S> Default for TypeBuilder<S> {
fn default() -> Self {
TypeBuilder {
path: Default::default(),
type_params: Default::default(),
docs: Default::default(),
marker: Default::default(),
}
}
}
impl TypeBuilder<state::PathNotAssigned> {
pub fn path(self, path: Path) -> TypeBuilder<state::PathAssigned> {
TypeBuilder {
path: Some(path),
type_params: self.type_params,
docs: self.docs,
marker: Default::default(),
}
}
}
impl TypeBuilder<state::PathAssigned> {
fn build<D>(self, type_def: D) -> Type
where
D: Into<TypeDef>,
{
let path = self.path.expect("Path not assigned");
Type::new(path, self.type_params, type_def, self.docs)
}
pub fn variant(self, builder: Variants) -> Type {
self.build(builder.finalize())
}
pub fn composite<F>(self, fields: FieldsBuilder<F>) -> Type {
self.build(TypeDefComposite::new(fields.finalize()))
}
}
impl<S> TypeBuilder<S> {
pub fn type_params<I>(mut self, type_params: I) -> Self
where
I: IntoIterator<Item = TypeParameter>,
{
self.type_params = type_params.into_iter().collect();
self
}
#[cfg(feature = "docs")]
pub fn docs(mut self, docs: &[&'static str]) -> Self {
self.docs = docs.to_vec();
self
}
#[cfg(not(feature = "docs"))]
#[inline]
pub fn docs(self, _docs: &'static [&'static str]) -> Self {
self
}
pub fn docs_always(mut self, docs: &[&'static str]) -> Self {
self.docs = docs.to_vec();
self
}
}
pub enum NoFields {}
pub enum NamedFields {}
pub enum UnnamedFields {}
pub enum Fields {}
impl Fields {
pub fn unit() -> FieldsBuilder<NoFields> {
FieldsBuilder::<NoFields>::default()
}
pub fn named() -> FieldsBuilder<NamedFields> {
FieldsBuilder::default()
}
pub fn unnamed() -> FieldsBuilder<UnnamedFields> {
FieldsBuilder::default()
}
}
#[must_use]
pub struct FieldsBuilder<T> {
fields: Vec<Field>,
marker: PhantomData<fn() -> T>,
}
impl<T> Default for FieldsBuilder<T> {
fn default() -> Self {
Self {
fields: Vec::new(),
marker: Default::default(),
}
}
}
impl<T> FieldsBuilder<T> {
pub fn finalize(self) -> Vec<Field<MetaForm>> {
self.fields
}
fn push_field(mut self, field: Field) -> Self {
if !field.ty().is_phantom() {
self.fields.push(field);
}
self
}
}
impl FieldsBuilder<NamedFields> {
pub fn field<F>(self, builder: F) -> Self
where
F: Fn(
FieldBuilder,
)
-> FieldBuilder<field_state::NameAssigned, field_state::TypeAssigned>,
{
let builder = builder(FieldBuilder::new());
self.push_field(builder.finalize())
}
}
impl FieldsBuilder<UnnamedFields> {
pub fn field<F>(self, builder: F) -> Self
where
F: Fn(
FieldBuilder,
)
-> FieldBuilder<field_state::NameNotAssigned, field_state::TypeAssigned>,
{
let builder = builder(FieldBuilder::new());
self.push_field(builder.finalize())
}
}
pub mod field_state {
pub enum NameNotAssigned {}
pub enum NameAssigned {}
pub enum TypeNotAssigned {}
pub enum TypeAssigned {}
}
#[must_use]
pub struct FieldBuilder<
N = field_state::NameNotAssigned,
T = field_state::TypeNotAssigned,
> {
name: Option<&'static str>,
ty: Option<MetaType>,
type_name: Option<&'static str>,
docs: &'static [&'static str],
marker: PhantomData<fn() -> (N, T)>,
}
impl<N, T> Default for FieldBuilder<N, T> {
fn default() -> Self {
FieldBuilder {
name: Default::default(),
ty: Default::default(),
type_name: Default::default(),
docs: Default::default(),
marker: Default::default(),
}
}
}
impl FieldBuilder {
pub fn new() -> Self {
Default::default()
}
}
impl<T> FieldBuilder<field_state::NameNotAssigned, T> {
pub fn name(self, name: &'static str) -> FieldBuilder<field_state::NameAssigned, T> {
FieldBuilder {
name: Some(name),
ty: self.ty,
type_name: self.type_name,
docs: self.docs,
marker: PhantomData,
}
}
}
impl<N> FieldBuilder<N, field_state::TypeNotAssigned> {
pub fn ty<TY>(self) -> FieldBuilder<N, field_state::TypeAssigned>
where
TY: TypeInfo + 'static + ?Sized,
{
FieldBuilder {
name: self.name,
ty: Some(MetaType::new::<TY>()),
type_name: self.type_name,
docs: self.docs,
marker: PhantomData,
}
}
pub fn compact<TY>(self) -> FieldBuilder<N, field_state::TypeAssigned>
where
TY: scale::HasCompact + TypeInfo + 'static,
{
FieldBuilder {
name: self.name,
ty: Some(MetaType::new::<scale::Compact<TY>>()),
type_name: self.type_name,
docs: self.docs,
marker: PhantomData,
}
}
}
impl<N, T> FieldBuilder<N, T> {
pub fn type_name(self, type_name: &'static str) -> FieldBuilder<N, T> {
FieldBuilder {
name: self.name,
ty: self.ty,
type_name: Some(type_name),
docs: self.docs,
marker: PhantomData,
}
}
#[cfg(feature = "docs")]
pub fn docs(self, docs: &'static [&'static str]) -> FieldBuilder<N, T> {
FieldBuilder {
name: self.name,
ty: self.ty,
type_name: self.type_name,
docs,
marker: PhantomData,
}
}
#[cfg(not(feature = "docs"))]
#[inline]
pub fn docs(self, _docs: &'static [&'static str]) -> FieldBuilder<N, T> {
self
}
pub fn docs_always(self, docs: &'static [&'static str]) -> Self {
FieldBuilder {
name: self.name,
ty: self.ty,
type_name: self.type_name,
docs,
marker: PhantomData,
}
}
}
impl<N> FieldBuilder<N, field_state::TypeAssigned> {
pub fn finalize(self) -> Field<MetaForm> {
Field::new(
self.name,
self.ty.expect("Type should be set by builder"),
self.type_name,
self.docs,
)
}
}
#[derive(Default)]
#[must_use]
pub struct Variants {
variants: Vec<Variant>,
}
impl Variants {
pub fn new() -> Self {
Variants {
variants: Vec::new(),
}
}
pub fn variant<F>(mut self, name: &'static str, builder: F) -> Self
where
F: Fn(VariantBuilder) -> VariantBuilder<variant_state::IndexAssigned>,
{
let builder = builder(VariantBuilder::new(name));
self.variants.push(builder.finalize());
self
}
pub fn variant_unit(mut self, name: &'static str, index: u8) -> Self {
let builder = VariantBuilder::new(name).index(index);
self.variants.push(builder.finalize());
self
}
pub fn finalize(self) -> TypeDefVariant {
TypeDefVariant::new(self.variants)
}
}
pub mod variant_state {
pub enum IndexNotAssigned {}
pub enum IndexAssigned {}
}
#[must_use]
pub struct VariantBuilder<S = variant_state::IndexNotAssigned> {
name: &'static str,
index: Option<u8>,
fields: Vec<Field<MetaForm>>,
discriminant: Option<u64>,
docs: Vec<&'static str>,
marker: PhantomData<S>,
}
impl VariantBuilder<variant_state::IndexNotAssigned> {
pub fn new(name: &'static str) -> Self {
Self {
name,
fields: Vec::new(),
discriminant: None,
index: None,
docs: Vec::new(),
marker: Default::default(),
}
}
pub fn index(self, index: u8) -> VariantBuilder<variant_state::IndexAssigned> {
VariantBuilder {
name: self.name,
index: Some(index),
fields: self.fields,
discriminant: self.discriminant,
docs: self.docs,
marker: Default::default(),
}
}
}
impl<S> VariantBuilder<S> {
pub fn discriminant(mut self, discriminant: u64) -> Self {
self.discriminant = Some(discriminant);
self
}
pub fn fields<F>(mut self, fields_builder: FieldsBuilder<F>) -> Self {
self.fields = fields_builder.finalize();
self
}
#[cfg(feature = "docs")]
pub fn docs(mut self, docs: &[&'static str]) -> Self {
self.docs = docs.to_vec();
self
}
#[cfg(not(feature = "docs"))]
#[inline]
pub fn docs(self, _docs: &[&'static str]) -> Self {
self
}
pub fn docs_always(mut self, docs: &[&'static str]) -> Self {
self.docs = docs.to_vec();
self
}
}
impl VariantBuilder<variant_state::IndexAssigned> {
pub fn finalize(self) -> Variant<MetaForm> {
Variant::new(
self.name,
self.fields,
self.index.expect("Index should be assigned by the builder"),
self.docs,
)
}
}