mina_p2p_messages/
core.rs

1//! Types from Janestreet's Core library.
2
3use std::net::IpAddr;
4
5use crate::{
6    string::{ByteString, CharString},
7    versioned::Versioned,
8};
9use binprot_derive::{BinProtRead, BinProtWrite};
10use serde::{Deserialize, Serialize};
11
12/// This type corresponds to `Bounded_types.Wrapped_error` OCaml type, but the
13/// structure is different. It only refrects the data that is passed over the
14/// wire (stringified sexp representation of the error)
15#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, derive_more::Display)]
16#[serde(into = "SexpString", try_from = "SexpString")]
17#[display(fmt = "{}", "String::from_utf8_lossy(&_0.to_bytes())")]
18pub struct Info(rsexp::Sexp);
19
20impl Info {
21    pub fn new(msg: &str) -> Self {
22        Info(rsexp::atom(msg.as_bytes()))
23    }
24}
25
26#[derive(Debug, thiserror::Error)]
27#[error("error parsing info sexp: {0:?}")]
28pub struct InfoFromSexpError(rsexp::Error);
29
30impl binprot::BinProtRead for Info {
31    fn binprot_read<R: std::io::Read + ?Sized>(r: &mut R) -> Result<Self, binprot::Error> {
32        let sexp = ByteString::binprot_read(r)?;
33        let parsed = rsexp::from_slice(&sexp)
34            .map_err(|e| binprot::Error::CustomError(Box::new(InfoFromSexpError(e))))?;
35        Ok(Info(parsed))
36    }
37}
38
39impl binprot::BinProtWrite for Info {
40    fn binprot_write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
41        ByteString::from(self.0.to_bytes()).binprot_write(w)
42    }
43}
44
45#[derive(Debug, Serialize, Deserialize)]
46#[serde(transparent)]
47pub struct SexpString(CharString);
48
49impl From<Info> for SexpString {
50    fn from(value: Info) -> Self {
51        SexpString(CharString::from(value.0.to_bytes()))
52    }
53}
54
55impl TryFrom<SexpString> for Info {
56    type Error = InfoFromSexpError;
57
58    fn try_from(value: SexpString) -> Result<Self, Self::Error> {
59        let parsed = rsexp::from_slice(&value.0).map_err(InfoFromSexpError)?;
60        Ok(Info(parsed))
61    }
62}
63
64/// Represents error processing an RPC request.
65pub type Error = Info;
66
67// TODO
68#[derive(Clone, Debug, Serialize, Deserialize, BinProtRead, BinProtWrite, PartialEq)]
69pub struct Time(f64);
70
71pub type InetAddrV1Versioned = Versioned<InetAddrV1, 1>;
72
73#[derive(
74    Clone, Debug, Serialize, Deserialize, PartialEq, Eq, derive_more::From, derive_more::Into,
75)]
76pub struct InetAddrV1(IpAddr);
77
78impl binprot::BinProtRead for InetAddrV1 {
79    fn binprot_read<R: std::io::Read + ?Sized>(r: &mut R) -> Result<Self, binprot::Error>
80    where
81        Self: Sized,
82    {
83        let s = binprot::SmallString1k::binprot_read(r)?;
84        let ip_addr: IpAddr =
85            s.0.parse()
86                .map_err(|e| binprot::Error::CustomError(Box::new(e)))?;
87        Ok(ip_addr.into())
88    }
89}
90
91impl binprot::BinProtWrite for InetAddrV1 {
92    fn binprot_write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
93        binprot::SmallString1k::from(self.0.to_string()).binprot_write(w)
94    }
95}
96
97#[cfg(test)]
98mod test {
99    use binprot::{BinProtRead, BinProtWrite};
100
101    use super::Info;
102
103    fn info_to_bytes(info: &Info) -> Vec<u8> {
104        let mut bytes = Vec::new();
105        info.binprot_write(&mut bytes).unwrap();
106        bytes
107    }
108
109    fn bytes_to_info(mut bytes: &[u8]) -> Info {
110        let info = Info::binprot_read(&mut bytes).unwrap();
111        assert!(bytes.is_empty());
112        info
113    }
114
115    #[test]
116    fn sexp_binprot() {
117        use rsexp::*;
118
119        let info = Info(atom(b"atom"));
120        let bytes = info_to_bytes(&info);
121        assert_eq!(&bytes, b"\x04atom");
122        assert_eq!(info, bytes_to_info(&bytes));
123
124        let info = Info(atom(b"atom atom"));
125        let bytes = info_to_bytes(&info);
126        assert_eq!(&bytes, b"\x0b\"atom atom\"");
127        assert_eq!(info, bytes_to_info(&bytes));
128    }
129}