#![allow(clippy::new_ret_no_self)]
use crate::serde_hex;
#[cfg(not(feature = "std"))]
use alloc::{
format,
vec,
vec::Vec,
};
use core::marker::PhantomData;
use tetsy_scale_info::{
form::{
Form,
MetaForm,
PortableForm,
},
meta_type,
IntoPortable,
Registry,
TypeInfo,
};
use serde::{
de::DeserializeOwned,
Deserialize,
Serialize,
};
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound(
serialize = "F::Type: Serialize, F::String: Serialize",
deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
))]
pub struct ContractSpec<F: Form = MetaForm> {
constructors: Vec<ConstructorSpec<F>>,
messages: Vec<MessageSpec<F>>,
events: Vec<EventSpec<F>>,
docs: Vec<F::String>,
}
impl IntoPortable for ContractSpec {
type Output = ContractSpec<PortableForm>;
fn into_portable(self, registry: &mut Registry) -> Self::Output {
ContractSpec {
constructors: self
.constructors
.into_iter()
.map(|constructor| constructor.into_portable(registry))
.collect::<Vec<_>>(),
messages: self
.messages
.into_iter()
.map(|msg| msg.into_portable(registry))
.collect::<Vec<_>>(),
events: self
.events
.into_iter()
.map(|event| event.into_portable(registry))
.collect::<Vec<_>>(),
docs: registry.map_into_portable(self.docs),
}
}
}
impl<F> ContractSpec<F>
where
F: Form,
{
pub fn constructors(&self) -> &[ConstructorSpec<F>] {
&self.constructors
}
pub fn messages(&self) -> &[MessageSpec<F>] {
&self.messages
}
pub fn events(&self) -> &[EventSpec<F>] {
&self.events
}
pub fn docs(&self) -> &[F::String] {
&self.docs
}
}
pub enum Valid {}
pub enum Invalid {}
pub struct ContractSpecBuilder<S = Invalid> {
spec: ContractSpec,
marker: PhantomData<fn() -> S>,
}
impl ContractSpecBuilder<Invalid> {
pub fn constructors<C>(self, constructors: C) -> ContractSpecBuilder<Valid>
where
C: IntoIterator<Item = ConstructorSpec>,
{
debug_assert!(self.spec.constructors.is_empty());
ContractSpecBuilder {
spec: ContractSpec {
constructors: constructors.into_iter().collect::<Vec<_>>(),
..self.spec
},
marker: Default::default(),
}
}
}
impl<S> ContractSpecBuilder<S> {
pub fn messages<M>(self, messages: M) -> Self
where
M: IntoIterator<Item = MessageSpec>,
{
debug_assert!(self.spec.messages.is_empty());
Self {
spec: ContractSpec {
messages: messages.into_iter().collect::<Vec<_>>(),
..self.spec
},
..self
}
}
pub fn events<E>(self, events: E) -> Self
where
E: IntoIterator<Item = EventSpec>,
{
debug_assert!(self.spec.events.is_empty());
Self {
spec: ContractSpec {
events: events.into_iter().collect::<Vec<_>>(),
..self.spec
},
..self
}
}
pub fn docs<D>(self, docs: D) -> Self
where
D: IntoIterator<Item = &'static str>,
{
debug_assert!(self.spec.docs.is_empty());
Self {
spec: ContractSpec {
docs: docs.into_iter().collect::<Vec<_>>(),
..self.spec
},
..self
}
}
}
impl ContractSpecBuilder<Valid> {
pub fn done(self) -> ContractSpec {
assert!(
!self.spec.constructors.is_empty(),
"must have at least one constructor"
);
assert!(
!self.spec.messages.is_empty(),
"must have at least one message"
);
self.spec
}
}
impl ContractSpec {
pub fn new() -> ContractSpecBuilder {
ContractSpecBuilder {
spec: Self {
constructors: Vec::new(),
messages: Vec::new(),
events: Vec::new(),
docs: Vec::new(),
},
marker: PhantomData,
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound(
serialize = "F::Type: Serialize, F::String: Serialize",
deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
))]
pub struct ConstructorSpec<F: Form = MetaForm> {
pub name: Vec<F::String>,
pub selector: Selector,
pub args: Vec<MessageParamSpec<F>>,
pub docs: Vec<F::String>,
}
impl IntoPortable for ConstructorSpec {
type Output = ConstructorSpec<PortableForm>;
fn into_portable(self, registry: &mut Registry) -> Self::Output {
ConstructorSpec {
name: registry.map_into_portable(self.name),
selector: self.selector,
args: self
.args
.into_iter()
.map(|arg| arg.into_portable(registry))
.collect::<Vec<_>>(),
docs: registry.map_into_portable(self.docs),
}
}
}
impl<F> ConstructorSpec<F>
where
F: Form,
{
pub fn name(&self) -> &[F::String] {
&self.name
}
pub fn selector(&self) -> &Selector {
&self.selector
}
pub fn args(&self) -> &[MessageParamSpec<F>] {
&self.args
}
pub fn docs(&self) -> &[F::String] {
&self.docs
}
}
pub struct ConstructorSpecBuilder<Selector> {
spec: ConstructorSpec,
marker: PhantomData<fn() -> Selector>,
}
impl ConstructorSpec {
fn from_name_segments(
segments: Vec<&'static str>,
) -> ConstructorSpecBuilder<Missing<state::Selector>> {
ConstructorSpecBuilder {
spec: Self {
name: segments,
selector: Selector::default(),
args: Vec::new(),
docs: Vec::new(),
},
marker: PhantomData,
}
}
pub fn from_name(
name: &'static str,
) -> ConstructorSpecBuilder<Missing<state::Selector>> {
Self::from_name_segments(vec![name])
}
pub fn from_trait_and_name(
trait_name: &'static str,
constructor_name: &'static str,
) -> ConstructorSpecBuilder<Missing<state::Selector>> {
Self::from_name_segments(vec![trait_name, constructor_name])
}
}
impl ConstructorSpecBuilder<Missing<state::Selector>> {
pub fn selector(self, selector: [u8; 4]) -> ConstructorSpecBuilder<state::Selector> {
ConstructorSpecBuilder {
spec: ConstructorSpec {
selector: selector.into(),
..self.spec
},
marker: PhantomData,
}
}
}
impl<S> ConstructorSpecBuilder<S> {
pub fn args<A>(self, args: A) -> Self
where
A: IntoIterator<Item = MessageParamSpec>,
{
let mut this = self;
debug_assert!(this.spec.args.is_empty());
this.spec.args = args.into_iter().collect::<Vec<_>>();
this
}
pub fn docs<D>(self, docs: D) -> Self
where
D: IntoIterator<Item = &'static str>,
{
let mut this = self;
debug_assert!(this.spec.docs.is_empty());
this.spec.docs = docs.into_iter().map(str::trim).collect::<Vec<_>>();
this
}
}
impl ConstructorSpecBuilder<state::Selector> {
pub fn done(self) -> ConstructorSpec {
self.spec
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound(
serialize = "F::Type: Serialize, F::String: Serialize",
deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
))]
#[serde(rename_all = "camelCase")]
pub struct MessageSpec<F: Form = MetaForm> {
name: Vec<F::String>,
selector: Selector,
mutates: bool,
payable: bool,
args: Vec<MessageParamSpec<F>>,
return_type: ReturnTypeSpec<F>,
docs: Vec<F::String>,
}
pub struct Missing<S>(PhantomData<fn() -> S>);
mod state {
pub struct Selector;
pub struct Mutates;
pub struct IsPayable;
pub struct Returns;
}
impl MessageSpec {
fn from_name_segments(
segments: Vec<&'static str>,
) -> MessageSpecBuilder<
Missing<state::Selector>,
Missing<state::Mutates>,
Missing<state::IsPayable>,
Missing<state::Returns>,
> {
MessageSpecBuilder {
spec: Self {
name: segments,
selector: Selector::default(),
mutates: false,
payable: false,
args: Vec::new(),
return_type: ReturnTypeSpec::new(None),
docs: Vec::new(),
},
marker: PhantomData,
}
}
pub fn from_name(
name: &'static str,
) -> MessageSpecBuilder<
Missing<state::Selector>,
Missing<state::Mutates>,
Missing<state::IsPayable>,
Missing<state::Returns>,
> {
Self::from_name_segments(vec![name])
}
pub fn from_trait_and_name(
trait_name: &'static str,
message_name: &'static str,
) -> MessageSpecBuilder<
Missing<state::Selector>,
Missing<state::Mutates>,
Missing<state::IsPayable>,
Missing<state::Returns>,
> {
Self::from_name_segments(vec![trait_name, message_name])
}
}
impl<F> MessageSpec<F>
where
F: Form,
{
pub fn name(&self) -> &[F::String] {
&self.name
}
pub fn selector(&self) -> &Selector {
&self.selector
}
pub fn mutates(&self) -> bool {
self.mutates
}
pub fn payable(&self) -> bool {
self.payable
}
pub fn args(&self) -> &[MessageParamSpec<F>] {
&self.args
}
pub fn return_type(&self) -> &ReturnTypeSpec<F> {
&self.return_type
}
pub fn docs(&self) -> &[F::String] {
&self.docs
}
}
#[allow(clippy::type_complexity)]
pub struct MessageSpecBuilder<Selector, Mutates, IsPayable, Returns> {
spec: MessageSpec,
marker: PhantomData<fn() -> (Selector, Mutates, IsPayable, Returns)>,
}
impl<M, P, R> MessageSpecBuilder<Missing<state::Selector>, M, P, R> {
pub fn selector(
self,
selector: [u8; 4],
) -> MessageSpecBuilder<state::Selector, M, P, R> {
MessageSpecBuilder {
spec: MessageSpec {
selector: selector.into(),
..self.spec
},
marker: PhantomData,
}
}
}
impl<S, P, R> MessageSpecBuilder<S, Missing<state::Mutates>, P, R> {
pub fn mutates(self, mutates: bool) -> MessageSpecBuilder<S, state::Mutates, P, R> {
MessageSpecBuilder {
spec: MessageSpec {
mutates,
..self.spec
},
marker: PhantomData,
}
}
}
impl<S, M, R> MessageSpecBuilder<S, M, Missing<state::IsPayable>, R> {
pub fn payable(
self,
is_payable: bool,
) -> MessageSpecBuilder<S, M, state::IsPayable, R> {
MessageSpecBuilder {
spec: MessageSpec {
payable: is_payable,
..self.spec
},
marker: PhantomData,
}
}
}
impl<M, S, P> MessageSpecBuilder<S, M, P, Missing<state::Returns>> {
pub fn returns(
self,
return_type: ReturnTypeSpec,
) -> MessageSpecBuilder<S, M, P, state::Returns> {
MessageSpecBuilder {
spec: MessageSpec {
return_type,
..self.spec
},
marker: PhantomData,
}
}
}
impl<S, M, P, R> MessageSpecBuilder<S, M, P, R> {
pub fn args<A>(self, args: A) -> Self
where
A: IntoIterator<Item = MessageParamSpec>,
{
let mut this = self;
debug_assert!(this.spec.args.is_empty());
this.spec.args = args.into_iter().collect::<Vec<_>>();
this
}
pub fn docs<D>(self, docs: D) -> Self
where
D: IntoIterator<Item = &'static str>,
{
let mut this = self;
debug_assert!(this.spec.docs.is_empty());
this.spec.docs = docs.into_iter().collect::<Vec<_>>();
this
}
}
impl
MessageSpecBuilder<state::Selector, state::Mutates, state::IsPayable, state::Returns>
{
pub fn done(self) -> MessageSpec {
self.spec
}
}
impl IntoPortable for MessageSpec {
type Output = MessageSpec<PortableForm>;
fn into_portable(self, registry: &mut Registry) -> Self::Output {
MessageSpec {
name: registry.map_into_portable(self.name),
selector: self.selector,
mutates: self.mutates,
payable: self.payable,
args: self
.args
.into_iter()
.map(|arg| arg.into_portable(registry))
.collect::<Vec<_>>(),
return_type: self.return_type.into_portable(registry),
docs: registry.map_into_portable(self.docs),
}
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound(
serialize = "F::Type: Serialize, F::String: Serialize",
deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
))]
pub struct EventSpec<F: Form = MetaForm> {
name: F::String,
args: Vec<EventParamSpec<F>>,
docs: Vec<F::String>,
}
pub struct EventSpecBuilder {
spec: EventSpec,
}
impl EventSpecBuilder {
pub fn args<A>(self, args: A) -> Self
where
A: IntoIterator<Item = EventParamSpec>,
{
let mut this = self;
debug_assert!(this.spec.args.is_empty());
this.spec.args = args.into_iter().collect::<Vec<_>>();
this
}
pub fn docs<D>(self, docs: D) -> Self
where
D: IntoIterator<Item = &'static str>,
{
let mut this = self;
debug_assert!(this.spec.docs.is_empty());
this.spec.docs = docs.into_iter().collect::<Vec<_>>();
this
}
pub fn done(self) -> EventSpec {
self.spec
}
}
impl IntoPortable for EventSpec {
type Output = EventSpec<PortableForm>;
fn into_portable(self, registry: &mut Registry) -> Self::Output {
EventSpec {
name: self.name.into_portable(registry),
args: self
.args
.into_iter()
.map(|arg| arg.into_portable(registry))
.collect::<Vec<_>>(),
docs: registry.map_into_portable(self.docs),
}
}
}
impl EventSpec {
pub fn new(name: &'static str) -> EventSpecBuilder {
EventSpecBuilder {
spec: Self {
name,
args: Vec::new(),
docs: Vec::new(),
},
}
}
}
impl<F> EventSpec<F>
where
F: Form,
{
pub fn name(&self) -> &F::String {
&self.name
}
pub fn args(&self) -> &[EventParamSpec<F>] {
&self.args
}
pub fn docs(&self) -> &[F::String] {
&self.docs
}
}
#[derive(Debug, Default, PartialEq, Eq, derive_more::From)]
pub struct Selector([u8; 4]);
impl serde::Serialize for Selector {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde_hex::serialize(&self.0, serializer)
}
}
impl<'de> serde::Deserialize<'de> for Selector {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut arr = [0; 4];
serde_hex::deserialize_check_len(d, serde_hex::ExpectedLen::Exact(&mut arr[..]))?;
Ok(arr.into())
}
}
impl Selector {
pub fn to_bytes(&self) -> &[u8] {
&self.0
}
}
pub type DisplayName<F> = tetsy_scale_info::Path<F>;
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound(
serialize = "F::Type: Serialize, F::String: Serialize",
deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
))]
#[serde(rename_all = "camelCase")]
pub struct TypeSpec<F: Form = MetaForm> {
#[serde(rename = "type")]
ty: F::Type,
display_name: DisplayName<F>,
}
impl IntoPortable for TypeSpec {
type Output = TypeSpec<PortableForm>;
fn into_portable(self, registry: &mut Registry) -> Self::Output {
TypeSpec {
ty: registry.register_type(&self.ty),
display_name: self.display_name.into_portable(registry),
}
}
}
impl TypeSpec {
pub fn with_name_str<T>(display_name: &'static str) -> Self
where
T: TypeInfo + 'static,
{
Self::with_name_segs::<T, _>(display_name.split("::"))
}
pub fn with_name_segs<T, S>(segments: S) -> Self
where
T: TypeInfo + 'static,
S: IntoIterator<Item = &'static str>,
{
Self {
ty: meta_type::<T>(),
display_name: DisplayName::from_segments(segments)
.expect("display name is invalid"),
}
}
pub fn new<T>() -> Self
where
T: TypeInfo + 'static,
{
Self {
ty: meta_type::<T>(),
display_name: DisplayName::default(),
}
}
}
impl<F> TypeSpec<F>
where
F: Form,
{
pub fn ty(&self) -> &F::Type {
&self.ty
}
pub fn display_name(&self) -> &DisplayName<F> {
&self.display_name
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound(
serialize = "F::Type: Serialize, F::String: Serialize",
deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
))]
pub struct EventParamSpec<F: Form = MetaForm> {
name: F::String,
indexed: bool,
#[serde(rename = "type")]
ty: TypeSpec<F>,
docs: Vec<F::String>,
}
impl IntoPortable for EventParamSpec {
type Output = EventParamSpec<PortableForm>;
fn into_portable(self, registry: &mut Registry) -> Self::Output {
EventParamSpec {
name: self.name.into_portable(registry),
indexed: self.indexed,
ty: self.ty.into_portable(registry),
docs: registry.map_into_portable(self.docs),
}
}
}
impl EventParamSpec {
pub fn new(name: &'static str) -> EventParamSpecBuilder {
EventParamSpecBuilder {
spec: Self {
name,
indexed: false,
ty: TypeSpec::new::<()>(),
docs: vec![],
},
}
}
}
impl<F> EventParamSpec<F>
where
F: Form,
{
pub fn name(&self) -> &F::String {
&self.name
}
pub fn indexed(&self) -> bool {
self.indexed
}
pub fn ty(&self) -> &TypeSpec<F> {
&self.ty
}
pub fn docs(&self) -> &[F::String] {
&self.docs
}
}
pub struct EventParamSpecBuilder {
spec: EventParamSpec,
}
impl EventParamSpecBuilder {
pub fn of_type(self, spec: TypeSpec) -> Self {
let mut this = self;
this.spec.ty = spec;
this
}
pub fn indexed(self, is_indexed: bool) -> Self {
let mut this = self;
this.spec.indexed = is_indexed;
this
}
pub fn docs<D>(self, docs: D) -> Self
where
D: IntoIterator<Item = &'static str>,
{
debug_assert!(self.spec.docs.is_empty());
Self {
spec: EventParamSpec {
docs: docs.into_iter().collect::<Vec<_>>(),
..self.spec
},
}
}
pub fn done(self) -> EventParamSpec {
self.spec
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
#[serde(bound(
serialize = "F::Type: Serialize, F::String: Serialize",
deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
))]
pub struct ReturnTypeSpec<F: Form = MetaForm> {
#[serde(rename = "type")]
opt_type: Option<TypeSpec<F>>,
}
impl IntoPortable for ReturnTypeSpec {
type Output = ReturnTypeSpec<PortableForm>;
fn into_portable(self, registry: &mut Registry) -> Self::Output {
ReturnTypeSpec {
opt_type: self
.opt_type
.map(|opt_type| opt_type.into_portable(registry)),
}
}
}
impl ReturnTypeSpec {
pub fn new<T>(ty: T) -> Self
where
T: Into<Option<TypeSpec>>,
{
Self {
opt_type: ty.into(),
}
}
}
impl<F> ReturnTypeSpec<F>
where
F: Form,
{
pub fn opt_type(&self) -> Option<&TypeSpec<F>> {
self.opt_type.as_ref()
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound(
serialize = "F::Type: Serialize, F::String: Serialize",
deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
))]
pub struct MessageParamSpec<F: Form = MetaForm> {
name: F::String,
#[serde(rename = "type")]
ty: TypeSpec<F>,
}
impl IntoPortable for MessageParamSpec {
type Output = MessageParamSpec<PortableForm>;
fn into_portable(self, registry: &mut Registry) -> Self::Output {
MessageParamSpec {
name: self.name.into_portable(registry),
ty: self.ty.into_portable(registry),
}
}
}
impl MessageParamSpec {
pub fn new(name: &'static str) -> MessageParamSpecBuilder {
MessageParamSpecBuilder {
spec: Self {
name,
ty: TypeSpec::new::<()>(),
},
}
}
}
impl<F> MessageParamSpec<F>
where
F: Form,
{
pub fn name(&self) -> &F::String {
&self.name
}
pub fn ty(&self) -> &TypeSpec<F> {
&self.ty
}
}
pub struct MessageParamSpecBuilder {
spec: MessageParamSpec,
}
impl MessageParamSpecBuilder {
pub fn of_type(self, ty: TypeSpec) -> Self {
let mut this = self;
this.spec.ty = ty;
this
}
pub fn done(self) -> MessageParamSpec {
self.spec
}
}