spacetimedb_vm/ops/
parse.rs

1use crate::errors::{ErrorType, ErrorVm};
2use spacetimedb_lib::{ConnectionId, Identity};
3use spacetimedb_sats::satn::Satn;
4use spacetimedb_sats::{i256, u256, AlgebraicType, AlgebraicValue, ProductType, SumType};
5use std::fmt::Display;
6use std::str::FromStr;
7
8fn _parse<F>(value: &str, ty: &AlgebraicType) -> Result<AlgebraicValue, ErrorVm>
9where
10    F: FromStr + Into<AlgebraicValue>,
11    <F as FromStr>::Err: Display,
12{
13    match value.parse::<F>() {
14        Ok(x) => Ok(x.into()),
15        Err(err) => Err(ErrorType::Parse {
16            value: value.to_string(),
17            ty: ty.to_satn(),
18            err: err.to_string(),
19        }
20        .into()),
21    }
22}
23
24/// Try to parse `tag_name` for a simple enum on `sum` into a valid `tag` value of `AlgebraicValue`
25pub fn parse_simple_enum(sum: &SumType, tag_name: &str) -> Result<AlgebraicValue, ErrorVm> {
26    if let Some((pos, _tag)) = sum.get_variant_simple(tag_name) {
27        Ok(AlgebraicValue::enum_simple(pos))
28    } else {
29        Err(ErrorVm::Unsupported(format!(
30            "Not found enum tag '{tag_name}' or not a simple enum: {}",
31            sum.to_satn_pretty()
32        )))
33    }
34}
35
36/// Try to parse `value` as [`Identity`] or [`ConnectionId`].
37pub fn parse_product(product: &ProductType, value: &str) -> Result<AlgebraicValue, ErrorVm> {
38    if product.is_identity() {
39        return Ok(Identity::from_hex(value.trim_start_matches("0x"))
40            .map_err(|err| ErrorVm::Other(err.into()))?
41            .into());
42    }
43    if product.is_connection_id() {
44        return Ok(ConnectionId::from_hex(value.trim_start_matches("0x"))
45            .map_err(ErrorVm::Other)?
46            .into());
47    }
48    Err(ErrorVm::Unsupported(format!(
49        "Can't parse '{value}' to {}",
50        product.to_satn_pretty()
51    )))
52}
53
54/// Parse a `&str` into [AlgebraicValue] using the supplied [AlgebraicType].
55///
56/// ```
57/// use spacetimedb_sats::{AlgebraicType, AlgebraicValue};
58/// use spacetimedb_vm::errors::ErrorLang;
59/// use spacetimedb_vm::ops::parse::parse;
60///
61/// assert_eq!(parse("1", &AlgebraicType::I32).map_err(ErrorLang::from), Ok(AlgebraicValue::I32(1)));
62/// assert_eq!(parse("true", &AlgebraicType::Bool).map_err(ErrorLang::from), Ok(AlgebraicValue::Bool(true)));
63/// assert_eq!(parse("1.0", &AlgebraicType::F64).map_err(ErrorLang::from), Ok(AlgebraicValue::F64(1.0f64.into())));
64/// assert_eq!(parse("Player", &AlgebraicType::simple_enum(["Player"].into_iter())).map_err(ErrorLang::from), Ok(AlgebraicValue::enum_simple(0)));
65/// assert!(parse("bananas", &AlgebraicType::I32).is_err());
66/// ```
67pub fn parse(value: &str, ty: &AlgebraicType) -> Result<AlgebraicValue, ErrorVm> {
68    match ty {
69        &AlgebraicType::Bool => _parse::<bool>(value, ty),
70        &AlgebraicType::I8 => _parse::<i8>(value, ty),
71        &AlgebraicType::U8 => _parse::<u8>(value, ty),
72        &AlgebraicType::I16 => _parse::<i16>(value, ty),
73        &AlgebraicType::U16 => _parse::<u16>(value, ty),
74        &AlgebraicType::I32 => _parse::<i32>(value, ty),
75        &AlgebraicType::U32 => _parse::<u32>(value, ty),
76        &AlgebraicType::I64 => _parse::<i64>(value, ty),
77        &AlgebraicType::U64 => _parse::<u64>(value, ty),
78        &AlgebraicType::I128 => _parse::<i128>(value, ty),
79        &AlgebraicType::U128 => _parse::<u128>(value, ty),
80        &AlgebraicType::I256 => _parse::<i256>(value, ty),
81        &AlgebraicType::U256 => _parse::<u256>(value, ty),
82        &AlgebraicType::F32 => _parse::<f32>(value, ty),
83        &AlgebraicType::F64 => _parse::<f64>(value, ty),
84        &AlgebraicType::String => Ok(AlgebraicValue::String(value.into())),
85        AlgebraicType::Sum(sum) => parse_simple_enum(sum, value),
86        AlgebraicType::Product(product) => parse_product(product, value),
87        x => Err(ErrorVm::Unsupported(format!(
88            "Can't parse '{value}' to {}",
89            x.to_satn_pretty()
90        ))),
91    }
92}