1use crate::serde::{ShapeDeserializer, ShapeSerializer};
9use crate::Schema;
10use aws_smithy_types::{BigDecimal, BigInteger, Blob, DateTime, Document};
11use std::error::Error;
12use std::fmt;
13
14#[derive(Debug)]
16pub struct HttpStringCodecError {
17 message: String,
18}
19
20impl HttpStringCodecError {
21 fn new(message: impl Into<String>) -> Self {
22 Self {
23 message: message.into(),
24 }
25 }
26}
27
28impl fmt::Display for HttpStringCodecError {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 write!(f, "HTTP string codec error: {}", self.message)
31 }
32}
33
34impl Error for HttpStringCodecError {}
35
36pub struct HttpStringSerializer {
38 output: String,
39}
40
41impl HttpStringSerializer {
42 pub fn new() -> Self {
44 Self {
45 output: String::new(),
46 }
47 }
48}
49
50impl Default for HttpStringSerializer {
51 fn default() -> Self {
52 Self::new()
53 }
54}
55
56impl ShapeSerializer for HttpStringSerializer {
57 type Output = String;
58 type Error = HttpStringCodecError;
59
60 fn finish(self) -> Result<Self::Output, Self::Error> {
61 Ok(self.output)
62 }
63
64 fn write_struct<F>(
65 &mut self,
66 _schema: &dyn Schema,
67 _write_members: F,
68 ) -> Result<(), Self::Error>
69 where
70 F: FnOnce(&mut Self) -> Result<(), Self::Error>,
71 {
72 Err(HttpStringCodecError::new(
73 "structures cannot be serialized to strings",
74 ))
75 }
76
77 fn write_list<F>(&mut self, _schema: &dyn Schema, write_elements: F) -> Result<(), Self::Error>
78 where
79 F: FnOnce(&mut Self) -> Result<(), Self::Error>,
80 {
81 write_elements(self)
83 }
84
85 fn write_map<F>(&mut self, _schema: &dyn Schema, _write_entries: F) -> Result<(), Self::Error>
86 where
87 F: FnOnce(&mut Self) -> Result<(), Self::Error>,
88 {
89 Err(HttpStringCodecError::new(
90 "maps cannot be serialized to strings",
91 ))
92 }
93
94 fn write_boolean(&mut self, _schema: &dyn Schema, value: bool) -> Result<(), Self::Error> {
95 if !self.output.is_empty() {
96 self.output.push(',');
97 }
98 self.output.push_str(if value { "true" } else { "false" });
99 Ok(())
100 }
101
102 fn write_byte(&mut self, _schema: &dyn Schema, value: i8) -> Result<(), Self::Error> {
103 if !self.output.is_empty() {
104 self.output.push(',');
105 }
106 self.output.push_str(&value.to_string());
107 Ok(())
108 }
109
110 fn write_short(&mut self, _schema: &dyn Schema, value: i16) -> Result<(), Self::Error> {
111 if !self.output.is_empty() {
112 self.output.push(',');
113 }
114 self.output.push_str(&value.to_string());
115 Ok(())
116 }
117
118 fn write_integer(&mut self, _schema: &dyn Schema, value: i32) -> Result<(), Self::Error> {
119 if !self.output.is_empty() {
120 self.output.push(',');
121 }
122 self.output.push_str(&value.to_string());
123 Ok(())
124 }
125
126 fn write_long(&mut self, _schema: &dyn Schema, value: i64) -> Result<(), Self::Error> {
127 if !self.output.is_empty() {
128 self.output.push(',');
129 }
130 self.output.push_str(&value.to_string());
131 Ok(())
132 }
133
134 fn write_float(&mut self, _schema: &dyn Schema, value: f32) -> Result<(), Self::Error> {
135 if !self.output.is_empty() {
136 self.output.push(',');
137 }
138 if value.is_nan() {
139 self.output.push_str("NaN");
140 } else if value.is_infinite() {
141 self.output.push_str(if value.is_sign_positive() {
142 "Infinity"
143 } else {
144 "-Infinity"
145 });
146 } else {
147 self.output.push_str(&value.to_string());
148 }
149 Ok(())
150 }
151
152 fn write_double(&mut self, _schema: &dyn Schema, value: f64) -> Result<(), Self::Error> {
153 if !self.output.is_empty() {
154 self.output.push(',');
155 }
156 if value.is_nan() {
157 self.output.push_str("NaN");
158 } else if value.is_infinite() {
159 self.output.push_str(if value.is_sign_positive() {
160 "Infinity"
161 } else {
162 "-Infinity"
163 });
164 } else {
165 self.output.push_str(&value.to_string());
166 }
167 Ok(())
168 }
169
170 fn write_big_integer(
171 &mut self,
172 _schema: &dyn Schema,
173 value: &BigInteger,
174 ) -> Result<(), Self::Error> {
175 if !self.output.is_empty() {
176 self.output.push(',');
177 }
178 self.output.push_str(value.as_ref());
179 Ok(())
180 }
181
182 fn write_big_decimal(
183 &mut self,
184 _schema: &dyn Schema,
185 value: &BigDecimal,
186 ) -> Result<(), Self::Error> {
187 if !self.output.is_empty() {
188 self.output.push(',');
189 }
190 self.output.push_str(value.as_ref());
191 Ok(())
192 }
193
194 fn write_string(&mut self, _schema: &dyn Schema, value: &str) -> Result<(), Self::Error> {
195 if !self.output.is_empty() {
196 self.output.push(',');
197 }
198 self.output.push_str(value);
199 Ok(())
200 }
201
202 fn write_blob(&mut self, _schema: &dyn Schema, value: &Blob) -> Result<(), Self::Error> {
203 if !self.output.is_empty() {
204 self.output.push(',');
205 }
206 self.output
208 .push_str(&aws_smithy_types::base64::encode(value.as_ref()));
209 Ok(())
210 }
211
212 fn write_timestamp(
213 &mut self,
214 _schema: &dyn Schema,
215 value: &DateTime,
216 ) -> Result<(), Self::Error> {
217 if !self.output.is_empty() {
218 self.output.push(',');
219 }
220 let formatted = value
223 .fmt(aws_smithy_types::date_time::Format::HttpDate)
224 .map_err(|e| HttpStringCodecError::new(format!("failed to format timestamp: {}", e)))?;
225 self.output.push_str(&formatted);
226 Ok(())
227 }
228
229 fn write_document(
230 &mut self,
231 _schema: &dyn Schema,
232 _value: &Document,
233 ) -> Result<(), Self::Error> {
234 Err(HttpStringCodecError::new(
235 "documents cannot be serialized to strings",
236 ))
237 }
238
239 fn write_null(&mut self, _schema: &dyn Schema) -> Result<(), Self::Error> {
240 Err(HttpStringCodecError::new(
241 "null cannot be serialized to strings",
242 ))
243 }
244}
245
246pub struct HttpStringDeserializer<'a> {
248 input: std::borrow::Cow<'a, str>,
249 position: usize,
250}
251
252impl<'a> HttpStringDeserializer<'a> {
253 pub fn new(input: &'a str) -> Self {
255 Self {
256 input: std::borrow::Cow::Borrowed(input),
257 position: 0,
258 }
259 }
260
261 fn next_value(&mut self) -> Option<&str> {
262 if self.position >= self.input.len() {
263 return None;
264 }
265
266 let start = self.position;
267 if let Some(comma_pos) = self.input[start..].find(',') {
268 let end = start + comma_pos;
269 self.position = end + 1;
270 Some(&self.input[start..end])
271 } else {
272 self.position = self.input.len();
273 Some(&self.input[start..])
274 }
275 }
276
277 fn current_value(&self) -> &str {
278 &self.input[self.position..]
279 }
280}
281
282impl<'a> ShapeDeserializer for HttpStringDeserializer<'a> {
283 type Error = HttpStringCodecError;
284
285 fn read_struct<T, F>(
286 &mut self,
287 _schema: &dyn Schema,
288 _state: T,
289 _consumer: F,
290 ) -> Result<T, Self::Error>
291 where
292 F: FnMut(T, &dyn Schema, &mut Self) -> Result<T, Self::Error>,
293 {
294 Err(HttpStringCodecError::new(
295 "structures cannot be deserialized from strings",
296 ))
297 }
298
299 fn read_list<T, F>(
300 &mut self,
301 _schema: &dyn Schema,
302 state: T,
303 _consumer: F,
304 ) -> Result<T, Self::Error>
305 where
306 F: FnMut(T, &mut Self) -> Result<T, Self::Error>,
307 {
308 Ok(state)
311 }
312
313 fn read_map<T, F>(
314 &mut self,
315 _schema: &dyn Schema,
316 _state: T,
317 _consumer: F,
318 ) -> Result<T, Self::Error>
319 where
320 F: FnMut(T, String, &mut Self) -> Result<T, Self::Error>,
321 {
322 Err(HttpStringCodecError::new(
323 "maps cannot be deserialized from strings",
324 ))
325 }
326
327 fn read_boolean(&mut self, _schema: &dyn Schema) -> Result<bool, Self::Error> {
328 let value = self
329 .next_value()
330 .ok_or_else(|| HttpStringCodecError::new("expected boolean value"))?;
331 value
332 .parse()
333 .map_err(|_| HttpStringCodecError::new(format!("invalid boolean: {}", value)))
334 }
335
336 fn read_byte(&mut self, _schema: &dyn Schema) -> Result<i8, Self::Error> {
337 let value = self
338 .next_value()
339 .ok_or_else(|| HttpStringCodecError::new("expected byte value"))?;
340 value
341 .parse()
342 .map_err(|_| HttpStringCodecError::new(format!("invalid byte: {}", value)))
343 }
344
345 fn read_short(&mut self, _schema: &dyn Schema) -> Result<i16, Self::Error> {
346 let value = self
347 .next_value()
348 .ok_or_else(|| HttpStringCodecError::new("expected short value"))?;
349 value
350 .parse()
351 .map_err(|_| HttpStringCodecError::new(format!("invalid short: {}", value)))
352 }
353
354 fn read_integer(&mut self, _schema: &dyn Schema) -> Result<i32, Self::Error> {
355 let value = self
356 .next_value()
357 .ok_or_else(|| HttpStringCodecError::new("expected integer value"))?;
358 value
359 .parse()
360 .map_err(|_| HttpStringCodecError::new(format!("invalid integer: {}", value)))
361 }
362
363 fn read_long(&mut self, _schema: &dyn Schema) -> Result<i64, Self::Error> {
364 let value = self
365 .next_value()
366 .ok_or_else(|| HttpStringCodecError::new("expected long value"))?;
367 value
368 .parse()
369 .map_err(|_| HttpStringCodecError::new(format!("invalid long: {}", value)))
370 }
371
372 fn read_float(&mut self, _schema: &dyn Schema) -> Result<f32, Self::Error> {
373 let value = self
374 .next_value()
375 .ok_or_else(|| HttpStringCodecError::new("expected float value"))?;
376 match value {
377 "NaN" => Ok(f32::NAN),
378 "Infinity" => Ok(f32::INFINITY),
379 "-Infinity" => Ok(f32::NEG_INFINITY),
380 _ => value
381 .parse()
382 .map_err(|_| HttpStringCodecError::new(format!("invalid float: {}", value))),
383 }
384 }
385
386 fn read_double(&mut self, _schema: &dyn Schema) -> Result<f64, Self::Error> {
387 let value = self
388 .next_value()
389 .ok_or_else(|| HttpStringCodecError::new("expected double value"))?;
390 match value {
391 "NaN" => Ok(f64::NAN),
392 "Infinity" => Ok(f64::INFINITY),
393 "-Infinity" => Ok(f64::NEG_INFINITY),
394 _ => value
395 .parse()
396 .map_err(|_| HttpStringCodecError::new(format!("invalid double: {}", value))),
397 }
398 }
399
400 fn read_big_integer(&mut self, _schema: &dyn Schema) -> Result<BigInteger, Self::Error> {
401 let value = self
402 .next_value()
403 .ok_or_else(|| HttpStringCodecError::new("expected big integer value"))?;
404 use std::str::FromStr;
405 BigInteger::from_str(value)
406 .map_err(|_| HttpStringCodecError::new(format!("invalid big integer: {}", value)))
407 }
408
409 fn read_big_decimal(&mut self, _schema: &dyn Schema) -> Result<BigDecimal, Self::Error> {
410 let value = self
411 .next_value()
412 .ok_or_else(|| HttpStringCodecError::new("expected big decimal value"))?;
413 use std::str::FromStr;
414 BigDecimal::from_str(value)
415 .map_err(|_| HttpStringCodecError::new(format!("invalid big decimal: {}", value)))
416 }
417
418 fn read_string(&mut self, _schema: &dyn Schema) -> Result<String, Self::Error> {
419 self.next_value()
420 .ok_or_else(|| HttpStringCodecError::new("expected string value"))
421 .map(|s| s.to_string())
422 }
423
424 fn read_blob(&mut self, _schema: &dyn Schema) -> Result<Blob, Self::Error> {
425 let value = self
426 .next_value()
427 .ok_or_else(|| HttpStringCodecError::new("expected blob value"))?;
428 let decoded = aws_smithy_types::base64::decode(value)
429 .map_err(|e| HttpStringCodecError::new(format!("invalid base64: {}", e)))?;
430 Ok(Blob::new(decoded))
431 }
432
433 fn read_timestamp(&mut self, _schema: &dyn Schema) -> Result<DateTime, Self::Error> {
434 let value = self
435 .next_value()
436 .ok_or_else(|| HttpStringCodecError::new("expected timestamp value"))?;
437 DateTime::from_str(value, aws_smithy_types::date_time::Format::HttpDate)
440 .or_else(|_| DateTime::from_str(value, aws_smithy_types::date_time::Format::DateTime))
441 .map_err(|e| HttpStringCodecError::new(format!("invalid timestamp: {}", e)))
442 }
443
444 fn read_document(&mut self, _schema: &dyn Schema) -> Result<Document, Self::Error> {
445 Err(HttpStringCodecError::new(
446 "documents cannot be deserialized from strings",
447 ))
448 }
449
450 fn is_null(&self) -> bool {
451 self.current_value().is_empty()
452 }
453
454 fn container_size(&self) -> Option<usize> {
455 Some(self.input.matches(',').count() + 1)
457 }
458}
459
460pub struct HttpStringCodec;
462
463impl crate::codec::Codec for HttpStringCodec {
464 type Serializer = HttpStringSerializer;
465 type Deserializer = HttpStringDeserializer<'static>;
466
467 fn create_serializer(&self) -> Self::Serializer {
468 HttpStringSerializer::new()
469 }
470
471 fn create_deserializer(&self, input: &[u8]) -> Self::Deserializer {
472 let input_str = std::str::from_utf8(input).unwrap_or("").to_string();
473 HttpStringDeserializer {
474 input: std::borrow::Cow::Owned(input_str),
475 position: 0,
476 }
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::*;
483 use crate::prelude::*;
484
485 #[test]
486 fn test_serialize_boolean() {
487 let mut ser = HttpStringSerializer::new();
488 ser.write_boolean(&BOOLEAN, true).unwrap();
489 assert_eq!(ser.finish().unwrap(), "true");
490
491 let mut ser = HttpStringSerializer::new();
492 ser.write_boolean(&BOOLEAN, false).unwrap();
493 assert_eq!(ser.finish().unwrap(), "false");
494 }
495
496 #[test]
497 fn test_serialize_integers() {
498 let mut ser = HttpStringSerializer::new();
499 ser.write_byte(&BYTE, 42).unwrap();
500 assert_eq!(ser.finish().unwrap(), "42");
501
502 let mut ser = HttpStringSerializer::new();
503 ser.write_integer(&INTEGER, -123).unwrap();
504 assert_eq!(ser.finish().unwrap(), "-123");
505
506 let mut ser = HttpStringSerializer::new();
507 ser.write_long(&LONG, 9876543210).unwrap();
508 assert_eq!(ser.finish().unwrap(), "9876543210");
509 }
510
511 #[test]
512 fn test_serialize_floats() {
513 let mut ser = HttpStringSerializer::new();
514 ser.write_float(&FLOAT, 3.14).unwrap();
515 assert_eq!(ser.finish().unwrap(), "3.14");
516
517 let mut ser = HttpStringSerializer::new();
518 ser.write_float(&FLOAT, f32::NAN).unwrap();
519 assert_eq!(ser.finish().unwrap(), "NaN");
520
521 let mut ser = HttpStringSerializer::new();
522 ser.write_float(&FLOAT, f32::INFINITY).unwrap();
523 assert_eq!(ser.finish().unwrap(), "Infinity");
524 }
525
526 #[test]
527 fn test_serialize_string() {
528 let mut ser = HttpStringSerializer::new();
529 ser.write_string(&STRING, "hello world").unwrap();
530 assert_eq!(ser.finish().unwrap(), "hello world");
531 }
532
533 #[test]
534 fn test_serialize_list() {
535 let mut ser = HttpStringSerializer::new();
536 ser.write_list(&STRING, |s| {
537 s.write_string(&STRING, "a")?;
538 s.write_string(&STRING, "b")?;
539 s.write_string(&STRING, "c")?;
540 Ok(())
541 })
542 .unwrap();
543 assert_eq!(ser.finish().unwrap(), "a,b,c");
544 }
545
546 #[test]
547 fn test_serialize_blob() {
548 let mut ser = HttpStringSerializer::new();
549 let blob = Blob::new(vec![1, 2, 3, 4]);
550 ser.write_blob(&BLOB, &blob).unwrap();
551 assert_eq!(ser.finish().unwrap(), "AQIDBA==");
553 }
554
555 #[test]
556 fn test_deserialize_boolean() {
557 let mut deser = HttpStringDeserializer::new("true");
558 assert_eq!(deser.read_boolean(&BOOLEAN).unwrap(), true);
559
560 let mut deser = HttpStringDeserializer::new("false");
561 assert_eq!(deser.read_boolean(&BOOLEAN).unwrap(), false);
562 }
563
564 #[test]
565 fn test_deserialize_integers() {
566 let mut deser = HttpStringDeserializer::new("42");
567 assert_eq!(deser.read_byte(&BYTE).unwrap(), 42);
568
569 let mut deser = HttpStringDeserializer::new("-123");
570 assert_eq!(deser.read_integer(&INTEGER).unwrap(), -123);
571
572 let mut deser = HttpStringDeserializer::new("9876543210");
573 assert_eq!(deser.read_long(&LONG).unwrap(), 9876543210);
574 }
575
576 #[test]
577 fn test_deserialize_floats() {
578 let mut deser = HttpStringDeserializer::new("3.14");
579 assert!((deser.read_float(&FLOAT).unwrap() - 3.14).abs() < 0.01);
580
581 let mut deser = HttpStringDeserializer::new("NaN");
582 assert!(deser.read_float(&FLOAT).unwrap().is_nan());
583
584 let mut deser = HttpStringDeserializer::new("Infinity");
585 assert_eq!(deser.read_float(&FLOAT).unwrap(), f32::INFINITY);
586 }
587
588 #[test]
589 fn test_deserialize_string() {
590 let mut deser = HttpStringDeserializer::new("hello world");
591 assert_eq!(deser.read_string(&STRING).unwrap(), "hello world");
592 }
593
594 #[test]
595 fn test_deserialize_list() {
596 let mut deser = HttpStringDeserializer::new("a,b,c");
597 let mut values = Vec::new();
598
599 values.push(deser.read_string(&STRING).unwrap());
601 values.push(deser.read_string(&STRING).unwrap());
602 values.push(deser.read_string(&STRING).unwrap());
603
604 assert_eq!(values, vec!["a", "b", "c"]);
605 }
606
607 #[test]
608 fn test_deserialize_blob() {
609 let mut deser = HttpStringDeserializer::new("AQIDBA==");
610 let blob = deser.read_blob(&BLOB).unwrap();
611 assert_eq!(blob.as_ref(), &[1, 2, 3, 4]);
612 }
613
614 #[test]
615 fn test_container_size() {
616 let deser = HttpStringDeserializer::new("a,b,c");
617 assert_eq!(deser.container_size(), Some(3));
618
619 let deser = HttpStringDeserializer::new("single");
620 assert_eq!(deser.container_size(), Some(1));
621 }
622
623 #[test]
624 fn test_is_null() {
625 let deser = HttpStringDeserializer::new("");
626 assert!(deser.is_null());
627
628 let deser = HttpStringDeserializer::new("value");
629 assert!(!deser.is_null());
630 }
631
632 #[test]
633 fn test_codec_trait() {
634 use crate::codec::Codec;
635
636 let codec = HttpStringCodec;
637
638 let mut ser = codec.create_serializer();
640 ser.write_string(&STRING, "test").unwrap();
641 let output = ser.finish().unwrap();
642 assert_eq!(output, "test");
643
644 let input = b"hello";
646 let mut deser = codec.create_deserializer(input);
647 let result = deser.read_string(&STRING).unwrap();
648 assert_eq!(result, "hello");
649 }
650}