ergotree_ir/mir/
upcast.rs

1//! Numerical upcast
2
3use super::expr::Expr;
4use super::expr::InvalidArgumentError;
5use crate::serialization::op_code::OpCode;
6use crate::serialization::sigma_byte_reader::SigmaByteRead;
7use crate::serialization::sigma_byte_writer::SigmaByteWrite;
8use crate::serialization::SigmaParsingError;
9use crate::serialization::SigmaSerializable;
10use crate::serialization::SigmaSerializeResult;
11use crate::types::stype::SType;
12
13use crate::has_opcode::HasStaticOpCode;
14
15/// Numerical upcast
16#[derive(PartialEq, Eq, Debug, Clone)]
17pub struct Upcast {
18    /// Numerical value to be upcasted
19    pub input: Box<Expr>,
20    /// Target type for the input value to be upcasted to
21    pub tpe: SType,
22}
23
24impl Upcast {
25    /// Create new object, returns an error if any of the requirements failed
26    pub fn new(input: Expr, target_tpe: SType) -> Result<Self, InvalidArgumentError> {
27        if !target_tpe.is_numeric() {
28            return Err(InvalidArgumentError(format!(
29                "Upcast: expected target type to be numeric, got {:?}",
30                target_tpe
31            )));
32        }
33        let post_eval_tpe = input.post_eval_tpe();
34        if post_eval_tpe.is_numeric() {
35            Ok(Self {
36                input: input.into(),
37                tpe: target_tpe,
38            })
39        } else {
40            Err(InvalidArgumentError(format!(
41                "Upcast: expected input value type to be numeric, got {:?}",
42                post_eval_tpe
43            )))
44        }
45    }
46
47    /// Type
48    pub fn tpe(&self) -> SType {
49        self.tpe.clone()
50    }
51}
52
53impl HasStaticOpCode for Upcast {
54    const OP_CODE: OpCode = OpCode::UPCAST;
55}
56
57impl SigmaSerializable for Upcast {
58    fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
59        self.input.sigma_serialize(w)?;
60        self.tpe.sigma_serialize(w)
61    }
62
63    fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
64        let input = Expr::sigma_parse(r)?.into();
65        let tpe = SType::sigma_parse(r)?;
66        Ok(Upcast { input, tpe })
67    }
68}
69
70#[cfg(feature = "arbitrary")]
71#[allow(clippy::unwrap_used)]
72/// Arbitrary impl
73mod arbitrary {
74    use crate::mir::expr::arbitrary::ArbExprParams;
75
76    use super::*;
77    use proptest::prelude::*;
78
79    impl Arbitrary for Upcast {
80        type Parameters = ();
81        type Strategy = BoxedStrategy<Self>;
82
83        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
84            any_with::<Expr>(ArbExprParams {
85                tpe: SType::SInt,
86                depth: 2,
87            })
88            .prop_map(|input| Upcast::new(input, SType::SLong).unwrap())
89            .boxed()
90        }
91    }
92}
93
94#[cfg(test)]
95#[cfg(feature = "arbitrary")]
96#[allow(clippy::panic)]
97pub mod proptests {
98
99    use super::*;
100    use crate::serialization::sigma_serialize_roundtrip;
101    use proptest::prelude::*;
102
103    proptest! {
104
105        #[test]
106        fn ser_roundtrip(v in any::<Upcast>()) {
107            let expr: Expr = v.into();
108            prop_assert_eq![sigma_serialize_roundtrip(&expr), expr];
109        }
110    }
111}