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}