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