valence_protocol/impls/
string.rs

1use std::io::Write;
2use std::str::FromStr;
3
4use anyhow::{ensure, Context};
5use valence_text::Text;
6
7use crate::{Bounded, Decode, Encode, VarInt};
8
9const DEFAULT_MAX_STRING_CHARS: usize = 32767;
10const MAX_TEXT_CHARS: usize = 262144;
11
12impl Encode for str {
13    fn encode(&self, w: impl Write) -> anyhow::Result<()> {
14        Bounded::<_, DEFAULT_MAX_STRING_CHARS>(self).encode(w)
15    }
16}
17
18impl<const MAX_CHARS: usize> Encode for Bounded<&'_ str, MAX_CHARS> {
19    fn encode(&self, mut w: impl Write) -> anyhow::Result<()> {
20        let char_count = self.encode_utf16().count();
21
22        ensure!(
23            char_count <= MAX_CHARS,
24            "char count of string exceeds maximum (expected <= {MAX_CHARS}, got {char_count})"
25        );
26
27        VarInt(self.len() as i32).encode(&mut w)?;
28        Ok(w.write_all(self.as_bytes())?)
29    }
30}
31
32impl<'a> Decode<'a> for &'a str {
33    fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
34        Ok(Bounded::<_, DEFAULT_MAX_STRING_CHARS>::decode(r)?.0)
35    }
36}
37
38impl<'a, const MAX_CHARS: usize> Decode<'a> for Bounded<&'a str, MAX_CHARS> {
39    fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self> {
40        let len = VarInt::decode(r)?.0;
41        ensure!(len >= 0, "attempt to decode string with negative length");
42        let len = len as usize;
43        ensure!(
44            len <= r.len(),
45            "not enough data remaining ({} bytes) to decode string of {len} bytes",
46            r.len()
47        );
48
49        let (res, remaining) = r.split_at(len);
50        let res = std::str::from_utf8(res)?;
51
52        let char_count = res.encode_utf16().count();
53        ensure!(
54            char_count <= MAX_CHARS,
55            "char count of string exceeds maximum (expected <= {MAX_CHARS}, got {char_count})"
56        );
57
58        *r = remaining;
59
60        Ok(Bounded(res))
61    }
62}
63
64impl Encode for String {
65    fn encode(&self, w: impl Write) -> anyhow::Result<()> {
66        self.as_str().encode(w)
67    }
68}
69
70impl<const MAX_CHARS: usize> Encode for Bounded<String, MAX_CHARS> {
71    fn encode(&self, w: impl Write) -> anyhow::Result<()> {
72        Bounded::<_, MAX_CHARS>(self.as_str()).encode(w)
73    }
74}
75
76impl Decode<'_> for String {
77    fn decode(r: &mut &[u8]) -> anyhow::Result<Self> {
78        Ok(<&str>::decode(r)?.into())
79    }
80}
81
82impl<const MAX_CHARS: usize> Decode<'_> for Bounded<String, MAX_CHARS> {
83    fn decode(r: &mut &'_ [u8]) -> anyhow::Result<Self> {
84        Ok(Bounded(Bounded::<&str, MAX_CHARS>::decode(r)?.0.into()))
85    }
86}
87
88impl Decode<'_> for Box<str> {
89    fn decode(r: &mut &[u8]) -> anyhow::Result<Self> {
90        Ok(<&str>::decode(r)?.into())
91    }
92}
93
94impl<const MAX_CHARS: usize> Decode<'_> for Bounded<Box<str>, MAX_CHARS> {
95    fn decode(r: &mut &'_ [u8]) -> anyhow::Result<Self> {
96        Ok(Bounded(Bounded::<&str, MAX_CHARS>::decode(r)?.0.into()))
97    }
98}
99
100impl Encode for Text {
101    fn encode(&self, w: impl Write) -> anyhow::Result<()> {
102        let s = serde_json::to_string(self).context("serializing text JSON")?;
103
104        Bounded::<_, MAX_TEXT_CHARS>(s).encode(w)
105    }
106}
107
108impl Decode<'_> for Text {
109    fn decode(r: &mut &[u8]) -> anyhow::Result<Self> {
110        let str = Bounded::<&str, MAX_TEXT_CHARS>::decode(r)?.0;
111
112        Self::from_str(str).context("deserializing text JSON")
113    }
114}