1use alloc::borrow::Cow;
2use alloc::format;
3use alloc::string::{String, ToString};
4use alloc::vec::Vec;
5
6use deser_core::State;
7use deser_core::ext::{BigInt, ExtValue, Number};
8use deser_core::ser::{self, EventSink, SerializeDriver, SerializeRef};
9use deser_core::{Atom, Error, ErrorKind, Event, ImplicitValue, Serialize};
10
11use crate::float::{write_f32, write_f64};
12use crate::object::{ClassName, PropertyVisibility, Visibility};
13use crate::parser::{int_key, is_class_name, is_name};
14use crate::reference::{Reference, ReferenceKind};
15
16#[derive(Debug, Clone, Default, PartialEq, Eq)]
30pub struct SerializerConfig {
31 context: deser_core::Context,
32}
33
34impl SerializerConfig {
35 pub const fn new() -> SerializerConfig {
37 SerializerConfig {
38 context: deser_core::Context::new(),
39 }
40 }
41
42 pub const fn builder() -> SerializerConfigBuilder {
44 SerializerConfigBuilder::new()
45 }
46
47 pub const fn into_builder(self) -> SerializerConfigBuilder {
49 SerializerConfigBuilder { value: self }
50 }
51
52 pub fn set_context(&mut self, context: deser_core::Context) {
59 self.context = context;
60 }
61
62 pub fn context(&self) -> &deser_core::Context {
64 &self.context
65 }
66
67 #[inline]
69 fn apply_context(&self, driver: &mut SerializeDriver<'_>) {
70 if !self.context.is_empty() {
71 driver.set_default_context(self.context.clone());
72 }
73 }
74
75 pub fn to_vec<T: Serialize + ?Sized>(&self, value: &T) -> Result<Vec<u8>, Error> {
77 self.to_vec_ref(SerializeRef::new(&value))
78 }
79
80 pub fn to_vec_with<F, T: Serialize + ?Sized>(
85 &self,
86 value: &T,
87 setup: F,
88 ) -> Result<Vec<u8>, Error>
89 where
90 F: FnOnce(&mut SerializeDriver<'_>),
91 {
92 let mut driver = SerializeDriver::new(&value);
93 setup(&mut driver);
94 self.apply_context(&mut driver);
95 serialize_driver(&mut driver)
96 }
97
98 fn to_vec_ref(&self, value: SerializeRef<'_>) -> Result<Vec<u8>, Error> {
104 let mut driver = SerializeDriver::from_ref(value);
105 self.apply_context(&mut driver);
106 serialize_driver(&mut driver)
107 }
108}
109
110#[derive(Debug, Clone)]
114#[must_use]
115pub struct SerializerConfigBuilder {
116 value: SerializerConfig,
117}
118
119impl SerializerConfigBuilder {
120 pub const fn new() -> SerializerConfigBuilder {
122 SerializerConfigBuilder {
123 value: SerializerConfig::new(),
124 }
125 }
126
127 pub fn context(mut self, context: deser_core::Context) -> SerializerConfigBuilder {
131 self.value.set_context(context);
132 self
133 }
134
135 pub const fn build(self) -> SerializerConfig {
137 let value = unsafe { core::ptr::read(&self.value) };
141 core::mem::forget(self);
142 value
143 }
144}
145
146impl Default for SerializerConfigBuilder {
147 fn default() -> SerializerConfigBuilder {
148 SerializerConfigBuilder::new()
149 }
150}
151
152#[derive(Debug, Clone, Default)]
172pub struct Serializer {
173 config: SerializerConfig,
174 out: Vec<u8>,
175}
176
177impl Serializer {
178 pub fn new() -> Serializer {
180 Serializer::with_config(SerializerConfig::new())
181 }
182
183 pub fn with_config(config: SerializerConfig) -> Serializer {
185 Serializer {
186 config,
187 out: Vec::new(),
188 }
189 }
190
191 pub fn config(&self) -> &SerializerConfig {
193 &self.config
194 }
195
196 pub fn serialize<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
198 ser::Serializer::serialize(self, value)
199 }
200
201 pub fn serialize_with<F, T: Serialize + ?Sized>(
206 &mut self,
207 value: &T,
208 setup: F,
209 ) -> Result<(), Error>
210 where
211 F: FnOnce(&mut SerializeDriver<'_>),
212 {
213 ser::Serializer::serialize_with(self, value, setup)
214 }
215
216 pub fn output(&self) -> &[u8] {
218 &self.out
219 }
220
221 pub fn finish(self) -> Vec<u8> {
223 self.out
224 }
225}
226
227impl ser::Serializer for Serializer {
228 fn drive(&mut self, driver: &mut SerializeDriver<'_>) -> Result<(), Error> {
229 self.config.apply_context(driver);
230 let bytes = serialize_driver(driver)?;
231 self.out.extend_from_slice(&bytes);
232 Ok(())
233 }
234}
235
236impl ser::StreamSerializer for Serializer {
237 fn output(&self) -> &[u8] {
238 &self.out
239 }
240
241 fn clear_output(&mut self) {
242 self.out.clear();
243 }
244}
245
246#[cfg(feature = "io")]
247impl SerializerConfig {
248 pub fn writer<W: std::io::Write>(&self, writer: W) -> deser_core::io::Writer<W, Serializer> {
253 deser_core::io::Writer::new(writer, Serializer::with_config(self.clone()))
254 }
255
256 pub fn to_writer<W: std::io::Write, T: Serialize + ?Sized>(
260 &self,
261 writer: W,
262 value: &T,
263 ) -> Result<(), Error> {
264 self.writer(writer).write(value)
265 }
266}
267
268#[cfg(feature = "io")]
276pub fn to_writer<W: std::io::Write, T: Serialize + ?Sized>(
277 writer: W,
278 value: &T,
279) -> Result<(), Error> {
280 SerializerConfig::new().to_writer(writer, value)
281}
282
283pub fn to_vec<T: Serialize + ?Sized>(value: &T) -> Result<Vec<u8>, Error> {
300 SerializerConfig::new().to_vec(value)
301}
302
303fn serialize_driver(driver: &mut SerializeDriver<'_>) -> Result<Vec<u8>, Error> {
305 let mut writer = Writer::default();
306 driver.drive_sink(&mut writer)?;
307 writer.finish()
308}
309
310enum Container {
312 List(u64),
314 Array,
315 Object(String),
316}
317
318struct Open {
320 container: Container,
321 header: usize,
323 count: usize,
325 expects_key: bool,
327}
328
329#[derive(Default)]
334struct Writer {
335 out: Vec<u8>,
336 stack: Vec<Open>,
337 headers: Vec<(usize, Vec<u8>)>,
340 started: bool,
342 objects: Vec<bool>,
345}
346
347impl EventSink for Writer {
348 fn event(
349 &mut self,
350 event: Event<'_>,
351 _value: SerializeRef<'_>,
352 state: &mut State,
353 ) -> Result<(), Error> {
354 let Some(open) = self.stack.last_mut() else {
355 if self.started {
356 return Err(Error::new(ErrorKind::InvalidState, "unexpected event"));
357 }
358 self.started = true;
359 return self.value(event, state);
360 };
361 match open.container {
362 Container::List(ref mut index) => {
363 if event == Event::SeqEnd {
364 return self.close();
365 }
366 let key = *index;
367 *index += 1;
368 open.count += 1;
369 self.out.extend_from_slice(b"i:");
370 push_int(&mut self.out, key as i128);
371 self.out.push(b';');
372 self.value(event, state)
373 }
374 _ if open.expects_key => {
375 if event == Event::MapEnd {
376 return self.close();
377 }
378 open.expects_key = false;
379 open.count += 1;
380 let is_object = matches!(open.container, Container::Object(_));
381 let Event::Atom(atom) = event else {
382 return Err(Error::new(
383 ErrorKind::UnsupportedType,
384 "keys must be integers or strings",
385 ));
386 };
387 let visibility = state
388 .event::<PropertyVisibility>()
389 .and_then(|visibility| visibility.0.clone());
390 self.key(atom, visibility, is_object)
391 }
392 _ => {
393 open.expects_key = true;
394 self.value(event, state)
395 }
396 }
397 }
398}
399
400impl Writer {
401 fn finish(self) -> Result<Vec<u8>, Error> {
403 if !self.started || !self.stack.is_empty() {
404 return Err(Error::new(ErrorKind::InvalidState, "incomplete value"));
405 }
406 if self.headers.is_empty() {
407 return Ok(self.out);
408 }
409 let len = self
410 .headers
411 .iter()
412 .map(|(_, header)| header.len())
413 .sum::<usize>();
414 let mut out = Vec::with_capacity(self.out.len() + len);
415 let mut pos = 0;
416 for (offset, header) in &self.headers {
417 out.extend_from_slice(&self.out[pos..*offset]);
418 out.extend_from_slice(header);
419 pos = *offset;
420 }
421 out.extend_from_slice(&self.out[pos..]);
422 Ok(out)
423 }
424
425 fn value(&mut self, event: Event<'_>, state: &mut State) -> Result<(), Error> {
427 let class = state
428 .event::<ClassName>()
429 .and_then(|class| class.0.as_ref());
430 match event {
431 Event::Atom(atom) => match class {
432 Some(class) => {
433 let class = class.clone();
434 self.objects.push(true);
435 self.classed_atom(atom, &class)
436 }
437 None => {
438 if !matches!(atom, Atom::Ext(ref ext) if ext.is::<Reference>()) {
440 self.objects.push(false);
441 }
442 self.atom(atom)
443 }
444 },
445 Event::MapStart(_) => {
446 let container = match class {
447 Some(class) => {
448 check_class(class)?;
449 Container::Object(class.clone())
450 }
451 None => Container::Array,
452 };
453 self.objects.push(matches!(container, Container::Object(_)));
454 self.open(container);
455 Ok(())
456 }
457 Event::SeqStart(_) => {
458 if class.is_some() {
459 return Err(Error::new(
460 ErrorKind::UnsupportedType,
461 "only maps, strings and bytes can have a class",
462 ));
463 }
464 self.objects.push(false);
465 self.open(Container::List(0));
466 Ok(())
467 }
468 Event::MapEnd | Event::SeqEnd => {
469 Err(Error::new(ErrorKind::InvalidState, "unexpected end event"))
470 }
471 }
472 }
473
474 fn open(&mut self, container: Container) {
475 self.stack.push(Open {
476 container,
477 header: self.headers.len(),
478 count: 0,
479 expects_key: true,
480 });
481 self.headers.push((self.out.len(), Vec::new()));
482 }
483
484 fn close(&mut self) -> Result<(), Error> {
486 let open = self.stack.pop().unwrap();
487 if !open.expects_key {
488 return Err(Error::new(ErrorKind::InvalidState, "map without value"));
489 }
490 let header = &mut self.headers[open.header].1;
491 match open.container {
492 Container::Object(class) => {
493 header.extend_from_slice(b"O:");
494 push_int(header, class.len() as i128);
495 header.extend_from_slice(b":\"");
496 header.extend_from_slice(class.as_bytes());
497 header.extend_from_slice(b"\":");
498 }
499 _ => header.extend_from_slice(b"a:"),
500 }
501 push_int(header, open.count as i128);
502 header.extend_from_slice(b":{");
503 self.out.push(b'}');
504 Ok(())
505 }
506
507 fn atom(&mut self, atom: Atom<'_>) -> Result<(), Error> {
508 match atom {
509 Atom::Null => self.out.extend_from_slice(b"N;"),
510 Atom::Bool(value) => self
511 .out
512 .extend_from_slice(if value { b"b:1;" } else { b"b:0;" }),
513 Atom::U64(value) => self.int(value.into())?,
514 Atom::I64(value) => self.int(value.into())?,
515 Atom::F32(value) => {
516 let mut text = String::new();
517 write_f32(value, &mut text);
518 self.float(&text);
519 }
520 Atom::F64(value) => {
521 let mut text = String::new();
522 write_f64(value, &mut text);
523 self.float(&text);
524 }
525 Atom::Str(value) | Atom::Lexical(value) => self.string(value.as_bytes()),
526 Atom::Char(value) => self.string(value.encode_utf8(&mut [0; 4]).as_bytes()),
527 Atom::Bytes(value) => self.string(value.data()),
528 Atom::Implicit(value) => return self.atom(value.value().to_atom()),
530 Atom::Ext(ref ext) => return self.ext(ext),
531 _ => return Err(Error::new(ErrorKind::UnsupportedType, "unknown atom")),
532 }
533 Ok(())
534 }
535
536 #[cold]
537 fn ext(&mut self, ext: &ExtValue<'_>) -> Result<(), Error> {
538 if let Some(reference) = ext.downcast_ref::<Reference>() {
539 let target = usize::try_from(reference.number())
542 .ok()
543 .and_then(|number| number.checked_sub(1))
544 .and_then(|index| self.objects.get(index));
545 match (reference.kind(), target) {
546 (ReferenceKind::Object, Some(true)) => self.objects.push(true),
547 (ReferenceKind::Value, Some(_)) => {}
548 _ => {
549 return Err(Error::new(
550 ErrorKind::InvalidValue,
551 "the reference does not refer to an earlier value",
552 ));
553 }
554 }
555 self.out.extend_from_slice(match reference.kind() {
556 ReferenceKind::Object => b"r:",
557 ReferenceKind::Value => b"R:",
558 });
559 push_int(&mut self.out, reference.number().into());
560 self.out.push(b';');
561 return Ok(());
562 }
563 if let Some(value) = ext_int(ext) {
564 return self.int(value);
565 }
566 if let Some(value) = ext.downcast_value_ref::<Number>() {
568 return match value.as_str().parse::<i64>() {
569 Ok(value) => self.int(value.into()),
570 Err(_) => self.atom(Atom::F64(value.value())),
571 };
572 }
573 match ext.fallback() {
574 Atom::Ext(_) => Err(Error::new(
575 ErrorKind::UnsupportedType,
576 format!("PHP's serialization format does not support {}", ext.name()),
577 )),
578 fallback => self.atom(fallback),
579 }
580 }
581
582 fn classed_atom(&mut self, atom: Atom<'_>, class: &str) -> Result<(), Error> {
585 check_class(class)?;
586 match atom {
587 Atom::Str(ref case) | Atom::Lexical(ref case) => {
588 if !is_name(case.as_bytes()) {
589 return Err(Error::new(ErrorKind::InvalidValue, "invalid enum case"));
590 }
591 self.out.extend_from_slice(b"E:");
592 push_int(&mut self.out, (class.len() + 1 + case.len()) as i128);
593 self.out.extend_from_slice(b":\"");
594 self.out.extend_from_slice(class.as_bytes());
595 self.out.push(b':');
596 self.out.extend_from_slice(case.as_bytes());
597 self.out.extend_from_slice(b"\";");
598 }
599 Atom::Bytes(ref payload) => {
600 self.out.extend_from_slice(b"C:");
601 push_int(&mut self.out, class.len() as i128);
602 self.out.extend_from_slice(b":\"");
603 self.out.extend_from_slice(class.as_bytes());
604 self.out.extend_from_slice(b"\":");
605 push_int(&mut self.out, payload.data().len() as i128);
606 self.out.extend_from_slice(b":{");
607 self.out.extend_from_slice(payload.data());
608 self.out.push(b'}');
609 }
610 _ => {
611 return Err(Error::new(
612 ErrorKind::UnsupportedType,
613 "only maps, strings and bytes can have a class",
614 ));
615 }
616 }
617 Ok(())
618 }
619
620 fn int(&mut self, value: i128) -> Result<(), Error> {
621 if i64::try_from(value).is_err() {
622 return Err(out_of_range());
623 }
624 self.out.extend_from_slice(b"i:");
625 push_int(&mut self.out, value);
626 self.out.push(b';');
627 Ok(())
628 }
629
630 fn float(&mut self, text: &str) {
631 self.out.extend_from_slice(b"d:");
632 self.out.extend_from_slice(text.as_bytes());
633 self.out.push(b';');
634 }
635
636 fn string(&mut self, bytes: &[u8]) {
637 self.out.extend_from_slice(b"s:");
638 push_int(&mut self.out, bytes.len() as i128);
639 self.out.extend_from_slice(b":\"");
640 self.out.extend_from_slice(bytes);
641 self.out.extend_from_slice(b"\";");
642 }
643
644 fn key(
651 &mut self,
652 atom: Atom<'_>,
653 visibility: Option<Visibility>,
654 is_object: bool,
655 ) -> Result<(), Error> {
656 let mut key = key_of(atom)?;
657 if let Some(visibility) = visibility.filter(|x| *x != Visibility::Public) {
658 let name = match key {
659 Key::Int(value) => Cow::Owned(value.to_string().into_bytes()),
660 Key::Str(name) => name,
661 };
662 let mut mangled = Vec::with_capacity(name.len() + 3);
663 mangled.push(0);
664 match visibility {
665 Visibility::Private(class) => mangled.extend_from_slice(class.as_bytes()),
666 _ => mangled.push(b'*'),
667 }
668 mangled.push(0);
669 mangled.extend_from_slice(&name);
670 key = Key::Str(Cow::Owned(mangled));
671 }
672 match key {
673 Key::Int(value) if !is_object => self.int(value.into()),
674 Key::Int(value) => {
675 self.string(value.to_string().as_bytes());
676 Ok(())
677 }
678 Key::Str(name) => {
679 match int_key(&name).filter(|_| !is_object) {
680 Some(value) => self.int(value.into())?,
681 None => self.string(&name),
682 }
683 Ok(())
684 }
685 }
686 }
687}
688
689enum Key<'a> {
691 Int(i64),
692 Str(Cow<'a, [u8]>),
693}
694
695fn key_of(atom: Atom<'_>) -> Result<Key<'_>, Error> {
697 Ok(match atom {
698 Atom::Str(value) | Atom::Lexical(value) => Key::Str(match value.into_cow() {
699 Cow::Borrowed(value) => Cow::Borrowed(value.as_bytes()),
700 Cow::Owned(value) => Cow::Owned(value.into_bytes()),
701 }),
702 Atom::Char(value) => Key::Str(Cow::Owned(value.to_string().into_bytes())),
703 Atom::Bytes(value) => Key::Str(value.into_data()),
704 Atom::U64(value) => Key::Int(i64::try_from(value).map_err(|_| out_of_range())?),
705 Atom::I64(value) => Key::Int(value),
706 Atom::Bool(value) => Key::Int(value.into()),
708 Atom::Implicit(value) => {
709 let (text, value) = value.into_parts();
710 match value {
711 ImplicitValue::U64(value) => {
712 Key::Int(i64::try_from(value).map_err(|_| out_of_range())?)
713 }
714 ImplicitValue::I64(value) => Key::Int(value),
715 _ => Key::Str(Cow::Owned(text.into_owned().into_bytes())),
716 }
717 }
718 Atom::Ext(ref ext) => {
719 if let Some(value) = ext_int(ext) {
720 Key::Int(i64::try_from(value).map_err(|_| out_of_range())?)
721 } else if ext.is::<Reference>() {
722 return Err(unsupported_key());
723 } else {
724 match ext.fallback() {
725 Atom::Ext(_) => return Err(unsupported_key()),
726 fallback => match key_of(fallback)? {
727 Key::Int(value) => Key::Int(value),
728 Key::Str(name) => Key::Str(Cow::Owned(name.into_owned())),
729 },
730 }
731 }
732 }
733 _ => return Err(unsupported_key()),
734 })
735}
736
737fn ext_int(ext: &ExtValue<'_>) -> Option<i128> {
739 if let Some(&value) = ext.downcast_ref::<u128>() {
740 return Some(i128::try_from(value).unwrap_or(i128::MAX));
742 }
743 if let Some(&value) = ext.downcast_ref::<i128>() {
744 return Some(value);
745 }
746 ext.downcast_ref::<BigInt>().map(|value| {
747 value.to_i128().unwrap_or(if value.is_negative() {
748 i128::MIN
749 } else {
750 i128::MAX
751 })
752 })
753}
754
755fn check_class(class: &str) -> Result<(), Error> {
756 if !is_class_name(class.as_bytes()) {
757 return Err(Error::new(
758 ErrorKind::InvalidValue,
759 format!("invalid class name {:?}", class),
760 ));
761 }
762 Ok(())
763}
764
765fn push_int(out: &mut Vec<u8>, value: i128) {
767 let mut buf = [0u8; 40];
768 let mut pos = buf.len();
769 let negative = value < 0;
770 let mut rest = value.unsigned_abs();
771 loop {
772 pos -= 1;
773 buf[pos] = b'0' + (rest % 10) as u8;
774 rest /= 10;
775 if rest == 0 {
776 break;
777 }
778 }
779 if negative {
780 pos -= 1;
781 buf[pos] = b'-';
782 }
783 out.extend_from_slice(&buf[pos..]);
784}
785
786#[cold]
787fn out_of_range() -> Error {
788 Error::new(
789 ErrorKind::OutOfRange,
790 "integer out of range for PHP's serialization format",
791 )
792}
793
794#[cold]
795fn unsupported_key() -> Error {
796 Error::new(
797 ErrorKind::UnsupportedType,
798 "keys must be integers or strings",
799 )
800}