snarkvm_circuit_types_string/
lib.rs1#![forbid(unsafe_code)]
17#![cfg_attr(test, allow(clippy::assertions_on_result_states))]
18
19extern crate snarkvm_console_types_string as console;
20
21pub mod identifier_literal;
22pub use identifier_literal::IdentifierLiteral;
23
24mod equal;
25mod helpers;
26
27#[cfg(test)]
28use console::TestRng;
29#[cfg(test)]
30use snarkvm_circuit_environment::assert_scope;
31
32use snarkvm_circuit_environment::prelude::*;
33use snarkvm_circuit_types_boolean::Boolean;
34use snarkvm_circuit_types_field::Field;
35use snarkvm_circuit_types_integers::U8;
36
37#[derive(Clone)]
38pub struct StringType<E: Environment> {
39 mode: Mode,
40 bytes: Vec<U8<E>>,
41 size_in_bytes: Field<E>,
42}
43
44impl<E: Environment> StringTrait for StringType<E> {}
45
46impl<E: Environment> Inject for StringType<E> {
47 type Primitive = console::StringType<E::Network>;
48
49 fn new(mode: Mode, string: Self::Primitive) -> Self {
51 let num_bytes =
53 console::Field::from_u32(u32::try_from(string.len()).unwrap_or_else(|error| E::halt(error.to_string())));
54
55 let expected_size_in_bytes = Field::constant(num_bytes);
59 let size_in_bytes = match mode.is_constant() {
61 true => expected_size_in_bytes.clone(),
62 false => Field::new(Mode::Private, num_bytes),
63 };
64 E::assert_eq(&expected_size_in_bytes, &size_in_bytes)
66 .expect("String size witness does not match expected size");
67
68 Self {
69 mode,
70 bytes: string.as_bytes().iter().map(|byte| U8::new(mode, console::Integer::new(*byte))).collect(),
71 size_in_bytes,
72 }
73 }
74}
75
76impl<E: Environment> Eject for StringType<E> {
77 type Primitive = console::StringType<E::Network>;
78
79 fn eject_mode(&self) -> Mode {
81 match self.bytes.is_empty() {
82 true => self.mode,
83 false => self.bytes.eject_mode(),
84 }
85 }
86
87 fn eject_value(&self) -> Self::Primitive {
89 let num_bytes = self.bytes.len();
91 match num_bytes <= E::MAX_STRING_BYTES as usize {
92 true => console::StringType::new(
93 &String::from_utf8(self.bytes.eject_value().into_iter().map(|byte| *byte).collect())
94 .unwrap_or_else(|error| E::halt(format!("Failed to eject a string value: {error}"))),
95 ),
96 false => E::halt(format!("Attempted to eject a string of size {num_bytes}")),
97 }
98 }
99}
100
101impl<E: Environment> Parser for StringType<E> {
102 #[inline]
104 fn parse(string: &str) -> ParserResult<Self> {
105 let (string, content) = console::StringType::parse(string)?;
107 let (string, mode) = opt(pair(tag("."), Mode::parse))(string)?;
109
110 match mode {
111 Some((_, mode)) => Ok((string, StringType::new(mode, content))),
112 None => Ok((string, StringType::new(Mode::Constant, content))),
113 }
114 }
115}
116
117impl<E: Environment> FromStr for StringType<E> {
118 type Err = Error;
119
120 #[inline]
122 fn from_str(string: &str) -> Result<Self> {
123 match Self::parse(string) {
124 Ok((remainder, object)) => {
125 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
127 Ok(object)
129 }
130 Err(error) => bail!("Failed to parse string. {error}"),
131 }
132 }
133}
134
135impl<E: Environment> TypeName for StringType<E> {
136 #[inline]
138 fn type_name() -> &'static str {
139 console::StringType::<E::Network>::type_name()
140 }
141}
142
143impl<E: Environment> Debug for StringType<E> {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 Display::fmt(self, f)
146 }
147}
148
149impl<E: Environment> Display for StringType<E> {
150 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151 write!(f, "{}.{}", self.eject_value(), self.eject_mode())
152 }
153}