librqbit_bencode/
bencode_value.rs

1use std::{collections::HashMap, fmt::Display, marker::PhantomData};
2
3use buffers::{ByteBuf, ByteBufOwned};
4use bytes::Bytes;
5use clone_to_owned::CloneToOwned;
6use serde::{Deserialize, Deserializer, Serialize};
7
8use crate::serde_bencode_de::from_bytes;
9
10pub fn dyn_from_bytes<'de, BufT>(buf: &'de [u8]) -> anyhow::Result<BencodeValue<BufT>>
11where
12    BufT: From<&'de [u8]> + std::hash::Hash + Eq,
13{
14    from_bytes(buf)
15}
16
17impl<BufT: serde::Serialize + Eq + std::hash::Hash> serde::Serialize for BencodeValue<BufT> {
18    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
19    where
20        S: serde::Serializer,
21    {
22        match self {
23            BencodeValue::Bytes(b) => b.serialize(serializer),
24            BencodeValue::Integer(v) => v.serialize(serializer),
25            BencodeValue::List(l) => l.serialize(serializer),
26            BencodeValue::Dict(d) => d.serialize(serializer),
27        }
28    }
29}
30
31impl<'de, BufT> serde::de::Deserialize<'de> for BencodeValue<BufT>
32where
33    BufT: From<&'de [u8]> + std::hash::Hash + Eq,
34{
35    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
36    where
37        D: Deserializer<'de>,
38    {
39        struct Visitor<BufT> {
40            buftype: PhantomData<BufT>,
41        }
42
43        impl<'de, BufT> serde::de::Visitor<'de> for Visitor<BufT>
44        where
45            BufT: From<&'de [u8]> + std::hash::Hash + Eq,
46        {
47            type Value = BencodeValue<BufT>;
48
49            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
50                write!(formatter, "a bencode value")
51            }
52
53            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
54            where
55                E: serde::de::Error,
56            {
57                Ok(BencodeValue::Integer(v))
58            }
59
60            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
61            where
62                A: serde::de::SeqAccess<'de>,
63            {
64                let mut v = Vec::new();
65                while let Some(value) = seq.next_element()? {
66                    v.push(value);
67                }
68                Ok(BencodeValue::List(v))
69            }
70
71            fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
72            where
73                E: serde::de::Error,
74            {
75                Ok(BencodeValue::Bytes(BufT::from(v)))
76            }
77
78            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
79            where
80                A: serde::de::MapAccess<'de>,
81            {
82                let mut hmap = HashMap::new();
83                while let Some(key) = map.next_key::<&'de [u8]>()? {
84                    let value = map.next_value()?;
85                    hmap.insert(BufT::from(key), value);
86                }
87                Ok(BencodeValue::Dict(hmap))
88            }
89        }
90
91        deserializer.deserialize_any(Visitor {
92            buftype: PhantomData,
93        })
94    }
95}
96
97// A dynamic value when we don't know exactly what we are deserializing.
98// Useful for debugging.
99
100#[derive(PartialEq, Eq)]
101pub enum BencodeValue<BufT: std::hash::Hash + Eq> {
102    Bytes(BufT),
103    Integer(i64),
104    List(Vec<BencodeValue<BufT>>),
105    Dict(HashMap<BufT, BencodeValue<BufT>>),
106}
107
108impl<BufT: std::fmt::Debug + std::hash::Hash + Eq> std::fmt::Debug for BencodeValue<BufT> {
109    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110        match self {
111            BencodeValue::Bytes(b) => std::fmt::Debug::fmt(b, f),
112            BencodeValue::Integer(i) => std::fmt::Debug::fmt(i, f),
113            BencodeValue::List(l) => std::fmt::Debug::fmt(l, f),
114            BencodeValue::Dict(d) => std::fmt::Debug::fmt(d, f),
115        }
116    }
117}
118
119impl<BufT> CloneToOwned for BencodeValue<BufT>
120where
121    BufT: CloneToOwned + std::hash::Hash + Eq,
122    <BufT as CloneToOwned>::Target: Eq + std::hash::Hash,
123{
124    type Target = BencodeValue<<BufT as CloneToOwned>::Target>;
125
126    fn clone_to_owned(&self, within_buffer: Option<&Bytes>) -> Self::Target {
127        match self {
128            BencodeValue::Bytes(b) => BencodeValue::Bytes(b.clone_to_owned(within_buffer)),
129            BencodeValue::Integer(i) => BencodeValue::Integer(*i),
130            BencodeValue::List(l) => BencodeValue::List(l.clone_to_owned(within_buffer)),
131            BencodeValue::Dict(d) => BencodeValue::Dict(d.clone_to_owned(within_buffer)),
132        }
133    }
134}
135
136pub type BencodeValueBorrowed<'a> = BencodeValue<ByteBuf<'a>>;
137pub type BencodeValueOwned = BencodeValue<ByteBufOwned>;
138
139// A wrapper to deserialize dyn values as strings.
140#[derive(PartialEq, Eq, Hash)]
141pub struct AsDisplay<T>(T);
142
143impl<'de, T> From<&'de [u8]> for AsDisplay<T>
144where
145    T: From<&'de [u8]>,
146{
147    fn from(value: &'de [u8]) -> Self {
148        Self(T::from(value))
149    }
150}
151
152impl<T> Serialize for AsDisplay<T>
153where
154    T: Display,
155{
156    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
157    where
158        S: serde::Serializer,
159    {
160        serializer.serialize_str(&format!("{}", self.0))
161    }
162}
163
164impl<'de, T> Deserialize<'de> for AsDisplay<T>
165where
166    T: Deserialize<'de>,
167{
168    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
169    where
170        D: Deserializer<'de>,
171    {
172        let value = T::deserialize(deserializer)?;
173        Ok(AsDisplay(value))
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use crate::serde_bencode_ser::bencode_serialize_to_writer;
180
181    use super::*;
182    use serde::Serialize;
183    use std::io::Read;
184
185    #[test]
186    fn test_deserialize_torrent_dyn() {
187        let mut buf = Vec::new();
188        let filename = "../librqbit/resources/ubuntu-21.04-desktop-amd64.iso.torrent";
189        std::fs::File::open(filename)
190            .unwrap()
191            .read_to_end(&mut buf)
192            .unwrap();
193
194        let torrent_borrowed: BencodeValueBorrowed = from_bytes(&buf).unwrap();
195        let torrent_owned: BencodeValueOwned = from_bytes(&buf).unwrap();
196        dbg!(torrent_borrowed);
197        dbg!(torrent_owned);
198    }
199
200    #[test]
201    fn test_serialize_torrent_dyn() {
202        let mut buf = Vec::new();
203        let filename = "../librqbit/resources/ubuntu-21.04-desktop-amd64.iso.torrent";
204        std::fs::File::open(filename)
205            .unwrap()
206            .read_to_end(&mut buf)
207            .unwrap();
208
209        let torrent: BencodeValueBorrowed = from_bytes(&buf).unwrap();
210
211        let mut buf = Vec::<u8>::new();
212        bencode_serialize_to_writer(&torrent, &mut buf).unwrap();
213
214        let new_torrent = from_bytes(&buf).unwrap();
215        assert_eq!(torrent, new_torrent);
216    }
217
218    #[test]
219    fn test_serialize_struct_with_option() {
220        #[derive(Serialize)]
221        struct Test {
222            f1: i64,
223            #[serde(skip_serializing_if = "Option::is_none")]
224            missing: Option<i64>,
225        }
226        let test = Test {
227            f1: 100,
228            missing: None,
229        };
230        let mut buf = Vec::<u8>::new();
231        bencode_serialize_to_writer(&test, &mut buf).unwrap();
232        assert_eq!(&buf, b"d2:f1i100ee");
233    }
234}