mina_p2p_messages/
core.rs1use 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#[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
64pub type Error = Info;
66
67#[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}