miden_mast_package/package/
section.rs1use alloc::{
2 borrow::{Cow, ToOwned},
3 format,
4 string::ToString,
5};
6use core::{fmt, str::FromStr};
7
8use miden_assembly_syntax::DisplayHex;
9use miden_core::serde::{
10 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
11};
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15#[derive(Debug, Clone, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18#[cfg_attr(feature = "serde", serde(transparent))]
19#[repr(transparent)]
20pub struct SectionId(Cow<'static, str>);
21
22impl SectionId {
23 pub const DEBUG_TYPES: Self = Self(Cow::Borrowed("debug_types"));
26 pub const DEBUG_SOURCES: Self = Self(Cow::Borrowed("debug_sources"));
28 pub const DEBUG_FUNCTIONS: Self = Self(Cow::Borrowed("debug_functions"));
30 pub const ACCOUNT_COMPONENT_METADATA: Self = Self(Cow::Borrowed("account_component_metadata"));
36
37 pub fn custom(name: impl AsRef<str>) -> Result<Self, InvalidSectionIdError> {
43 let name = name.as_ref();
44 if !name.starts_with(|c: char| c.is_ascii_alphabetic() || c == '_') {
45 return Err(InvalidSectionIdError::InvalidStart);
46 }
47 if name.contains(|c: char| !c.is_ascii_alphanumeric() && !matches!(c, '.' | '_' | '-')) {
48 return Err(InvalidSectionIdError::InvalidCharacter);
49 }
50 Ok(Self(name.to_string().into()))
51 }
52
53 #[inline]
55 pub fn as_str(&self) -> &str {
56 self.0.as_ref()
57 }
58}
59
60#[derive(Debug, thiserror::Error)]
61pub enum InvalidSectionIdError {
62 #[error("invalid section id: cannot be empty")]
63 Empty,
64 #[error(
65 "invalid section id: contains invalid characters, only the set [a-z0-9._-] are allowed"
66 )]
67 InvalidCharacter,
68 #[error("invalid section id: must start with a character in the set [a-z_]")]
69 InvalidStart,
70}
71
72impl FromStr for SectionId {
73 type Err = InvalidSectionIdError;
74 fn from_str(s: &str) -> Result<Self, Self::Err> {
75 match s {
76 "debug_types" => Ok(Self::DEBUG_TYPES),
77 "debug_sources" => Ok(Self::DEBUG_SOURCES),
78 "debug_functions" => Ok(Self::DEBUG_FUNCTIONS),
79 "account_component_metadata" => Ok(Self::ACCOUNT_COMPONENT_METADATA),
80 custom => Self::custom(custom),
81 }
82 }
83}
84
85impl fmt::Display for SectionId {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 f.write_str(self.as_str())
88 }
89}
90
91#[derive(Clone, PartialEq, Eq)]
92#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
93pub struct Section {
94 pub id: SectionId,
95 pub data: Cow<'static, [u8]>,
96}
97
98impl fmt::Debug for Section {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 let verbose = f.alternate();
101 let mut builder = f.debug_struct("Section");
102 builder.field("id", &format_args!("{}", &self.id));
103 if verbose {
104 builder.field("data", &format_args!("{}", DisplayHex(&self.data))).finish()
105 } else {
106 builder.field("data", &format_args!("{} bytes", self.data.len())).finish()
107 }
108 }
109}
110
111impl Section {
112 pub fn new<B>(id: SectionId, data: B) -> Self
113 where
114 B: Into<Cow<'static, [u8]>>,
115 {
116 Self { id, data: data.into() }
117 }
118
119 pub fn is_empty(&self) -> bool {
121 self.data.is_empty()
122 }
123
124 pub fn len(&self) -> usize {
126 self.data.len()
127 }
128}
129
130impl Serializable for Section {
131 fn write_into<W: ByteWriter>(&self, target: &mut W) {
132 let id = self.id.as_str();
133 target.write_usize(id.len());
134 target.write_bytes(id.as_bytes());
135 target.write_usize(self.len());
136 target.write_bytes(&self.data);
137 }
138}
139
140impl Deserializable for Section {
141 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
142 let id_len = source.read_usize()?;
143 let id_bytes = source.read_slice(id_len)?;
144 let id_str = core::str::from_utf8(id_bytes).map_err(|err| {
145 DeserializationError::InvalidValue(format!("invalid utf-8 in section name: {err}"))
146 })?;
147 let id = SectionId(Cow::Owned(id_str.to_owned()));
148
149 let len = source.read_usize()?;
150 let bytes = source.read_slice(len)?;
151 Ok(Section { id, data: Cow::Owned(bytes.to_owned()) })
152 }
153}