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