mcproto_types/
json_text_component.rs1use std::io::{Read, Write};
2
3use mcproto_codec::{
4 error::{CodecError, CodecKind, CodecOperation, InvalidEncodingReason},
5 io::{read_exact_counted, write_all_counted},
6 varint::{VarIntRead, VarIntWrite},
7};
8
9use crate::{TypeCodec, component::JsonComponent};
10
11pub use serde_json::Value as JsonValue;
12
13#[derive(Debug, Clone, PartialEq)]
15pub struct JsonTextComponent(pub JsonComponent);
16
17impl JsonTextComponent {
18 pub const MAX_DECODE_UTF16_CODE_UNITS: usize = 262_144;
19 pub const MAX_DECODE_BYTES: usize = Self::MAX_DECODE_UTF16_CODE_UNITS * 3;
20 pub const MAX_DECODE_ENCODED_BYTES: usize = Self::MAX_DECODE_BYTES + 3;
21
22 pub const MAX_ENCODE_UTF16_CODE_UNITS: usize = 32_767;
24 pub const MAX_ENCODE_BYTES: usize = Self::MAX_ENCODE_UTF16_CODE_UNITS * 3;
25 pub const MAX_ENCODE_ENCODED_BYTES: usize = Self::MAX_ENCODE_BYTES + 3;
26
27 const MAX_COMPONENT_DEPTH: usize = 512;
28
29 pub fn text(value: impl Into<String>) -> Self {
30 Self(JsonComponent::text(value))
31 }
32
33 pub fn from_json_str(value: &str) -> Result<Self, serde_json::Error> {
34 serde_json::from_str(value).map(Self)
35 }
36
37 fn validate_length(
38 value: &str,
39 max_code_units: usize,
40 max_bytes: usize,
41 operation: CodecOperation,
42 bytes_processed: usize,
43 ) -> Result<(), CodecError> {
44 if value.len() > max_bytes {
45 return Err(CodecError::invalid_encoding_for_operation(
46 CodecKind::JsonTextComponent,
47 operation,
48 bytes_processed,
49 InvalidEncodingReason::StringTooLong { max_bytes },
50 ));
51 }
52 if value.encode_utf16().count() > max_code_units {
53 return Err(CodecError::invalid_encoding_for_operation(
54 CodecKind::JsonTextComponent,
55 operation,
56 bytes_processed,
57 InvalidEncodingReason::TooManyUtf16CodeUnits { max_code_units },
58 ));
59 }
60 Ok(())
61 }
62
63 fn invalid_json(
64 operation: CodecOperation,
65 bytes_processed: usize,
66 source: impl std::error::Error + Send + Sync + 'static,
67 ) -> CodecError {
68 CodecError::invalid_encoding_for_operation_with_source(
69 CodecKind::JsonTextComponent,
70 operation,
71 bytes_processed,
72 InvalidEncodingReason::InvalidJson,
73 source,
74 )
75 }
76}
77
78impl Default for JsonTextComponent {
79 fn default() -> Self {
80 Self::text("")
81 }
82}
83
84impl From<JsonComponent> for JsonTextComponent {
85 fn from(value: JsonComponent) -> Self {
86 Self(value)
87 }
88}
89
90impl From<String> for JsonTextComponent {
91 fn from(value: String) -> Self {
92 Self::text(value)
93 }
94}
95
96impl From<&str> for JsonTextComponent {
97 fn from(value: &str) -> Self {
98 Self::text(value)
99 }
100}
101
102impl TypeCodec for JsonTextComponent {
103 fn encode(&self, writer: &mut impl Write) -> Result<(), CodecError> {
104 self.0
105 .validate_depth(Self::MAX_COMPONENT_DEPTH)
106 .map_err(|source| Self::invalid_json(CodecOperation::Write, 0, source))?;
107 let json = serde_json::to_string(&self.0)
108 .map_err(|source| Self::invalid_json(CodecOperation::Write, 0, source))?;
109 Self::validate_length(
110 &json,
111 Self::MAX_ENCODE_UTF16_CODE_UNITS,
112 Self::MAX_ENCODE_BYTES,
113 CodecOperation::Write,
114 0,
115 )?;
116
117 let bytes = json.as_bytes();
118 let prefix_size = writer
119 .write_varint_with_size(bytes.len() as i32)
120 .map_err(|error| error.with_context(CodecKind::JsonTextComponent))?;
121 write_all_counted(writer, bytes, CodecKind::JsonTextComponent, prefix_size)
122 }
123
124 fn decode(reader: &mut impl Read) -> Result<Self, CodecError> {
125 let (byte_length, prefix_size) = reader
126 .read_varint_with_size()
127 .map_err(|error| error.with_context(CodecKind::JsonTextComponent))?;
128 let byte_length = usize::try_from(byte_length).map_err(|_| {
129 CodecError::invalid_encoding(
130 CodecKind::JsonTextComponent,
131 prefix_size,
132 InvalidEncodingReason::NegativeLength { value: byte_length },
133 )
134 })?;
135 if byte_length > Self::MAX_DECODE_BYTES {
136 return Err(CodecError::invalid_encoding(
137 CodecKind::JsonTextComponent,
138 prefix_size,
139 InvalidEncodingReason::StringTooLong {
140 max_bytes: Self::MAX_DECODE_BYTES,
141 },
142 ));
143 }
144
145 let mut bytes = vec![0; byte_length];
146 read_exact_counted(
147 reader,
148 &mut bytes,
149 CodecKind::JsonTextComponent,
150 prefix_size,
151 )?;
152 let bytes_processed = prefix_size + byte_length;
153 let json = String::from_utf8(bytes).map_err(|error| {
154 let utf8_error = error.utf8_error();
155 CodecError::invalid_encoding(
156 CodecKind::JsonTextComponent,
157 bytes_processed,
158 InvalidEncodingReason::InvalidUtf8 {
159 valid_up_to: utf8_error.valid_up_to(),
160 error_len: utf8_error.error_len(),
161 },
162 )
163 })?;
164 Self::validate_length(
165 &json,
166 Self::MAX_DECODE_UTF16_CODE_UNITS,
167 Self::MAX_DECODE_BYTES,
168 CodecOperation::Read,
169 bytes_processed,
170 )?;
171
172 let component: JsonComponent = serde_json::from_str(&json)
173 .map_err(|source| Self::invalid_json(CodecOperation::Read, bytes_processed, source))?;
174 component
175 .validate_depth(Self::MAX_COMPONENT_DEPTH)
176 .map_err(|source| Self::invalid_json(CodecOperation::Read, bytes_processed, source))?;
177 Ok(Self(component))
178 }
179}