diff --git a/Makefile b/Makefile
index 74915ea..edd1f00 100644
--- a/Makefile
+++ b/Makefile
@@ -6,6 +6,7 @@ all:
mol:
moleculec --language rust --schema-file schemas/basic.mol > ckb-typed-message/src/schemas/basic.rs
moleculec --language rust --schema-file schemas/top_level.mol > ckb-typed-message/src/schemas/top_level.rs
+ moleculec --language rust --schema-file schemas/spore.mol > ckb-typed-message/src/schemas/spore.rs
cargo fmt
install:
diff --git a/ckb-typed-message/src/schemas/basic.rs b/ckb-typed-message/src/schemas/basic.rs
index b796a9c..f95e485 100644
--- a/ckb-typed-message/src/schemas/basic.rs
+++ b/ckb-typed-message/src/schemas/basic.rs
@@ -513,6 +513,170 @@ impl<'r> AddressUnionReader<'r> {
}
}
#[derive(Clone)]
+pub struct AddressOpt(molecule::bytes::Bytes);
+impl ::core::fmt::LowerHex for AddressOpt {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ use molecule::hex_string;
+ if f.alternate() {
+ write!(f, "0x")?;
+ }
+ write!(f, "{}", hex_string(self.as_slice()))
+ }
+}
+impl ::core::fmt::Debug for AddressOpt {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}({:#x})", Self::NAME, self)
+ }
+}
+impl ::core::fmt::Display for AddressOpt {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(v) = self.to_opt() {
+ write!(f, "{}(Some({}))", Self::NAME, v)
+ } else {
+ write!(f, "{}(None)", Self::NAME)
+ }
+ }
+}
+impl ::core::default::Default for AddressOpt {
+ fn default() -> Self {
+ let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE);
+ AddressOpt::new_unchecked(v)
+ }
+}
+impl AddressOpt {
+ const DEFAULT_VALUE: [u8; 0] = [];
+ pub fn is_none(&self) -> bool {
+ self.0.is_empty()
+ }
+ pub fn is_some(&self) -> bool {
+ !self.0.is_empty()
+ }
+ pub fn to_opt(&self) -> Option
{
+ if self.is_none() {
+ None
+ } else {
+ Some(Address::new_unchecked(self.0.clone()))
+ }
+ }
+ pub fn as_reader<'r>(&'r self) -> AddressOptReader<'r> {
+ AddressOptReader::new_unchecked(self.as_slice())
+ }
+}
+impl molecule::prelude::Entity for AddressOpt {
+ type Builder = AddressOptBuilder;
+ const NAME: &'static str = "AddressOpt";
+ fn new_unchecked(data: molecule::bytes::Bytes) -> Self {
+ AddressOpt(data)
+ }
+ fn as_bytes(&self) -> molecule::bytes::Bytes {
+ self.0.clone()
+ }
+ fn as_slice(&self) -> &[u8] {
+ &self.0[..]
+ }
+ fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult {
+ AddressOptReader::from_slice(slice).map(|reader| reader.to_entity())
+ }
+ fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult {
+ AddressOptReader::from_compatible_slice(slice).map(|reader| reader.to_entity())
+ }
+ fn new_builder() -> Self::Builder {
+ ::core::default::Default::default()
+ }
+ fn as_builder(self) -> Self::Builder {
+ Self::new_builder().set(self.to_opt())
+ }
+}
+#[derive(Clone, Copy)]
+pub struct AddressOptReader<'r>(&'r [u8]);
+impl<'r> ::core::fmt::LowerHex for AddressOptReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ use molecule::hex_string;
+ if f.alternate() {
+ write!(f, "0x")?;
+ }
+ write!(f, "{}", hex_string(self.as_slice()))
+ }
+}
+impl<'r> ::core::fmt::Debug for AddressOptReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}({:#x})", Self::NAME, self)
+ }
+}
+impl<'r> ::core::fmt::Display for AddressOptReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ if let Some(v) = self.to_opt() {
+ write!(f, "{}(Some({}))", Self::NAME, v)
+ } else {
+ write!(f, "{}(None)", Self::NAME)
+ }
+ }
+}
+impl<'r> AddressOptReader<'r> {
+ pub fn is_none(&self) -> bool {
+ self.0.is_empty()
+ }
+ pub fn is_some(&self) -> bool {
+ !self.0.is_empty()
+ }
+ pub fn to_opt(&self) -> Option> {
+ if self.is_none() {
+ None
+ } else {
+ Some(AddressReader::new_unchecked(self.as_slice()))
+ }
+ }
+}
+impl<'r> molecule::prelude::Reader<'r> for AddressOptReader<'r> {
+ type Entity = AddressOpt;
+ const NAME: &'static str = "AddressOptReader";
+ fn to_entity(&self) -> Self::Entity {
+ Self::Entity::new_unchecked(self.as_slice().to_owned().into())
+ }
+ fn new_unchecked(slice: &'r [u8]) -> Self {
+ AddressOptReader(slice)
+ }
+ fn as_slice(&self) -> &'r [u8] {
+ self.0
+ }
+ fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> {
+ if !slice.is_empty() {
+ AddressReader::verify(&slice[..], compatible)?;
+ }
+ Ok(())
+ }
+}
+#[derive(Debug, Default)]
+pub struct AddressOptBuilder(pub(crate) Option);
+impl AddressOptBuilder {
+ pub fn set(mut self, v: Option) -> Self {
+ self.0 = v;
+ self
+ }
+}
+impl molecule::prelude::Builder for AddressOptBuilder {
+ type Entity = AddressOpt;
+ const NAME: &'static str = "AddressOptBuilder";
+ fn expected_length(&self) -> usize {
+ self.0
+ .as_ref()
+ .map(|ref inner| inner.as_slice().len())
+ .unwrap_or(0)
+ }
+ fn write(&self, writer: &mut W) -> molecule::io::Result<()> {
+ self.0
+ .as_ref()
+ .map(|ref inner| writer.write_all(inner.as_slice()))
+ .unwrap_or(Ok(()))
+ }
+ fn build(&self) -> Self::Entity {
+ let mut inner = Vec::with_capacity(self.expected_length());
+ self.write(&mut inner)
+ .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME));
+ AddressOpt::new_unchecked(inner.into())
+ }
+}
+#[derive(Clone)]
pub struct Action(molecule::bytes::Bytes);
impl ::core::fmt::LowerHex for Action {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
diff --git a/ckb-typed-message/src/schemas/mod.rs b/ckb-typed-message/src/schemas/mod.rs
index ecd0844..5c8677e 100644
--- a/ckb-typed-message/src/schemas/mod.rs
+++ b/ckb-typed-message/src/schemas/mod.rs
@@ -1,3 +1,4 @@
pub mod basic;
pub mod blockchain;
+pub mod spore;
pub mod top_level;
diff --git a/ckb-typed-message/src/schemas/spore.rs b/ckb-typed-message/src/schemas/spore.rs
new file mode 100644
index 0000000..f0e554d
--- /dev/null
+++ b/ckb-typed-message/src/schemas/spore.rs
@@ -0,0 +1,1152 @@
+// Generated by Molecule 0.7.5
+
+use super::basic::*;
+use super::blockchain::*;
+use molecule::prelude::*;
+#[derive(Clone)]
+pub struct Mint(molecule::bytes::Bytes);
+impl ::core::fmt::LowerHex for Mint {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ use molecule::hex_string;
+ if f.alternate() {
+ write!(f, "0x")?;
+ }
+ write!(f, "{}", hex_string(self.as_slice()))
+ }
+}
+impl ::core::fmt::Debug for Mint {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}({:#x})", Self::NAME, self)
+ }
+}
+impl ::core::fmt::Display for Mint {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{} {{ ", Self::NAME)?;
+ write!(f, "{}: {}", "id", self.id())?;
+ write!(f, ", {}: {}", "to", self.to())?;
+ write!(f, ", {}: {}", "content_hash", self.content_hash())?;
+ let extra_count = self.count_extra_fields();
+ if extra_count != 0 {
+ write!(f, ", .. ({} fields)", extra_count)?;
+ }
+ write!(f, " }}")
+ }
+}
+impl ::core::default::Default for Mint {
+ fn default() -> Self {
+ let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE);
+ Mint::new_unchecked(v)
+ }
+}
+impl Mint {
+ const DEFAULT_VALUE: [u8; 137] = [
+ 137, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 16, 0,
+ 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ];
+ pub const FIELD_COUNT: usize = 3;
+ pub fn total_size(&self) -> usize {
+ molecule::unpack_number(self.as_slice()) as usize
+ }
+ pub fn field_count(&self) -> usize {
+ if self.total_size() == molecule::NUMBER_SIZE {
+ 0
+ } else {
+ (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1
+ }
+ }
+ pub fn count_extra_fields(&self) -> usize {
+ self.field_count() - Self::FIELD_COUNT
+ }
+ pub fn has_extra_fields(&self) -> bool {
+ Self::FIELD_COUNT != self.field_count()
+ }
+ pub fn id(&self) -> Byte32 {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[4..]) as usize;
+ let end = molecule::unpack_number(&slice[8..]) as usize;
+ Byte32::new_unchecked(self.0.slice(start..end))
+ }
+ pub fn to(&self) -> Address {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[8..]) as usize;
+ let end = molecule::unpack_number(&slice[12..]) as usize;
+ Address::new_unchecked(self.0.slice(start..end))
+ }
+ pub fn content_hash(&self) -> Byte32 {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[12..]) as usize;
+ if self.has_extra_fields() {
+ let end = molecule::unpack_number(&slice[16..]) as usize;
+ Byte32::new_unchecked(self.0.slice(start..end))
+ } else {
+ Byte32::new_unchecked(self.0.slice(start..))
+ }
+ }
+ pub fn as_reader<'r>(&'r self) -> MintReader<'r> {
+ MintReader::new_unchecked(self.as_slice())
+ }
+}
+impl molecule::prelude::Entity for Mint {
+ type Builder = MintBuilder;
+ const NAME: &'static str = "Mint";
+ fn new_unchecked(data: molecule::bytes::Bytes) -> Self {
+ Mint(data)
+ }
+ fn as_bytes(&self) -> molecule::bytes::Bytes {
+ self.0.clone()
+ }
+ fn as_slice(&self) -> &[u8] {
+ &self.0[..]
+ }
+ fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult {
+ MintReader::from_slice(slice).map(|reader| reader.to_entity())
+ }
+ fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult {
+ MintReader::from_compatible_slice(slice).map(|reader| reader.to_entity())
+ }
+ fn new_builder() -> Self::Builder {
+ ::core::default::Default::default()
+ }
+ fn as_builder(self) -> Self::Builder {
+ Self::new_builder()
+ .id(self.id())
+ .to(self.to())
+ .content_hash(self.content_hash())
+ }
+}
+#[derive(Clone, Copy)]
+pub struct MintReader<'r>(&'r [u8]);
+impl<'r> ::core::fmt::LowerHex for MintReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ use molecule::hex_string;
+ if f.alternate() {
+ write!(f, "0x")?;
+ }
+ write!(f, "{}", hex_string(self.as_slice()))
+ }
+}
+impl<'r> ::core::fmt::Debug for MintReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}({:#x})", Self::NAME, self)
+ }
+}
+impl<'r> ::core::fmt::Display for MintReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{} {{ ", Self::NAME)?;
+ write!(f, "{}: {}", "id", self.id())?;
+ write!(f, ", {}: {}", "to", self.to())?;
+ write!(f, ", {}: {}", "content_hash", self.content_hash())?;
+ let extra_count = self.count_extra_fields();
+ if extra_count != 0 {
+ write!(f, ", .. ({} fields)", extra_count)?;
+ }
+ write!(f, " }}")
+ }
+}
+impl<'r> MintReader<'r> {
+ pub const FIELD_COUNT: usize = 3;
+ pub fn total_size(&self) -> usize {
+ molecule::unpack_number(self.as_slice()) as usize
+ }
+ pub fn field_count(&self) -> usize {
+ if self.total_size() == molecule::NUMBER_SIZE {
+ 0
+ } else {
+ (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1
+ }
+ }
+ pub fn count_extra_fields(&self) -> usize {
+ self.field_count() - Self::FIELD_COUNT
+ }
+ pub fn has_extra_fields(&self) -> bool {
+ Self::FIELD_COUNT != self.field_count()
+ }
+ pub fn id(&self) -> Byte32Reader<'r> {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[4..]) as usize;
+ let end = molecule::unpack_number(&slice[8..]) as usize;
+ Byte32Reader::new_unchecked(&self.as_slice()[start..end])
+ }
+ pub fn to(&self) -> AddressReader<'r> {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[8..]) as usize;
+ let end = molecule::unpack_number(&slice[12..]) as usize;
+ AddressReader::new_unchecked(&self.as_slice()[start..end])
+ }
+ pub fn content_hash(&self) -> Byte32Reader<'r> {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[12..]) as usize;
+ if self.has_extra_fields() {
+ let end = molecule::unpack_number(&slice[16..]) as usize;
+ Byte32Reader::new_unchecked(&self.as_slice()[start..end])
+ } else {
+ Byte32Reader::new_unchecked(&self.as_slice()[start..])
+ }
+ }
+}
+impl<'r> molecule::prelude::Reader<'r> for MintReader<'r> {
+ type Entity = Mint;
+ const NAME: &'static str = "MintReader";
+ fn to_entity(&self) -> Self::Entity {
+ Self::Entity::new_unchecked(self.as_slice().to_owned().into())
+ }
+ fn new_unchecked(slice: &'r [u8]) -> Self {
+ MintReader(slice)
+ }
+ fn as_slice(&self) -> &'r [u8] {
+ self.0
+ }
+ fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> {
+ use molecule::verification_error as ve;
+ let slice_len = slice.len();
+ if slice_len < molecule::NUMBER_SIZE {
+ return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len);
+ }
+ let total_size = molecule::unpack_number(slice) as usize;
+ if slice_len != total_size {
+ return ve!(Self, TotalSizeNotMatch, total_size, slice_len);
+ }
+ if slice_len < molecule::NUMBER_SIZE * 2 {
+ return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len);
+ }
+ let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize;
+ if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 {
+ return ve!(Self, OffsetsNotMatch);
+ }
+ if slice_len < offset_first {
+ return ve!(Self, HeaderIsBroken, offset_first, slice_len);
+ }
+ let field_count = offset_first / molecule::NUMBER_SIZE - 1;
+ if field_count < Self::FIELD_COUNT {
+ return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count);
+ } else if !compatible && field_count > Self::FIELD_COUNT {
+ return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count);
+ };
+ let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first]
+ .chunks_exact(molecule::NUMBER_SIZE)
+ .map(|x| molecule::unpack_number(x) as usize)
+ .collect();
+ offsets.push(total_size);
+ if offsets.windows(2).any(|i| i[0] > i[1]) {
+ return ve!(Self, OffsetsNotMatch);
+ }
+ Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?;
+ AddressReader::verify(&slice[offsets[1]..offsets[2]], compatible)?;
+ Byte32Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?;
+ Ok(())
+ }
+}
+#[derive(Debug, Default)]
+pub struct MintBuilder {
+ pub(crate) id: Byte32,
+ pub(crate) to: Address,
+ pub(crate) content_hash: Byte32,
+}
+impl MintBuilder {
+ pub const FIELD_COUNT: usize = 3;
+ pub fn id(mut self, v: Byte32) -> Self {
+ self.id = v;
+ self
+ }
+ pub fn to(mut self, v: Address) -> Self {
+ self.to = v;
+ self
+ }
+ pub fn content_hash(mut self, v: Byte32) -> Self {
+ self.content_hash = v;
+ self
+ }
+}
+impl molecule::prelude::Builder for MintBuilder {
+ type Entity = Mint;
+ const NAME: &'static str = "MintBuilder";
+ fn expected_length(&self) -> usize {
+ molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1)
+ + self.id.as_slice().len()
+ + self.to.as_slice().len()
+ + self.content_hash.as_slice().len()
+ }
+ fn write(&self, writer: &mut W) -> molecule::io::Result<()> {
+ let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1);
+ let mut offsets = Vec::with_capacity(Self::FIELD_COUNT);
+ offsets.push(total_size);
+ total_size += self.id.as_slice().len();
+ offsets.push(total_size);
+ total_size += self.to.as_slice().len();
+ offsets.push(total_size);
+ total_size += self.content_hash.as_slice().len();
+ writer.write_all(&molecule::pack_number(total_size as molecule::Number))?;
+ for offset in offsets.into_iter() {
+ writer.write_all(&molecule::pack_number(offset as molecule::Number))?;
+ }
+ writer.write_all(self.id.as_slice())?;
+ writer.write_all(self.to.as_slice())?;
+ writer.write_all(self.content_hash.as_slice())?;
+ Ok(())
+ }
+ fn build(&self) -> Self::Entity {
+ let mut inner = Vec::with_capacity(self.expected_length());
+ self.write(&mut inner)
+ .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME));
+ Mint::new_unchecked(inner.into())
+ }
+}
+#[derive(Clone)]
+pub struct Transfer(molecule::bytes::Bytes);
+impl ::core::fmt::LowerHex for Transfer {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ use molecule::hex_string;
+ if f.alternate() {
+ write!(f, "0x")?;
+ }
+ write!(f, "{}", hex_string(self.as_slice()))
+ }
+}
+impl ::core::fmt::Debug for Transfer {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}({:#x})", Self::NAME, self)
+ }
+}
+impl ::core::fmt::Display for Transfer {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{} {{ ", Self::NAME)?;
+ write!(f, "{}: {}", "nft_id", self.nft_id())?;
+ write!(f, ", {}: {}", "from", self.from())?;
+ write!(f, ", {}: {}", "to", self.to())?;
+ let extra_count = self.count_extra_fields();
+ if extra_count != 0 {
+ write!(f, ", .. ({} fields)", extra_count)?;
+ }
+ write!(f, " }}")
+ }
+}
+impl ::core::default::Default for Transfer {
+ fn default() -> Self {
+ let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE);
+ Transfer::new_unchecked(v)
+ }
+}
+impl Transfer {
+ const DEFAULT_VALUE: [u8; 48] = [
+ 48, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ];
+ pub const FIELD_COUNT: usize = 3;
+ pub fn total_size(&self) -> usize {
+ molecule::unpack_number(self.as_slice()) as usize
+ }
+ pub fn field_count(&self) -> usize {
+ if self.total_size() == molecule::NUMBER_SIZE {
+ 0
+ } else {
+ (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1
+ }
+ }
+ pub fn count_extra_fields(&self) -> usize {
+ self.field_count() - Self::FIELD_COUNT
+ }
+ pub fn has_extra_fields(&self) -> bool {
+ Self::FIELD_COUNT != self.field_count()
+ }
+ pub fn nft_id(&self) -> Byte32 {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[4..]) as usize;
+ let end = molecule::unpack_number(&slice[8..]) as usize;
+ Byte32::new_unchecked(self.0.slice(start..end))
+ }
+ pub fn from(&self) -> AddressOpt {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[8..]) as usize;
+ let end = molecule::unpack_number(&slice[12..]) as usize;
+ AddressOpt::new_unchecked(self.0.slice(start..end))
+ }
+ pub fn to(&self) -> AddressOpt {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[12..]) as usize;
+ if self.has_extra_fields() {
+ let end = molecule::unpack_number(&slice[16..]) as usize;
+ AddressOpt::new_unchecked(self.0.slice(start..end))
+ } else {
+ AddressOpt::new_unchecked(self.0.slice(start..))
+ }
+ }
+ pub fn as_reader<'r>(&'r self) -> TransferReader<'r> {
+ TransferReader::new_unchecked(self.as_slice())
+ }
+}
+impl molecule::prelude::Entity for Transfer {
+ type Builder = TransferBuilder;
+ const NAME: &'static str = "Transfer";
+ fn new_unchecked(data: molecule::bytes::Bytes) -> Self {
+ Transfer(data)
+ }
+ fn as_bytes(&self) -> molecule::bytes::Bytes {
+ self.0.clone()
+ }
+ fn as_slice(&self) -> &[u8] {
+ &self.0[..]
+ }
+ fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult {
+ TransferReader::from_slice(slice).map(|reader| reader.to_entity())
+ }
+ fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult {
+ TransferReader::from_compatible_slice(slice).map(|reader| reader.to_entity())
+ }
+ fn new_builder() -> Self::Builder {
+ ::core::default::Default::default()
+ }
+ fn as_builder(self) -> Self::Builder {
+ Self::new_builder()
+ .nft_id(self.nft_id())
+ .from(self.from())
+ .to(self.to())
+ }
+}
+#[derive(Clone, Copy)]
+pub struct TransferReader<'r>(&'r [u8]);
+impl<'r> ::core::fmt::LowerHex for TransferReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ use molecule::hex_string;
+ if f.alternate() {
+ write!(f, "0x")?;
+ }
+ write!(f, "{}", hex_string(self.as_slice()))
+ }
+}
+impl<'r> ::core::fmt::Debug for TransferReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}({:#x})", Self::NAME, self)
+ }
+}
+impl<'r> ::core::fmt::Display for TransferReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{} {{ ", Self::NAME)?;
+ write!(f, "{}: {}", "nft_id", self.nft_id())?;
+ write!(f, ", {}: {}", "from", self.from())?;
+ write!(f, ", {}: {}", "to", self.to())?;
+ let extra_count = self.count_extra_fields();
+ if extra_count != 0 {
+ write!(f, ", .. ({} fields)", extra_count)?;
+ }
+ write!(f, " }}")
+ }
+}
+impl<'r> TransferReader<'r> {
+ pub const FIELD_COUNT: usize = 3;
+ pub fn total_size(&self) -> usize {
+ molecule::unpack_number(self.as_slice()) as usize
+ }
+ pub fn field_count(&self) -> usize {
+ if self.total_size() == molecule::NUMBER_SIZE {
+ 0
+ } else {
+ (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1
+ }
+ }
+ pub fn count_extra_fields(&self) -> usize {
+ self.field_count() - Self::FIELD_COUNT
+ }
+ pub fn has_extra_fields(&self) -> bool {
+ Self::FIELD_COUNT != self.field_count()
+ }
+ pub fn nft_id(&self) -> Byte32Reader<'r> {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[4..]) as usize;
+ let end = molecule::unpack_number(&slice[8..]) as usize;
+ Byte32Reader::new_unchecked(&self.as_slice()[start..end])
+ }
+ pub fn from(&self) -> AddressOptReader<'r> {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[8..]) as usize;
+ let end = molecule::unpack_number(&slice[12..]) as usize;
+ AddressOptReader::new_unchecked(&self.as_slice()[start..end])
+ }
+ pub fn to(&self) -> AddressOptReader<'r> {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[12..]) as usize;
+ if self.has_extra_fields() {
+ let end = molecule::unpack_number(&slice[16..]) as usize;
+ AddressOptReader::new_unchecked(&self.as_slice()[start..end])
+ } else {
+ AddressOptReader::new_unchecked(&self.as_slice()[start..])
+ }
+ }
+}
+impl<'r> molecule::prelude::Reader<'r> for TransferReader<'r> {
+ type Entity = Transfer;
+ const NAME: &'static str = "TransferReader";
+ fn to_entity(&self) -> Self::Entity {
+ Self::Entity::new_unchecked(self.as_slice().to_owned().into())
+ }
+ fn new_unchecked(slice: &'r [u8]) -> Self {
+ TransferReader(slice)
+ }
+ fn as_slice(&self) -> &'r [u8] {
+ self.0
+ }
+ fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> {
+ use molecule::verification_error as ve;
+ let slice_len = slice.len();
+ if slice_len < molecule::NUMBER_SIZE {
+ return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len);
+ }
+ let total_size = molecule::unpack_number(slice) as usize;
+ if slice_len != total_size {
+ return ve!(Self, TotalSizeNotMatch, total_size, slice_len);
+ }
+ if slice_len < molecule::NUMBER_SIZE * 2 {
+ return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len);
+ }
+ let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize;
+ if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 {
+ return ve!(Self, OffsetsNotMatch);
+ }
+ if slice_len < offset_first {
+ return ve!(Self, HeaderIsBroken, offset_first, slice_len);
+ }
+ let field_count = offset_first / molecule::NUMBER_SIZE - 1;
+ if field_count < Self::FIELD_COUNT {
+ return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count);
+ } else if !compatible && field_count > Self::FIELD_COUNT {
+ return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count);
+ };
+ let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first]
+ .chunks_exact(molecule::NUMBER_SIZE)
+ .map(|x| molecule::unpack_number(x) as usize)
+ .collect();
+ offsets.push(total_size);
+ if offsets.windows(2).any(|i| i[0] > i[1]) {
+ return ve!(Self, OffsetsNotMatch);
+ }
+ Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?;
+ AddressOptReader::verify(&slice[offsets[1]..offsets[2]], compatible)?;
+ AddressOptReader::verify(&slice[offsets[2]..offsets[3]], compatible)?;
+ Ok(())
+ }
+}
+#[derive(Debug, Default)]
+pub struct TransferBuilder {
+ pub(crate) nft_id: Byte32,
+ pub(crate) from: AddressOpt,
+ pub(crate) to: AddressOpt,
+}
+impl TransferBuilder {
+ pub const FIELD_COUNT: usize = 3;
+ pub fn nft_id(mut self, v: Byte32) -> Self {
+ self.nft_id = v;
+ self
+ }
+ pub fn from(mut self, v: AddressOpt) -> Self {
+ self.from = v;
+ self
+ }
+ pub fn to(mut self, v: AddressOpt) -> Self {
+ self.to = v;
+ self
+ }
+}
+impl molecule::prelude::Builder for TransferBuilder {
+ type Entity = Transfer;
+ const NAME: &'static str = "TransferBuilder";
+ fn expected_length(&self) -> usize {
+ molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1)
+ + self.nft_id.as_slice().len()
+ + self.from.as_slice().len()
+ + self.to.as_slice().len()
+ }
+ fn write(&self, writer: &mut W) -> molecule::io::Result<()> {
+ let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1);
+ let mut offsets = Vec::with_capacity(Self::FIELD_COUNT);
+ offsets.push(total_size);
+ total_size += self.nft_id.as_slice().len();
+ offsets.push(total_size);
+ total_size += self.from.as_slice().len();
+ offsets.push(total_size);
+ total_size += self.to.as_slice().len();
+ writer.write_all(&molecule::pack_number(total_size as molecule::Number))?;
+ for offset in offsets.into_iter() {
+ writer.write_all(&molecule::pack_number(offset as molecule::Number))?;
+ }
+ writer.write_all(self.nft_id.as_slice())?;
+ writer.write_all(self.from.as_slice())?;
+ writer.write_all(self.to.as_slice())?;
+ Ok(())
+ }
+ fn build(&self) -> Self::Entity {
+ let mut inner = Vec::with_capacity(self.expected_length());
+ self.write(&mut inner)
+ .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME));
+ Transfer::new_unchecked(inner.into())
+ }
+}
+#[derive(Clone)]
+pub struct Melt(molecule::bytes::Bytes);
+impl ::core::fmt::LowerHex for Melt {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ use molecule::hex_string;
+ if f.alternate() {
+ write!(f, "0x")?;
+ }
+ write!(f, "{}", hex_string(self.as_slice()))
+ }
+}
+impl ::core::fmt::Debug for Melt {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}({:#x})", Self::NAME, self)
+ }
+}
+impl ::core::fmt::Display for Melt {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{} {{ ", Self::NAME)?;
+ write!(f, "{}: {}", "id", self.id())?;
+ let extra_count = self.count_extra_fields();
+ if extra_count != 0 {
+ write!(f, ", .. ({} fields)", extra_count)?;
+ }
+ write!(f, " }}")
+ }
+}
+impl ::core::default::Default for Melt {
+ fn default() -> Self {
+ let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE);
+ Melt::new_unchecked(v)
+ }
+}
+impl Melt {
+ const DEFAULT_VALUE: [u8; 40] = [
+ 40, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ];
+ pub const FIELD_COUNT: usize = 1;
+ pub fn total_size(&self) -> usize {
+ molecule::unpack_number(self.as_slice()) as usize
+ }
+ pub fn field_count(&self) -> usize {
+ if self.total_size() == molecule::NUMBER_SIZE {
+ 0
+ } else {
+ (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1
+ }
+ }
+ pub fn count_extra_fields(&self) -> usize {
+ self.field_count() - Self::FIELD_COUNT
+ }
+ pub fn has_extra_fields(&self) -> bool {
+ Self::FIELD_COUNT != self.field_count()
+ }
+ pub fn id(&self) -> Byte32 {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[4..]) as usize;
+ if self.has_extra_fields() {
+ let end = molecule::unpack_number(&slice[8..]) as usize;
+ Byte32::new_unchecked(self.0.slice(start..end))
+ } else {
+ Byte32::new_unchecked(self.0.slice(start..))
+ }
+ }
+ pub fn as_reader<'r>(&'r self) -> MeltReader<'r> {
+ MeltReader::new_unchecked(self.as_slice())
+ }
+}
+impl molecule::prelude::Entity for Melt {
+ type Builder = MeltBuilder;
+ const NAME: &'static str = "Melt";
+ fn new_unchecked(data: molecule::bytes::Bytes) -> Self {
+ Melt(data)
+ }
+ fn as_bytes(&self) -> molecule::bytes::Bytes {
+ self.0.clone()
+ }
+ fn as_slice(&self) -> &[u8] {
+ &self.0[..]
+ }
+ fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult {
+ MeltReader::from_slice(slice).map(|reader| reader.to_entity())
+ }
+ fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult {
+ MeltReader::from_compatible_slice(slice).map(|reader| reader.to_entity())
+ }
+ fn new_builder() -> Self::Builder {
+ ::core::default::Default::default()
+ }
+ fn as_builder(self) -> Self::Builder {
+ Self::new_builder().id(self.id())
+ }
+}
+#[derive(Clone, Copy)]
+pub struct MeltReader<'r>(&'r [u8]);
+impl<'r> ::core::fmt::LowerHex for MeltReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ use molecule::hex_string;
+ if f.alternate() {
+ write!(f, "0x")?;
+ }
+ write!(f, "{}", hex_string(self.as_slice()))
+ }
+}
+impl<'r> ::core::fmt::Debug for MeltReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}({:#x})", Self::NAME, self)
+ }
+}
+impl<'r> ::core::fmt::Display for MeltReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{} {{ ", Self::NAME)?;
+ write!(f, "{}: {}", "id", self.id())?;
+ let extra_count = self.count_extra_fields();
+ if extra_count != 0 {
+ write!(f, ", .. ({} fields)", extra_count)?;
+ }
+ write!(f, " }}")
+ }
+}
+impl<'r> MeltReader<'r> {
+ pub const FIELD_COUNT: usize = 1;
+ pub fn total_size(&self) -> usize {
+ molecule::unpack_number(self.as_slice()) as usize
+ }
+ pub fn field_count(&self) -> usize {
+ if self.total_size() == molecule::NUMBER_SIZE {
+ 0
+ } else {
+ (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1
+ }
+ }
+ pub fn count_extra_fields(&self) -> usize {
+ self.field_count() - Self::FIELD_COUNT
+ }
+ pub fn has_extra_fields(&self) -> bool {
+ Self::FIELD_COUNT != self.field_count()
+ }
+ pub fn id(&self) -> Byte32Reader<'r> {
+ let slice = self.as_slice();
+ let start = molecule::unpack_number(&slice[4..]) as usize;
+ if self.has_extra_fields() {
+ let end = molecule::unpack_number(&slice[8..]) as usize;
+ Byte32Reader::new_unchecked(&self.as_slice()[start..end])
+ } else {
+ Byte32Reader::new_unchecked(&self.as_slice()[start..])
+ }
+ }
+}
+impl<'r> molecule::prelude::Reader<'r> for MeltReader<'r> {
+ type Entity = Melt;
+ const NAME: &'static str = "MeltReader";
+ fn to_entity(&self) -> Self::Entity {
+ Self::Entity::new_unchecked(self.as_slice().to_owned().into())
+ }
+ fn new_unchecked(slice: &'r [u8]) -> Self {
+ MeltReader(slice)
+ }
+ fn as_slice(&self) -> &'r [u8] {
+ self.0
+ }
+ fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> {
+ use molecule::verification_error as ve;
+ let slice_len = slice.len();
+ if slice_len < molecule::NUMBER_SIZE {
+ return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len);
+ }
+ let total_size = molecule::unpack_number(slice) as usize;
+ if slice_len != total_size {
+ return ve!(Self, TotalSizeNotMatch, total_size, slice_len);
+ }
+ if slice_len < molecule::NUMBER_SIZE * 2 {
+ return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len);
+ }
+ let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize;
+ if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 {
+ return ve!(Self, OffsetsNotMatch);
+ }
+ if slice_len < offset_first {
+ return ve!(Self, HeaderIsBroken, offset_first, slice_len);
+ }
+ let field_count = offset_first / molecule::NUMBER_SIZE - 1;
+ if field_count < Self::FIELD_COUNT {
+ return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count);
+ } else if !compatible && field_count > Self::FIELD_COUNT {
+ return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count);
+ };
+ let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first]
+ .chunks_exact(molecule::NUMBER_SIZE)
+ .map(|x| molecule::unpack_number(x) as usize)
+ .collect();
+ offsets.push(total_size);
+ if offsets.windows(2).any(|i| i[0] > i[1]) {
+ return ve!(Self, OffsetsNotMatch);
+ }
+ Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?;
+ Ok(())
+ }
+}
+#[derive(Debug, Default)]
+pub struct MeltBuilder {
+ pub(crate) id: Byte32,
+}
+impl MeltBuilder {
+ pub const FIELD_COUNT: usize = 1;
+ pub fn id(mut self, v: Byte32) -> Self {
+ self.id = v;
+ self
+ }
+}
+impl molecule::prelude::Builder for MeltBuilder {
+ type Entity = Melt;
+ const NAME: &'static str = "MeltBuilder";
+ fn expected_length(&self) -> usize {
+ molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + self.id.as_slice().len()
+ }
+ fn write(&self, writer: &mut W) -> molecule::io::Result<()> {
+ let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1);
+ let mut offsets = Vec::with_capacity(Self::FIELD_COUNT);
+ offsets.push(total_size);
+ total_size += self.id.as_slice().len();
+ writer.write_all(&molecule::pack_number(total_size as molecule::Number))?;
+ for offset in offsets.into_iter() {
+ writer.write_all(&molecule::pack_number(offset as molecule::Number))?;
+ }
+ writer.write_all(self.id.as_slice())?;
+ Ok(())
+ }
+ fn build(&self) -> Self::Entity {
+ let mut inner = Vec::with_capacity(self.expected_length());
+ self.write(&mut inner)
+ .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME));
+ Melt::new_unchecked(inner.into())
+ }
+}
+#[derive(Clone)]
+pub struct SporeAction(molecule::bytes::Bytes);
+impl ::core::fmt::LowerHex for SporeAction {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ use molecule::hex_string;
+ if f.alternate() {
+ write!(f, "0x")?;
+ }
+ write!(f, "{}", hex_string(self.as_slice()))
+ }
+}
+impl ::core::fmt::Debug for SporeAction {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}({:#x})", Self::NAME, self)
+ }
+}
+impl ::core::fmt::Display for SporeAction {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}(", Self::NAME)?;
+ self.to_enum().display_inner(f)?;
+ write!(f, ")")
+ }
+}
+impl ::core::default::Default for SporeAction {
+ fn default() -> Self {
+ let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE);
+ SporeAction::new_unchecked(v)
+ }
+}
+impl SporeAction {
+ const DEFAULT_VALUE: [u8; 141] = [
+ 0, 0, 0, 0, 137, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0,
+ 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ];
+ pub const ITEMS_COUNT: usize = 3;
+ pub fn item_id(&self) -> molecule::Number {
+ molecule::unpack_number(self.as_slice())
+ }
+ pub fn to_enum(&self) -> SporeActionUnion {
+ let inner = self.0.slice(molecule::NUMBER_SIZE..);
+ match self.item_id() {
+ 0 => Mint::new_unchecked(inner).into(),
+ 1 => Transfer::new_unchecked(inner).into(),
+ 2 => Melt::new_unchecked(inner).into(),
+ _ => panic!("{}: invalid data", Self::NAME),
+ }
+ }
+ pub fn as_reader<'r>(&'r self) -> SporeActionReader<'r> {
+ SporeActionReader::new_unchecked(self.as_slice())
+ }
+}
+impl molecule::prelude::Entity for SporeAction {
+ type Builder = SporeActionBuilder;
+ const NAME: &'static str = "SporeAction";
+ fn new_unchecked(data: molecule::bytes::Bytes) -> Self {
+ SporeAction(data)
+ }
+ fn as_bytes(&self) -> molecule::bytes::Bytes {
+ self.0.clone()
+ }
+ fn as_slice(&self) -> &[u8] {
+ &self.0[..]
+ }
+ fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult {
+ SporeActionReader::from_slice(slice).map(|reader| reader.to_entity())
+ }
+ fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult {
+ SporeActionReader::from_compatible_slice(slice).map(|reader| reader.to_entity())
+ }
+ fn new_builder() -> Self::Builder {
+ ::core::default::Default::default()
+ }
+ fn as_builder(self) -> Self::Builder {
+ Self::new_builder().set(self.to_enum())
+ }
+}
+#[derive(Clone, Copy)]
+pub struct SporeActionReader<'r>(&'r [u8]);
+impl<'r> ::core::fmt::LowerHex for SporeActionReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ use molecule::hex_string;
+ if f.alternate() {
+ write!(f, "0x")?;
+ }
+ write!(f, "{}", hex_string(self.as_slice()))
+ }
+}
+impl<'r> ::core::fmt::Debug for SporeActionReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}({:#x})", Self::NAME, self)
+ }
+}
+impl<'r> ::core::fmt::Display for SporeActionReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ write!(f, "{}(", Self::NAME)?;
+ self.to_enum().display_inner(f)?;
+ write!(f, ")")
+ }
+}
+impl<'r> SporeActionReader<'r> {
+ pub const ITEMS_COUNT: usize = 3;
+ pub fn item_id(&self) -> molecule::Number {
+ molecule::unpack_number(self.as_slice())
+ }
+ pub fn to_enum(&self) -> SporeActionUnionReader<'r> {
+ let inner = &self.as_slice()[molecule::NUMBER_SIZE..];
+ match self.item_id() {
+ 0 => MintReader::new_unchecked(inner).into(),
+ 1 => TransferReader::new_unchecked(inner).into(),
+ 2 => MeltReader::new_unchecked(inner).into(),
+ _ => panic!("{}: invalid data", Self::NAME),
+ }
+ }
+}
+impl<'r> molecule::prelude::Reader<'r> for SporeActionReader<'r> {
+ type Entity = SporeAction;
+ const NAME: &'static str = "SporeActionReader";
+ fn to_entity(&self) -> Self::Entity {
+ Self::Entity::new_unchecked(self.as_slice().to_owned().into())
+ }
+ fn new_unchecked(slice: &'r [u8]) -> Self {
+ SporeActionReader(slice)
+ }
+ fn as_slice(&self) -> &'r [u8] {
+ self.0
+ }
+ fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> {
+ use molecule::verification_error as ve;
+ let slice_len = slice.len();
+ if slice_len < molecule::NUMBER_SIZE {
+ return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len);
+ }
+ let item_id = molecule::unpack_number(slice);
+ let inner_slice = &slice[molecule::NUMBER_SIZE..];
+ match item_id {
+ 0 => MintReader::verify(inner_slice, compatible),
+ 1 => TransferReader::verify(inner_slice, compatible),
+ 2 => MeltReader::verify(inner_slice, compatible),
+ _ => ve!(Self, UnknownItem, Self::ITEMS_COUNT, item_id),
+ }?;
+ Ok(())
+ }
+}
+#[derive(Debug, Default)]
+pub struct SporeActionBuilder(pub(crate) SporeActionUnion);
+impl SporeActionBuilder {
+ pub const ITEMS_COUNT: usize = 3;
+ pub fn set(mut self, v: I) -> Self
+ where
+ I: ::core::convert::Into,
+ {
+ self.0 = v.into();
+ self
+ }
+}
+impl molecule::prelude::Builder for SporeActionBuilder {
+ type Entity = SporeAction;
+ const NAME: &'static str = "SporeActionBuilder";
+ fn expected_length(&self) -> usize {
+ molecule::NUMBER_SIZE + self.0.as_slice().len()
+ }
+ fn write(&self, writer: &mut W) -> molecule::io::Result<()> {
+ writer.write_all(&molecule::pack_number(self.0.item_id()))?;
+ writer.write_all(self.0.as_slice())
+ }
+ fn build(&self) -> Self::Entity {
+ let mut inner = Vec::with_capacity(self.expected_length());
+ self.write(&mut inner)
+ .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME));
+ SporeAction::new_unchecked(inner.into())
+ }
+}
+#[derive(Debug, Clone)]
+pub enum SporeActionUnion {
+ Mint(Mint),
+ Transfer(Transfer),
+ Melt(Melt),
+}
+#[derive(Debug, Clone, Copy)]
+pub enum SporeActionUnionReader<'r> {
+ Mint(MintReader<'r>),
+ Transfer(TransferReader<'r>),
+ Melt(MeltReader<'r>),
+}
+impl ::core::default::Default for SporeActionUnion {
+ fn default() -> Self {
+ SporeActionUnion::Mint(::core::default::Default::default())
+ }
+}
+impl ::core::fmt::Display for SporeActionUnion {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ match self {
+ SporeActionUnion::Mint(ref item) => {
+ write!(f, "{}::{}({})", Self::NAME, Mint::NAME, item)
+ }
+ SporeActionUnion::Transfer(ref item) => {
+ write!(f, "{}::{}({})", Self::NAME, Transfer::NAME, item)
+ }
+ SporeActionUnion::Melt(ref item) => {
+ write!(f, "{}::{}({})", Self::NAME, Melt::NAME, item)
+ }
+ }
+ }
+}
+impl<'r> ::core::fmt::Display for SporeActionUnionReader<'r> {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ match self {
+ SporeActionUnionReader::Mint(ref item) => {
+ write!(f, "{}::{}({})", Self::NAME, Mint::NAME, item)
+ }
+ SporeActionUnionReader::Transfer(ref item) => {
+ write!(f, "{}::{}({})", Self::NAME, Transfer::NAME, item)
+ }
+ SporeActionUnionReader::Melt(ref item) => {
+ write!(f, "{}::{}({})", Self::NAME, Melt::NAME, item)
+ }
+ }
+ }
+}
+impl SporeActionUnion {
+ pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ match self {
+ SporeActionUnion::Mint(ref item) => write!(f, "{}", item),
+ SporeActionUnion::Transfer(ref item) => write!(f, "{}", item),
+ SporeActionUnion::Melt(ref item) => write!(f, "{}", item),
+ }
+ }
+}
+impl<'r> SporeActionUnionReader<'r> {
+ pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ match self {
+ SporeActionUnionReader::Mint(ref item) => write!(f, "{}", item),
+ SporeActionUnionReader::Transfer(ref item) => write!(f, "{}", item),
+ SporeActionUnionReader::Melt(ref item) => write!(f, "{}", item),
+ }
+ }
+}
+impl ::core::convert::From for SporeActionUnion {
+ fn from(item: Mint) -> Self {
+ SporeActionUnion::Mint(item)
+ }
+}
+impl ::core::convert::From for SporeActionUnion {
+ fn from(item: Transfer) -> Self {
+ SporeActionUnion::Transfer(item)
+ }
+}
+impl ::core::convert::From for SporeActionUnion {
+ fn from(item: Melt) -> Self {
+ SporeActionUnion::Melt(item)
+ }
+}
+impl<'r> ::core::convert::From> for SporeActionUnionReader<'r> {
+ fn from(item: MintReader<'r>) -> Self {
+ SporeActionUnionReader::Mint(item)
+ }
+}
+impl<'r> ::core::convert::From> for SporeActionUnionReader<'r> {
+ fn from(item: TransferReader<'r>) -> Self {
+ SporeActionUnionReader::Transfer(item)
+ }
+}
+impl<'r> ::core::convert::From> for SporeActionUnionReader<'r> {
+ fn from(item: MeltReader<'r>) -> Self {
+ SporeActionUnionReader::Melt(item)
+ }
+}
+impl SporeActionUnion {
+ pub const NAME: &'static str = "SporeActionUnion";
+ pub fn as_bytes(&self) -> molecule::bytes::Bytes {
+ match self {
+ SporeActionUnion::Mint(item) => item.as_bytes(),
+ SporeActionUnion::Transfer(item) => item.as_bytes(),
+ SporeActionUnion::Melt(item) => item.as_bytes(),
+ }
+ }
+ pub fn as_slice(&self) -> &[u8] {
+ match self {
+ SporeActionUnion::Mint(item) => item.as_slice(),
+ SporeActionUnion::Transfer(item) => item.as_slice(),
+ SporeActionUnion::Melt(item) => item.as_slice(),
+ }
+ }
+ pub fn item_id(&self) -> molecule::Number {
+ match self {
+ SporeActionUnion::Mint(_) => 0,
+ SporeActionUnion::Transfer(_) => 1,
+ SporeActionUnion::Melt(_) => 2,
+ }
+ }
+ pub fn item_name(&self) -> &str {
+ match self {
+ SporeActionUnion::Mint(_) => "Mint",
+ SporeActionUnion::Transfer(_) => "Transfer",
+ SporeActionUnion::Melt(_) => "Melt",
+ }
+ }
+ pub fn as_reader<'r>(&'r self) -> SporeActionUnionReader<'r> {
+ match self {
+ SporeActionUnion::Mint(item) => item.as_reader().into(),
+ SporeActionUnion::Transfer(item) => item.as_reader().into(),
+ SporeActionUnion::Melt(item) => item.as_reader().into(),
+ }
+ }
+}
+impl<'r> SporeActionUnionReader<'r> {
+ pub const NAME: &'r str = "SporeActionUnionReader";
+ pub fn as_slice(&self) -> &'r [u8] {
+ match self {
+ SporeActionUnionReader::Mint(item) => item.as_slice(),
+ SporeActionUnionReader::Transfer(item) => item.as_slice(),
+ SporeActionUnionReader::Melt(item) => item.as_slice(),
+ }
+ }
+ pub fn item_id(&self) -> molecule::Number {
+ match self {
+ SporeActionUnionReader::Mint(_) => 0,
+ SporeActionUnionReader::Transfer(_) => 1,
+ SporeActionUnionReader::Melt(_) => 2,
+ }
+ }
+ pub fn item_name(&self) -> &str {
+ match self {
+ SporeActionUnionReader::Mint(_) => "Mint",
+ SporeActionUnionReader::Transfer(_) => "Transfer",
+ SporeActionUnionReader::Melt(_) => "Melt",
+ }
+ }
+}
diff --git a/schemas/basic.mol b/schemas/basic.mol
index d1dab9d..fe2e307 100644
--- a/schemas/basic.mol
+++ b/schemas/basic.mol
@@ -6,6 +6,8 @@ union Address {
Script,
}
+option AddressOpt (Address);
+
table Action {
info_hash: Byte32,
data: Bytes,
diff --git a/schemas/spore.mol b/schemas/spore.mol
new file mode 100644
index 0000000..597c0e0
--- /dev/null
+++ b/schemas/spore.mol
@@ -0,0 +1,24 @@
+import blockchain;
+import basic;
+
+table Mint {
+ id: Byte32,
+ to: Address,
+ content_hash: Byte32,
+}
+
+table Transfer {
+ nft_id: Byte32,
+ from: AddressOpt,
+ to: AddressOpt,
+}
+
+table Melt {
+ id: Byte32,
+}
+
+union SporeAction {
+ Mint,
+ Transfer,
+ Melt,
+}