1use core::cmp::Ordering;
25use core::str::FromStr;
26
27use amplify::confinement::ConfinedBlob;
28use amplify::num::u256;
29use strict_encoding::{StreamReader, StrictDecode, StrictEncode};
30use strict_types::typify::TypedVal;
31use strict_types::value::StrictNum;
32use strict_types::{SemId, StrictVal, TypeSystem};
33use ultrasonic::{StateData, StateValue};
34
35use crate::api::{TOTAL_BYTES, USED_FIEL_BYTES};
36use crate::{
37 ApiVm, StateAdaptor, StateArithm, StateAtom, StateCalc, StateCalcError, StateName, StateReader, StateTy, VmType,
38 LIB_NAME_SONIC,
39};
40
41#[derive(Clone, Debug)]
42pub struct EmbeddedProc;
43
44impl ApiVm for EmbeddedProc {
45 type Arithm = EmbeddedArithm;
46 type Reader = EmbeddedReaders;
47 type Adaptor = EmbeddedImmutable;
48
49 fn vm_type(&self) -> VmType { VmType::Embedded }
50}
51
52#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
53#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
54#[strict_type(lib = LIB_NAME_SONIC, tags = custom, dumb = Self::Count(strict_dumb!()))]
55#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
56pub enum EmbeddedReaders {
57 #[strict_type(tag = 1)]
60 Count(StateName),
61
62 #[strict_type(tag = 2)]
64 SumV(StateName),
65
66 #[strict_type(tag = 0x20)]
74 ListV(StateName),
75
76 #[strict_type(tag = 0x22)]
78 SetV(StateName),
79
80 #[strict_type(tag = 0x30)]
82 MapV2U(StateName),
83}
84
85impl StateReader for EmbeddedReaders {
86 fn read<'s, I: IntoIterator<Item = &'s StateAtom>>(&self, state: impl Fn(&StateName) -> I) -> StrictVal {
87 match self {
88 EmbeddedReaders::Count(name) => {
90 let count = state(name).into_iter().count();
91 svnum!(count as u64)
92 }
93 EmbeddedReaders::SumV(name) => {
94 let sum = state(name)
95 .into_iter()
96 .map(|atom| match &atom.verified {
97 StrictVal::Number(StrictNum::Uint(val)) => *val,
98 _ => panic!("invalid type of state for sum aggregator"),
99 })
100 .sum::<u64>();
101 svnum!(sum)
102 }
103 EmbeddedReaders::ListV(name) => StrictVal::List(
104 state(name)
105 .into_iter()
106 .map(|atom| atom.verified.clone())
107 .collect(),
108 ),
109 EmbeddedReaders::SetV(name) => StrictVal::Set(
110 state(name)
111 .into_iter()
112 .map(|atom| atom.verified.clone())
113 .collect(),
114 ),
115 EmbeddedReaders::MapV2U(name) => StrictVal::Map(
116 state(name)
117 .into_iter()
118 .filter_map(|atom| atom.unverified.clone().map(|u| (atom.verified.clone(), u)))
119 .collect(),
120 ),
121 }
122 }
123}
124
125#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
126#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
127#[strict_type(lib = LIB_NAME_SONIC)]
128#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
129pub struct EmbeddedImmutable(pub StateTy);
130
131impl EmbeddedImmutable {
132 fn convert_value(&self, sem_id: SemId, value: StateValue, sys: &TypeSystem) -> Option<StrictVal> {
133 let ty = value.get(0)?.to_u256();
135 if ty != self.0 {
136 return None;
137 }
138
139 let mut buf = [0u8; TOTAL_BYTES];
140 let mut i = 1u8;
141 while let Some(el) = value.get(i) {
142 let from = USED_FIEL_BYTES * (i - 1) as usize;
143 let to = USED_FIEL_BYTES * i as usize;
144 buf[from..to].copy_from_slice(&el.to_u256().to_le_bytes()[..USED_FIEL_BYTES]);
145 i += 1;
146 }
147 debug_assert!(i <= 4);
148
149 let mut cursor = StreamReader::cursor::<TOTAL_BYTES>(buf);
150 let mut val = sys.strict_read_type(sem_id, &mut cursor).ok()?.unbox();
153
154 loop {
155 if let StrictVal::Tuple(ref mut vec) = val {
156 if vec.len() == 1 {
157 val = vec.remove(0);
158 continue;
159 }
160 }
161 break;
162 }
163
164 Some(val)
165 }
166
167 fn build_value(&self, ser: ConfinedBlob<0, TOTAL_BYTES>) -> StateValue {
168 let mut elems = Vec::with_capacity(4);
169 elems.push(self.0);
170 for chunk in ser.chunks(USED_FIEL_BYTES) {
171 let mut buf = [0u8; u256::BYTES as usize];
172 buf[..chunk.len()].copy_from_slice(chunk);
173 elems.push(u256::from_le_bytes(buf));
174 }
175
176 StateValue::from_iter(elems)
177 }
178}
179
180impl StateAdaptor for EmbeddedImmutable {
181 fn convert_immutable(
182 &self,
183 sem_id: SemId,
184 raw_sem_id: SemId,
185 data: &StateData,
186 sys: &TypeSystem,
187 ) -> Option<StateAtom> {
188 let verified = self.convert_value(sem_id, data.value, sys)?;
189 let unverified = data
190 .raw
191 .as_ref()
192 .and_then(|raw| sys.strict_deserialize_type(raw_sem_id, raw.as_ref()).ok())
193 .map(TypedVal::unbox);
194 Some(StateAtom { verified, unverified })
195 }
196
197 fn convert_destructible(&self, sem_id: SemId, value: StateValue, sys: &TypeSystem) -> Option<StrictVal> {
198 self.convert_value(sem_id, value, sys)
199 }
200
201 fn build_immutable(&self, value: ConfinedBlob<0, TOTAL_BYTES>) -> StateValue { self.build_value(value) }
202
203 fn build_destructible(&self, value: ConfinedBlob<0, TOTAL_BYTES>) -> StateValue { self.build_value(value) }
204}
205
206#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
207#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
208#[strict_type(lib = LIB_NAME_SONIC, tags = repr, try_from_u8, into_u8)]
209#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
210#[repr(u8)]
211pub enum EmbeddedArithm {
212 #[strict_type(dumb)]
213 NonFungible = 0,
214 Fungible = 1,
215}
216
217impl StateArithm for EmbeddedArithm {
218 fn calculator(&self) -> Box<dyn StateCalc> {
219 match self {
220 EmbeddedArithm::NonFungible => Box::new(EmbeddedCalc::NonFungible(empty!())),
221 EmbeddedArithm::Fungible => Box::new(EmbeddedCalc::Fungible(StrictVal::Number(StrictNum::Uint(0)))),
222 }
223 }
224}
225
226#[derive(Clone, Eq, PartialEq, Debug)]
227pub enum EmbeddedCalc {
228 NonFungible(Vec<StrictVal>),
229 Fungible(StrictVal),
230}
231
232impl StateCalc for EmbeddedCalc {
233 fn compare(&self, state: &StrictVal, target: &StrictVal) -> Option<Ordering> {
234 match (state, target) {
235 (val, tgt) if val == tgt => Some(Ordering::Equal),
236 (StrictVal::Number(StrictNum::Uint(val)), StrictVal::String(s)) if u64::from_str(s).is_ok() => {
238 Some(val.cmp(&unsafe { u64::from_str(s).unwrap_unchecked() }))
239 }
240 (StrictVal::Number(StrictNum::Uint(val)), StrictVal::Number(StrictNum::Uint(tgt))) => Some(val.cmp(tgt)),
241 _ => None,
242 }
243 }
244
245 fn accumulate(&mut self, state: &StrictVal) -> Result<(), StateCalcError> {
246 match self {
247 EmbeddedCalc::NonFungible(states) => {
248 states.push(state.clone());
249 Ok(())
250 }
251 EmbeddedCalc::Fungible(value) => {
252 let (val, add) = match (state, value) {
253 (StrictVal::String(s), StrictVal::Number(StrictNum::Uint(val))) if u64::from_str(s).is_ok() => {
255 let add = unsafe { u64::from_str(s).unwrap_unchecked() };
256 (val, add)
257 }
258 (StrictVal::Number(StrictNum::Uint(add)), StrictVal::Number(StrictNum::Uint(val))) => (val, *add),
259 _ => return Err(StateCalcError::UncountableState),
260 };
261 *val = val.checked_add(add).ok_or(StateCalcError::Overflow)?;
262 Ok(())
263 }
264 }
265 }
266
267 fn lessen(&mut self, state: &StrictVal) -> Result<(), StateCalcError> {
268 match self {
269 EmbeddedCalc::NonFungible(states) => {
270 if let Some(pos) = states.iter().position(|s| s == state) {
271 states.remove(pos);
272 Ok(())
273 } else {
274 Err(StateCalcError::UncountableState)
275 }
276 }
277 EmbeddedCalc::Fungible(value) => {
278 let (val, dec) = match (state, value) {
279 (StrictVal::String(s), StrictVal::Number(StrictNum::Uint(val))) if u64::from_str(s).is_ok() => {
281 let dec = unsafe { u64::from_str(s).unwrap_unchecked() };
282 (val, dec)
283 }
284 (StrictVal::Number(StrictNum::Uint(dec)), StrictVal::Number(StrictNum::Uint(val))) => (val, *dec),
285 _ => return Err(StateCalcError::UncountableState),
286 };
287 if dec > *val {
288 return Err(StateCalcError::Overflow);
289 }
290 *val -= dec;
291 Ok(())
292 }
293 }
294 }
295
296 fn diff(&self) -> Result<Vec<StrictVal>, StateCalcError> {
297 Ok(match self {
298 EmbeddedCalc::NonFungible(items) => items.clone(),
299 EmbeddedCalc::Fungible(value) => match value {
300 StrictVal::Number(StrictNum::Uint(val)) => {
301 if val.eq(&u64::MIN) {
302 vec![]
303 } else {
304 vec![value.clone()]
305 }
306 }
307 _ => return Err(StateCalcError::UncountableState),
308 },
309 })
310 }
311
312 fn is_satisfied(&self, target: &StrictVal) -> bool {
313 match self {
314 EmbeddedCalc::NonFungible(items) => items.contains(target),
315 EmbeddedCalc::Fungible(value) => {
316 if value == target {
317 true
318 } else if let StrictVal::Number(StrictNum::Uint(val)) = value {
319 if let StrictVal::Number(StrictNum::Uint(tgt)) = target {
320 val >= tgt
321 } else {
322 false
323 }
324 } else {
325 false
326 }
327 }
328 }
329 }
330}