Skip to main content

miden_protocol/note/
note_type.rs

1use core::fmt::Display;
2use core::str::FromStr;
3
4use crate::Felt;
5use crate::errors::NoteError;
6use crate::utils::serde::{
7    ByteReader,
8    ByteWriter,
9    Deserializable,
10    DeserializationError,
11    Serializable,
12};
13
14// NOTE TYPE
15// ================================================================================================
16
17#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
18#[repr(u8)]
19pub enum NoteType {
20    #[default]
21    /// Notes with this type have only their hash published to the network.
22    Private = Self::PRIVATE,
23
24    /// Notes with this type are fully shared with the network.
25    Public = Self::PUBLIC,
26}
27
28impl NoteType {
29    const PRIVATE: u8 = 0;
30    const PUBLIC: u8 = 1;
31
32    /// Returns the note type encoded to a 1-bit flag, where private is 0 and public is 1.
33    pub const fn as_u8(self) -> u8 {
34        self as u8
35    }
36}
37
38// CONVERSIONS FROM NOTE TYPE
39// ================================================================================================
40
41impl From<NoteType> for Felt {
42    fn from(note_type: NoteType) -> Self {
43        Felt::from(note_type.as_u8())
44    }
45}
46
47// CONVERSIONS INTO NOTE TYPE
48// ================================================================================================
49
50impl TryFrom<u8> for NoteType {
51    type Error = NoteError;
52
53    fn try_from(value: u8) -> Result<Self, Self::Error> {
54        match value {
55            Self::PRIVATE => Ok(NoteType::Private),
56            Self::PUBLIC => Ok(NoteType::Public),
57            _ => Err(NoteError::UnknownNoteType(format!("0b{value:b}").into())),
58        }
59    }
60}
61
62impl TryFrom<Felt> for NoteType {
63    type Error = NoteError;
64
65    fn try_from(value: Felt) -> Result<Self, Self::Error> {
66        let byte = value.as_canonical_u64();
67        Self::try_from(
68            u8::try_from(byte)
69                .map_err(|_| NoteError::UnknownNoteType(format!("0b{byte:b}").into()))?,
70        )
71    }
72}
73
74// STRING CONVERSION
75// ================================================================================================
76
77impl Display for NoteType {
78    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
79        match self {
80            NoteType::Private => write!(f, "private"),
81            NoteType::Public => write!(f, "public"),
82        }
83    }
84}
85
86impl FromStr for NoteType {
87    type Err = NoteError;
88
89    fn from_str(s: &str) -> Result<Self, Self::Err> {
90        match s {
91            "private" => Ok(NoteType::Private),
92            "public" => Ok(NoteType::Public),
93            _ => Err(NoteError::UnknownNoteType(s.into())),
94        }
95    }
96}
97
98// SERIALIZATION
99// ================================================================================================
100
101impl Serializable for NoteType {
102    fn write_into<W: ByteWriter>(&self, target: &mut W) {
103        (*self as u8).write_into(target)
104    }
105
106    fn get_size_hint(&self) -> usize {
107        core::mem::size_of::<u8>()
108    }
109}
110
111impl Deserializable for NoteType {
112    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
113        let discriminant = u8::read_from(source)?;
114
115        let note_type = match discriminant {
116            NoteType::PRIVATE => NoteType::Private,
117            NoteType::PUBLIC => NoteType::Public,
118            discriminant => {
119                return Err(DeserializationError::InvalidValue(format!(
120                    "discriminant {discriminant} is not a valid NoteType"
121                )));
122            },
123        };
124
125        Ok(note_type)
126    }
127}
128
129// TESTS
130// ================================================================================================
131
132#[cfg(test)]
133mod tests {
134    use assert_matches::assert_matches;
135
136    use super::*;
137    use crate::alloc::string::ToString;
138
139    #[rstest::rstest]
140    #[case::private(NoteType::Private)]
141    #[case::public(NoteType::Public)]
142    #[test]
143    fn test_note_type_roundtrip(#[case] note_type: NoteType) -> anyhow::Result<()> {
144        // String roundtrip
145        assert_eq!(note_type, note_type.to_string().parse()?);
146
147        // Serialization roundtrip
148        assert_eq!(note_type, NoteType::read_from_bytes(&note_type.to_bytes())?);
149
150        // Byte conversion roundtrip
151        assert_eq!(note_type, NoteType::try_from(note_type.as_u8())?);
152
153        // Felt conversion roundtrip
154        assert_eq!(note_type, NoteType::try_from(Felt::from(note_type))?);
155
156        Ok(())
157    }
158
159    #[test]
160    fn test_from_str_note_type() {
161        for string in ["private", "public"] {
162            let parsed_note_type = NoteType::from_str(string).unwrap();
163            assert_eq!(parsed_note_type.to_string(), string);
164        }
165
166        let public_type_invalid_err = NoteType::from_str("puBlIc").unwrap_err();
167        assert_matches!(public_type_invalid_err, NoteError::UnknownNoteType(_));
168
169        let invalid_type = NoteType::from_str("invalid").unwrap_err();
170        assert_matches!(invalid_type, NoteError::UnknownNoteType(_));
171    }
172}