cml_cip25/
lib.rs

1#![allow(clippy::too_many_arguments)]
2
3// This library was code-generated using an experimental CDDL to rust tool:
4// https://github.com/dcSpark/cddl-codegen
5
6pub mod serialization;
7pub mod utils;
8
9pub use utils::{CIP25LabelMetadata, CIP25Version};
10
11use cbor_event::de::Deserializer;
12use cbor_event::se::Serializer;
13use cbor_event::Special as CBORSpecial;
14use cbor_event::Type as CBORType;
15pub use cml_core::error::*;
16use std::convert::{From, TryFrom};
17use std::io::{BufRead, Write};
18
19/// A String that may or may not be chunked into 64-byte chunks to be able
20/// to conform to Cardano TX Metadata limitations.
21/// Unless you have good reasons, you should be using the From<&str> trait to construct this:
22/// ```
23/// use cml_cip25::CIP25ChunkableString;
24/// // automatically chunks this too long string into two chunks:
25/// let chunkable_string = CIP25ChunkableString::from("this can be any length and will automatically be chunked into 64-byte pieces when/if needed");
26/// match chunkable_string {
27///     CIP25ChunkableString::Single(_) => panic!(),
28///     CIP25ChunkableString::Chunked(chunks) => {
29///         assert_eq!(chunks[0].to_str(), "this can be any length and will automatically be chunked into 64");
30///         assert_eq!(chunks[1].to_str(), "-byte pieces when/if needed");
31///     },
32/// }
33/// ```
34#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
35pub enum CIP25ChunkableString {
36    Single(CIP25String64),
37    Chunked(Vec<CIP25String64>),
38}
39
40impl CIP25ChunkableString {
41    /// Construct from a single <=64 byte string chunk.
42    /// If size is not known or for simplicity use From<&str> instead
43    pub fn new_single(single: CIP25String64) -> Self {
44        Self::Single(single)
45    }
46
47    /// Construct from an explicit list of chunks
48    /// If size is not known or for simplicity use From<&str> instead
49    pub fn new_chunked(chunked: Vec<CIP25String64>) -> Self {
50        Self::Chunked(chunked)
51    }
52}
53
54#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
55pub struct CIP25FilesDetails {
56    pub name: CIP25String64,
57    pub media_type: CIP25String64,
58    pub src: CIP25ChunkableString,
59}
60
61impl CIP25FilesDetails {
62    pub fn new(name: CIP25String64, media_type: CIP25String64, src: CIP25ChunkableString) -> Self {
63        Self {
64            name,
65            media_type,
66            src,
67        }
68    }
69}
70
71/// This is the entire metadata schema for CIP-25
72/// It can be parsed by passing in the CBOR bytes of the entire transaction metadata
73/// or by passing in an existing Metadata struct.
74/// Parsing from CBOR bytes should be marginally faster.
75#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
76pub struct CIP25Metadata {
77    /// The core details of the CIP25 spec
78    pub key_721: CIP25LabelMetadata,
79}
80
81impl CIP25Metadata {
82    pub fn new(key_721: CIP25LabelMetadata) -> Self {
83        Self { key_721 }
84    }
85}
86
87#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
88pub struct CIP25MetadataDetails {
89    pub name: CIP25String64,
90    pub image: CIP25ChunkableString,
91    pub media_type: Option<CIP25String64>,
92    pub description: Option<CIP25ChunkableString>,
93    pub files: Option<Vec<CIP25FilesDetails>>,
94}
95
96impl CIP25MetadataDetails {
97    pub fn new(name: CIP25String64, image: CIP25ChunkableString) -> Self {
98        Self {
99            name,
100            image,
101            media_type: None,
102            description: None,
103            files: None,
104        }
105    }
106}
107
108#[derive(Clone, Debug, serde::Deserialize, serde::Serialize, schemars::JsonSchema)]
109pub struct CIP25String64(pub String);
110
111impl CIP25String64 {
112    pub fn get(&self) -> &String {
113        &self.0
114    }
115
116    pub fn new(inner: String) -> Result<Self, DeserializeError> {
117        if inner.len() > 64 {
118            return Err(DeserializeError::new(
119                "CIP25String64",
120                DeserializeFailure::RangeCheck {
121                    found: inner.len() as isize,
122                    min: Some(0),
123                    max: Some(64),
124                },
125            ));
126        }
127        Ok(Self(inner))
128    }
129}
130
131impl TryFrom<String> for CIP25String64 {
132    type Error = DeserializeError;
133
134    fn try_from(inner: String) -> Result<Self, Self::Error> {
135        CIP25String64::new(inner)
136    }
137}
138
139impl From<CIP25String64> for String {
140    fn from(wrapper: CIP25String64) -> Self {
141        wrapper.0
142    }
143}