1use alloc::borrow::{Cow, ToOwned};
16use core::cmp::Ordering;
17use core::ops::{Deref, DerefMut};
18
19use wasefire_error::{Code, Error};
20use wasefire_wire::Wire;
21
22#[derive(Debug, Default, Clone, Wire)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25#[wire(refine = Name::new)]
26pub struct Name<'a>(Cow<'a, str>);
27
28impl<'a> Deref for Name<'a> {
29 type Target = str;
30
31 fn deref(&self) -> &Self::Target {
32 &self.0
33 }
34}
35
36#[cfg(feature = "host")]
37impl<'a> core::str::FromStr for Name<'a> {
38 type Err = anyhow::Error;
39
40 fn from_str(input: &str) -> Result<Self, Self::Err> {
41 if let Some(bad) = input.chars().find(|x| !x.is_ascii_graphic()) {
42 anyhow::bail!("{input:?} contains {bad:?} which is not a graphic ASCII character");
43 }
44 Ok(Name(alloc::string::String::from(input).into()))
45 }
46}
47
48#[cfg(feature = "host")]
49impl<'a> core::fmt::Display for Name<'a> {
50 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51 self.0.fmt(f)
52 }
53}
54
55impl<'a> Name<'a> {
56 pub fn new(data: Cow<'a, str>) -> Result<Self, Error> {
57 if data.bytes().all(|x| x.is_ascii_graphic()) {
58 Ok(Self(data))
59 } else {
60 Err(Error::user(Code::InvalidArgument))
61 }
62 }
63
64 pub fn static_clone(&self) -> Name<'static> {
65 Name(Cow::Owned(<str as ToOwned>::to_owned(self)))
66 }
67
68 pub fn reborrow(&self) -> Name<'_> {
69 Name(<&str>::into(self))
70 }
71}
72
73#[derive(Debug, Default, Clone, Wire)]
78#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
79pub struct Hexa<'a>(pub Cow<'a, [u8]>);
80
81impl<'a> Deref for Hexa<'a> {
82 type Target = Cow<'a, [u8]>;
83
84 fn deref(&self) -> &Self::Target {
85 &self.0
86 }
87}
88
89impl<'a> DerefMut for Hexa<'a> {
90 fn deref_mut(&mut self) -> &mut Self::Target {
91 &mut self.0
92 }
93}
94
95#[cfg(feature = "host")]
96impl<'a> core::str::FromStr for Hexa<'a> {
97 type Err = anyhow::Error;
98
99 fn from_str(input: &str) -> Result<Self, Self::Err> {
100 match data_encoding::HEXLOWER_PERMISSIVE.decode(input.as_bytes()) {
101 Ok(x) => Ok(Hexa(x.into())),
102 Err(e) => anyhow::bail!("{input:?} is not hexadecimal: {e}"),
103 }
104 }
105}
106
107#[cfg(feature = "host")]
108impl<'a> core::fmt::Display for Hexa<'a> {
109 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
110 data_encoding::HEXLOWER.encode_display(&self.0).fmt(f)
111 }
112}
113
114impl<'a> PartialOrd for Hexa<'a> {
115 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
116 Some(self.cmp(other))
117 }
118}
119
120impl<'a> Ord for Hexa<'a> {
121 fn cmp(&self, other: &Self) -> Ordering {
122 let left = self.shrink();
123 let right = other.shrink();
124 left.len().cmp(&right.len()).then_with(|| left.cmp(right))
125 }
126}
127
128impl<'a> PartialEq for Hexa<'a> {
129 fn eq(&self, other: &Self) -> bool {
130 self.cmp(other).is_eq()
131 }
132}
133
134impl<'a> Eq for Hexa<'a> {}
135
136impl<'a> Hexa<'a> {
137 pub fn reborrow(&self) -> Hexa<'_> {
138 Hexa(<&[u8]>::into(self))
139 }
140
141 pub fn shrink(&self) -> &[u8] {
143 let mut result = &*self.0;
144 while let Some((&0, x)) = result.split_first() {
145 result = x;
146 }
147 result
148 }
149
150 pub fn extend(&mut self, len: usize) {
152 if len <= self.len() {
153 return;
154 }
155 let cur = self.0.to_mut();
156 let mid = cur.len();
157 cur.resize(len, 0);
158 cur.rotate_left(mid);
159 }
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Wire)]
163#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
164pub enum AppletKind {
165 Wasm,
166 Pulley,
167 Native,
168}
169
170#[cfg(feature = "host")]
171impl AppletKind {
172 pub fn name(&self) -> &'static str {
173 match self {
174 AppletKind::Wasm => "wasm",
175 AppletKind::Pulley => "pulley",
176 AppletKind::Native => "native",
177 }
178 }
179}
180
181#[cfg(feature = "host")]
182impl core::fmt::Display for AppletKind {
183 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
184 self.name().fmt(f)
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 #[test]
193 fn version_cmp() {
194 #[track_caller]
195 fn test(left: &[u8], right: &[u8], expected: Ordering) {
196 let actual = Hexa(left.into()).cmp(&Hexa(right.into()));
197 assert_eq!(actual, expected);
198 }
199 test(&[], &[], Ordering::Equal);
200 test(&[0], &[], Ordering::Equal);
201 test(&[], &[0], Ordering::Equal);
202 test(&[0], &[0], Ordering::Equal);
203 test(&[], &[1], Ordering::Less);
204 test(&[1], &[], Ordering::Greater);
205 test(&[1], &[0, 0], Ordering::Greater);
206 test(&[1, 2], &[2, 1], Ordering::Less);
207 }
208
209 #[test]
210 fn version_extend() {
211 #[track_caller]
212 fn test(input: &[u8], len: usize, expected: &[u8]) {
213 let mut actual = Hexa(input.into());
214 actual.extend(len);
215 assert_eq!(&**actual, expected);
216 let mut actual = Hexa(input.to_vec().into());
217 actual.extend(len);
218 assert_eq!(&**actual, expected);
219 }
220 test(&[], 0, &[]);
221 test(&[], 2, &[0, 0]);
222 test(&[1, 1], 0, &[1, 1]);
223 test(&[1, 2], 6, &[0, 0, 0, 0, 1, 2]);
224 }
225}