Skip to main content

simfony/
str.rs

1//! Types for handling strings with invariants.
2
3use std::sync::Arc;
4
5/// Implementations for newtypes that wrap [`Arc<str>`].
6macro_rules! wrapped_string {
7    ($wrapper:ident, $name:expr) => {
8        impl $wrapper {
9            #[doc = "Create a"]
10            #[doc = $name]
11            #[doc = ".\n\n"]
12            #[doc = "## Precondition\n\n"]
13            #[doc = "The string must be a valid"]
14            #[doc = $name]
15            #[doc = ".\n\n"]
16            #[doc = "## Panics\n\n"]
17            #[doc = "Panics may occur down the line if the precondition is not satisfied."]
18            pub fn from_str_unchecked(s: &str) -> Self {
19                Self(Arc::from(s))
20            }
21
22            /// Access the inner string.
23            pub fn as_inner(&self) -> &str {
24                self.0.as_ref()
25            }
26
27            /// Make a cheap copy of the name.
28            pub fn shallow_clone(&self) -> Self {
29                Self(Arc::clone(&self.0))
30            }
31        }
32
33        impl std::fmt::Display for $wrapper {
34            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35                std::fmt::Display::fmt(&self.0, f)
36            }
37        }
38
39        impl std::fmt::Debug for $wrapper {
40            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41                std::fmt::Display::fmt(&self.0, f)
42            }
43        }
44    };
45}
46
47/// Implementation of [`arbitrary::Arbitrary`] for wrapped string types,
48/// such that strings of 1 to 10 letters `a` to `z` are generated.
49///
50/// The space of lowercase letter strings includes values that are invalid
51/// according to the grammar of the particular string type. For instance,
52/// keywords are reserved. However, this should not affect fuzzing.
53macro_rules! impl_arbitrary_lowercase_alpha {
54    ($wrapper:ident) => {
55        #[cfg(feature = "arbitrary")]
56        impl<'a> arbitrary::Arbitrary<'a> for $wrapper {
57            fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
58                let len = u.int_in_range(1..=10)?;
59                let mut string = String::with_capacity(len);
60                for _ in 0..len {
61                    let offset = u.int_in_range(0..=25)?;
62                    string.push((b'a' + offset) as char)
63                }
64                Ok(Self::from_str_unchecked(string.as_str()))
65            }
66        }
67    };
68}
69
70/// The name of a function.
71#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
72pub struct FunctionName(Arc<str>);
73
74impl FunctionName {
75    /// Return the name of the main function.
76    pub fn main() -> Self {
77        Self(Arc::from("main"))
78    }
79}
80
81wrapped_string!(FunctionName, "function name");
82
83#[cfg(feature = "arbitrary")]
84impl<'a> arbitrary::Arbitrary<'a> for FunctionName {
85    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
86        const RESERVED_NAMES: [&str; 11] = [
87            "unwrap_left",
88            "unwrap_right",
89            "for_while",
90            "is_none",
91            "unwrap",
92            "assert",
93            "panic",
94            "match",
95            "into",
96            "fold",
97            "dbg",
98        ];
99
100        let len = u.int_in_range(1..=10)?;
101        let mut string = String::with_capacity(len);
102        for _ in 0..len {
103            let offset = u.int_in_range(0..=25)?;
104            string.push((b'a' + offset) as char)
105        }
106        if RESERVED_NAMES.contains(&string.as_str()) {
107            string.push('_');
108        }
109
110        Ok(Self::from_str_unchecked(string.as_str()))
111    }
112}
113
114/// The identifier of a variable.
115#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
116pub struct Identifier(Arc<str>);
117
118wrapped_string!(Identifier, "variable identifier");
119impl_arbitrary_lowercase_alpha!(Identifier);
120
121/// The name of a witness.
122#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
123pub struct WitnessName(Arc<str>);
124
125wrapped_string!(WitnessName, "witness name");
126impl_arbitrary_lowercase_alpha!(WitnessName);
127
128/// The name of a jet.
129#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
130pub struct JetName(Arc<str>);
131
132wrapped_string!(JetName, "jet name");
133
134#[cfg(feature = "arbitrary")]
135impl<'a> arbitrary::Arbitrary<'a> for JetName {
136    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
137        u.choose(&simplicity::jet::Elements::ALL)
138            .map(simplicity::jet::Elements::to_string)
139            .map(Arc::from)
140            .map(Self)
141    }
142}
143
144/// The name of a type alias.
145#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
146pub struct AliasName(Arc<str>);
147
148wrapped_string!(AliasName, "name of a type alias");
149
150#[cfg(feature = "arbitrary")]
151impl<'a> arbitrary::Arbitrary<'a> for AliasName {
152    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
153        const RESERVED_NAMES: [&str; 37] = [
154            "Either",
155            "Option",
156            "bool",
157            "List",
158            "u128",
159            "u256",
160            "u16",
161            "u32",
162            "u64",
163            "u1",
164            "u2",
165            "u4",
166            "u8",
167            "Ctx8",
168            "Pubkey",
169            "Message64",
170            "Message",
171            "Signature",
172            "Scalar",
173            "Fe",
174            "Gej",
175            "Ge",
176            "Point",
177            "Height",
178            "Time",
179            "Distance",
180            "Duration",
181            "Lock",
182            "Outpoint",
183            "Confidential1",
184            "ExplicitAsset",
185            "Asset1",
186            "ExplicitAmount",
187            "Amount1",
188            "ExplicitNonce",
189            "Nonce",
190            "TokenAmount1",
191        ];
192
193        let len = u.int_in_range(1..=10)?;
194        let mut string = String::with_capacity(len);
195        for _ in 0..len {
196            let offset = u.int_in_range(0..=25)?;
197            string.push((b'a' + offset) as char)
198        }
199        if RESERVED_NAMES.contains(&string.as_str()) {
200            string.push('_');
201        }
202
203        Ok(Self::from_str_unchecked(string.as_str()))
204    }
205}
206
207/// A string of decimal digits.
208#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
209pub struct Decimal(Arc<str>);
210
211wrapped_string!(Decimal, "decimal string");
212
213#[cfg(feature = "arbitrary")]
214impl<'a> arbitrary::Arbitrary<'a> for Decimal {
215    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
216        let len = u.int_in_range(1..=10)?;
217        let mut string = String::with_capacity(len);
218        for _ in 0..len {
219            let offset = u.int_in_range(0..=9)?;
220            string.push((b'0' + offset) as char)
221        }
222        Ok(Self::from_str_unchecked(string.as_str()))
223    }
224}
225
226/// A string of binary digits.
227#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
228pub struct Binary(Arc<str>);
229
230wrapped_string!(Binary, "binary string");
231
232#[cfg(feature = "arbitrary")]
233impl<'a> arbitrary::Arbitrary<'a> for Binary {
234    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
235        let len = u.int_in_range(1..=10)?;
236        let mut string = String::with_capacity(len);
237        for _ in 0..len {
238            let offset = u.int_in_range(0..=1)?;
239            let bin_digit = (b'0' + offset) as char;
240            string.push(bin_digit);
241        }
242        Ok(Self::from_str_unchecked(string.as_str()))
243    }
244}
245
246/// A string of hexadecimal digits.
247#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
248pub struct Hexadecimal(Arc<str>);
249
250wrapped_string!(Hexadecimal, "hexadecimal string");
251
252#[cfg(feature = "arbitrary")]
253impl<'a> arbitrary::Arbitrary<'a> for Hexadecimal {
254    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
255        let len = u.int_in_range(1..=10)?;
256        let mut string = String::with_capacity(len);
257        for _ in 0..len {
258            let offset = u.int_in_range(0..=15)?;
259            let hex_digit = match offset {
260                0..=9 => (b'0' + offset) as char,
261                10..=15 => (b'a' + (offset - 10)) as char,
262                _ => unreachable!(),
263            };
264            string.push(hex_digit);
265        }
266        Ok(Self::from_str_unchecked(string.as_str()))
267    }
268}
269
270/// The name of a module.
271#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
272pub struct ModuleName(Arc<str>);
273
274impl ModuleName {
275    /// Return the name of the witness module.
276    pub fn witness() -> Self {
277        Self(Arc::from("witness"))
278    }
279
280    /// Return the name of the parameter module.
281    pub fn param() -> Self {
282        Self(Arc::from("param"))
283    }
284}
285
286wrapped_string!(ModuleName, "module name");