actyx_sdk/event/
opaque.rs

1use crate::types::ArcVal;
2use libipld::{
3    cbor::DagCborCodec,
4    codec::{Decode, Encode},
5    raw_value::RawValue,
6};
7use serde::de::Error;
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9use std::sync::Arc;
10
11/// A ref-counted slice of memory holding a compact binary representation of an event payload
12///
13/// see [`Event::extract`](struct.Event.html#method.extract) for supported ways of using the
14/// data
15#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
16#[cfg_attr(feature = "dataflow", derive(Abomonation))]
17pub struct Opaque(ArcVal<[u8]>);
18
19impl Opaque {
20    pub fn new(bytes: Arc<[u8]>) -> Self {
21        Opaque(bytes.into())
22    }
23
24    pub fn from_bytes(bytes: &[u8]) -> Self {
25        Opaque(ArcVal::clone_from_unsized(bytes))
26    }
27
28    pub fn is_empty(&self) -> bool {
29        self.0.is_empty()
30    }
31
32    pub fn len(&self) -> usize {
33        self.0.len()
34    }
35
36    /// Rough estimate of the in memory size of an opaque value
37    pub fn rough_size(&self) -> usize {
38        self.len() + 16
39    }
40}
41
42impl AsRef<[u8]> for Opaque {
43    fn as_ref(&self) -> &[u8] {
44        self.0.as_ref()
45    }
46}
47
48impl Serialize for Opaque {
49    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
50        let mut deserializer = serde_cbor::Deserializer::from_slice(&self.0);
51        serde_transcode::transcode(&mut deserializer, serializer)
52    }
53}
54
55impl<'de> Deserialize<'de> for Opaque {
56    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
57        let res = Vec::new();
58        let mut serializer = serde_cbor::Serializer::new(res);
59        serde_transcode::transcode(deserializer, &mut serializer).map_err(D::Error::custom)?;
60        let res = serializer.into_inner();
61        Ok(Opaque(ArcVal::from_boxed(res.into())))
62    }
63}
64
65impl Encode<DagCborCodec> for Opaque {
66    fn encode<W: std::io::Write>(&self, _c: DagCborCodec, w: &mut W) -> anyhow::Result<()> {
67        // we know that an opaque contains cbor, so we just write it
68        Ok(w.write_all(self.as_ref())?)
69    }
70}
71
72impl Decode<DagCborCodec> for Opaque {
73    fn decode<R: std::io::Read + std::io::Seek>(c: DagCborCodec, r: &mut R) -> anyhow::Result<Self> {
74        let tmp = RawValue::<DagCborCodec>::decode(c, r)?;
75        Ok(Self(ArcVal::from_boxed(tmp.into())))
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use crate::from_cbor_me;
83    use libipld::codec::Codec;
84    use serde_json::json;
85
86    #[test]
87    fn opaque_dag_cbor_roundtrip() -> anyhow::Result<()> {
88        let text = "";
89        // using JSON value allows CBOR to use known-length array encoding
90        let o1: Opaque = serde_json::from_value(json!([text]))?;
91        let tmp = DagCborCodec.encode(&o1)?;
92        let expected = from_cbor_me(
93            r#"
9481     # array(1)
95   60  # text(0)
96       # ""
97"#,
98        )?;
99        assert_eq!(tmp, expected);
100        let o2: Opaque = DagCborCodec.decode(&tmp)?;
101        assert_eq!(o1, o2);
102        Ok(())
103    }
104
105    #[test]
106    fn u128_is_f64() {
107        // this test is to ensure that serde_json does not convert long integers to u128, which CBOR does not support
108        let text = format!("{}", u128::max_value());
109        let value: serde_json::Value = serde_json::from_str(&text).unwrap();
110        assert!(value.is_f64());
111    }
112
113    #[test]
114    fn i128_is_f64() {
115        // this test is to ensure that serde_json does not convert long signed integers to u128, which CBOR does not support
116        let text = format!("{}", i128::min_value());
117        let value: serde_json::Value = serde_json::from_str(&text).unwrap();
118        assert!(value.is_f64());
119    }
120}