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}
343
344impl EventSink for Writer {
345 fn event(
346 &mut self,
347 event: Event<'_>,
348 _value: SerializeRef<'_>,
349 state: &mut State,
350 ) -> Result<(), Error> {
351 let Some(open) = self.stack.last_mut() else {
352 if self.started {
353 return Err(Error::new(ErrorKind::InvalidState, "unexpected event"));
354 }
355 self.started = true;
356 return self.value(event, state);
357 };
358 match open.container {
359 Container::List(ref mut index) => {
360 if event == Event::SeqEnd {
361 return self.close();
362 }
363 let key = *index;
364 *index += 1;
365 open.count += 1;
366 self.out.extend_from_slice(b"i:");
367 push_int(&mut self.out, key as i128);
368 self.out.push(b';');
369 self.value(event, state)
370 }
371 _ if open.expects_key => {
372 if event == Event::MapEnd {
373 return self.close();
374 }
375 open.expects_key = false;
376 open.count += 1;
377 let is_object = matches!(open.container, Container::Object(_));
378 let Event::Atom(atom) = event else {
379 return Err(Error::new(
380 ErrorKind::UnsupportedType,
381 "keys must be integers or strings",
382 ));
383 };
384 let visibility = state
385 .event::<PropertyVisibility>()
386 .and_then(|visibility| visibility.0.clone());
387 self.key(atom, visibility, is_object)
388 }
389 _ => {
390 open.expects_key = true;
391 self.value(event, state)
392 }
393 }
394 }
395}
396
397impl Writer {
398 fn finish(self) -> Result<Vec<u8>, Error> {
400 if !self.started || !self.stack.is_empty() {
401 return Err(Error::new(ErrorKind::InvalidState, "incomplete value"));
402 }
403 if self.headers.is_empty() {
404 return Ok(self.out);
405 }
406 let len = self
407 .headers
408 .iter()
409 .map(|(_, header)| header.len())
410 .sum::<usize>();
411 let mut out = Vec::with_capacity(self.out.len() + len);
412 let mut pos = 0;
413 for (offset, header) in &self.headers {
414 out.extend_from_slice(&self.out[pos..*offset]);
415 out.extend_from_slice(header);
416 pos = *offset;
417 }
418 out.extend_from_slice(&self.out[pos..]);
419 Ok(out)
420 }
421
422 fn value(&mut self, event: Event<'_>, state: &mut State) -> Result<(), Error> {
424 let class = state
425 .event::<ClassName>()
426 .and_then(|class| class.0.as_ref());
427 match event {
428 Event::Atom(atom) => match class {
429 Some(class) => {
430 let class = class.clone();
431 self.classed_atom(atom, &class)
432 }
433 None => self.atom(atom),
434 },
435 Event::MapStart(_) => {
436 let container = match class {
437 Some(class) => {
438 check_class(class)?;
439 Container::Object(class.clone())
440 }
441 None => Container::Array,
442 };
443 self.open(container);
444 Ok(())
445 }
446 Event::SeqStart(_) => {
447 if class.is_some() {
448 return Err(Error::new(
449 ErrorKind::UnsupportedType,
450 "only maps, strings and bytes can have a class",
451 ));
452 }
453 self.open(Container::List(0));
454 Ok(())
455 }
456 Event::MapEnd | Event::SeqEnd => {
457 Err(Error::new(ErrorKind::InvalidState, "unexpected end event"))
458 }
459 }
460 }
461
462 fn open(&mut self, container: Container) {
463 self.stack.push(Open {
464 container,
465 header: self.headers.len(),
466 count: 0,
467 expects_key: true,
468 });
469 self.headers.push((self.out.len(), Vec::new()));
470 }
471
472 fn close(&mut self) -> Result<(), Error> {
474 let open = self.stack.pop().unwrap();
475 if !open.expects_key {
476 return Err(Error::new(ErrorKind::InvalidState, "map without value"));
477 }
478 let header = &mut self.headers[open.header].1;
479 match open.container {
480 Container::Object(class) => {
481 header.extend_from_slice(b"O:");
482 push_int(header, class.len() as i128);
483 header.extend_from_slice(b":\"");
484 header.extend_from_slice(class.as_bytes());
485 header.extend_from_slice(b"\":");
486 }
487 _ => header.extend_from_slice(b"a:"),
488 }
489 push_int(header, open.count as i128);
490 header.extend_from_slice(b":{");
491 self.out.push(b'}');
492 Ok(())
493 }
494
495 fn atom(&mut self, atom: Atom<'_>) -> Result<(), Error> {
496 match atom {
497 Atom::Null => self.out.extend_from_slice(b"N;"),
498 Atom::Bool(value) => self
499 .out
500 .extend_from_slice(if value { b"b:1;" } else { b"b:0;" }),
501 Atom::U64(value) => self.int(value.into())?,
502 Atom::I64(value) => self.int(value.into())?,
503 Atom::F32(value) => {
504 let mut text = String::new();
505 write_f32(value, &mut text);
506 self.float(&text);
507 }
508 Atom::F64(value) => {
509 let mut text = String::new();
510 write_f64(value, &mut text);
511 self.float(&text);
512 }
513 Atom::Str(value) | Atom::Lexical(value) => self.string(value.as_bytes()),
514 Atom::Char(value) => self.string(value.encode_utf8(&mut [0; 4]).as_bytes()),
515 Atom::Bytes(value) => self.string(value.data()),
516 Atom::Implicit(value) => return self.atom(value.value().to_atom()),
518 Atom::Ext(ref ext) => return self.ext(ext),
519 _ => return Err(Error::new(ErrorKind::UnsupportedType, "unknown atom")),
520 }
521 Ok(())
522 }
523
524 #[cold]
525 fn ext(&mut self, ext: &ExtValue<'_>) -> Result<(), Error> {
526 if let Some(reference) = ext.downcast_ref::<Reference>() {
527 self.out.extend_from_slice(match reference.kind() {
528 ReferenceKind::Object => b"r:",
529 ReferenceKind::Value => b"R:",
530 });
531 push_int(&mut self.out, reference.number().into());
532 self.out.push(b';');
533 return Ok(());
534 }
535 if let Some(value) = ext_int(ext) {
536 return self.int(value);
537 }
538 if let Some(value) = ext.downcast_value_ref::<Number>() {
540 return match value.as_str().parse::<i64>() {
541 Ok(value) => self.int(value.into()),
542 Err(_) => self.atom(Atom::F64(value.value())),
543 };
544 }
545 match ext.fallback() {
546 Atom::Ext(_) => Err(Error::new(
547 ErrorKind::UnsupportedType,
548 format!("PHP's serialization format does not support {}", ext.name()),
549 )),
550 fallback => self.atom(fallback),
551 }
552 }
553
554 fn classed_atom(&mut self, atom: Atom<'_>, class: &str) -> Result<(), Error> {
557 check_class(class)?;
558 match atom {
559 Atom::Str(ref case) | Atom::Lexical(ref case) => {
560 if !is_name(case.as_bytes()) {
561 return Err(Error::new(ErrorKind::InvalidValue, "invalid enum case"));
562 }
563 self.out.extend_from_slice(b"E:");
564 push_int(&mut self.out, (class.len() + 1 + case.len()) as i128);
565 self.out.extend_from_slice(b":\"");
566 self.out.extend_from_slice(class.as_bytes());
567 self.out.push(b':');
568 self.out.extend_from_slice(case.as_bytes());
569 self.out.extend_from_slice(b"\";");
570 }
571 Atom::Bytes(ref payload) => {
572 self.out.extend_from_slice(b"C:");
573 push_int(&mut self.out, class.len() as i128);
574 self.out.extend_from_slice(b":\"");
575 self.out.extend_from_slice(class.as_bytes());
576 self.out.extend_from_slice(b"\":");
577 push_int(&mut self.out, payload.data().len() as i128);
578 self.out.extend_from_slice(b":{");
579 self.out.extend_from_slice(payload.data());
580 self.out.push(b'}');
581 }
582 _ => {
583 return Err(Error::new(
584 ErrorKind::UnsupportedType,
585 "only maps, strings and bytes can have a class",
586 ));
587 }
588 }
589 Ok(())
590 }
591
592 fn int(&mut self, value: i128) -> Result<(), Error> {
593 if i64::try_from(value).is_err() {
594 return Err(out_of_range());
595 }
596 self.out.extend_from_slice(b"i:");
597 push_int(&mut self.out, value);
598 self.out.push(b';');
599 Ok(())
600 }
601
602 fn float(&mut self, text: &str) {
603 self.out.extend_from_slice(b"d:");
604 self.out.extend_from_slice(text.as_bytes());
605 self.out.push(b';');
606 }
607
608 fn string(&mut self, bytes: &[u8]) {
609 self.out.extend_from_slice(b"s:");
610 push_int(&mut self.out, bytes.len() as i128);
611 self.out.extend_from_slice(b":\"");
612 self.out.extend_from_slice(bytes);
613 self.out.extend_from_slice(b"\";");
614 }
615
616 fn key(
623 &mut self,
624 atom: Atom<'_>,
625 visibility: Option<Visibility>,
626 is_object: bool,
627 ) -> Result<(), Error> {
628 let mut key = key_of(atom)?;
629 if let Some(visibility) = visibility.filter(|x| *x != Visibility::Public) {
630 let name = match key {
631 Key::Int(value) => Cow::Owned(value.to_string().into_bytes()),
632 Key::Str(name) => name,
633 };
634 let mut mangled = Vec::with_capacity(name.len() + 3);
635 mangled.push(0);
636 match visibility {
637 Visibility::Private(class) => mangled.extend_from_slice(class.as_bytes()),
638 _ => mangled.push(b'*'),
639 }
640 mangled.push(0);
641 mangled.extend_from_slice(&name);
642 key = Key::Str(Cow::Owned(mangled));
643 }
644 match key {
645 Key::Int(value) if !is_object => self.int(value.into()),
646 Key::Int(value) => {
647 self.string(value.to_string().as_bytes());
648 Ok(())
649 }
650 Key::Str(name) => {
651 match int_key(&name).filter(|_| !is_object) {
652 Some(value) => self.int(value.into())?,
653 None => self.string(&name),
654 }
655 Ok(())
656 }
657 }
658 }
659}
660
661enum Key<'a> {
663 Int(i64),
664 Str(Cow<'a, [u8]>),
665}
666
667fn key_of(atom: Atom<'_>) -> Result<Key<'_>, Error> {
669 Ok(match atom {
670 Atom::Str(value) | Atom::Lexical(value) => Key::Str(match value.into_cow() {
671 Cow::Borrowed(value) => Cow::Borrowed(value.as_bytes()),
672 Cow::Owned(value) => Cow::Owned(value.into_bytes()),
673 }),
674 Atom::Char(value) => Key::Str(Cow::Owned(value.to_string().into_bytes())),
675 Atom::Bytes(value) => Key::Str(value.into_data()),
676 Atom::U64(value) => Key::Int(i64::try_from(value).map_err(|_| out_of_range())?),
677 Atom::I64(value) => Key::Int(value),
678 Atom::Bool(value) => Key::Int(value.into()),
680 Atom::Implicit(value) => {
681 let (text, value) = value.into_parts();
682 match value {
683 ImplicitValue::U64(value) => {
684 Key::Int(i64::try_from(value).map_err(|_| out_of_range())?)
685 }
686 ImplicitValue::I64(value) => Key::Int(value),
687 _ => Key::Str(Cow::Owned(text.into_owned().into_bytes())),
688 }
689 }
690 Atom::Ext(ref ext) => {
691 if let Some(value) = ext_int(ext) {
692 Key::Int(i64::try_from(value).map_err(|_| out_of_range())?)
693 } else if ext.is::<Reference>() {
694 return Err(unsupported_key());
695 } else {
696 match ext.fallback() {
697 Atom::Ext(_) => return Err(unsupported_key()),
698 fallback => match key_of(fallback)? {
699 Key::Int(value) => Key::Int(value),
700 Key::Str(name) => Key::Str(Cow::Owned(name.into_owned())),
701 },
702 }
703 }
704 }
705 _ => return Err(unsupported_key()),
706 })
707}
708
709fn ext_int(ext: &ExtValue<'_>) -> Option<i128> {
711 if let Some(&value) = ext.downcast_ref::<u128>() {
712 return Some(i128::try_from(value).unwrap_or(i128::MAX));
714 }
715 if let Some(&value) = ext.downcast_ref::<i128>() {
716 return Some(value);
717 }
718 ext.downcast_ref::<BigInt>().map(|value| {
719 value.to_i128().unwrap_or(if value.is_negative() {
720 i128::MIN
721 } else {
722 i128::MAX
723 })
724 })
725}
726
727fn check_class(class: &str) -> Result<(), Error> {
728 if !is_class_name(class.as_bytes()) {
729 return Err(Error::new(
730 ErrorKind::InvalidValue,
731 format!("invalid class name {:?}", class),
732 ));
733 }
734 Ok(())
735}
736
737fn push_int(out: &mut Vec<u8>, value: i128) {
739 let mut buf = [0u8; 40];
740 let mut pos = buf.len();
741 let negative = value < 0;
742 let mut rest = value.unsigned_abs();
743 loop {
744 pos -= 1;
745 buf[pos] = b'0' + (rest % 10) as u8;
746 rest /= 10;
747 if rest == 0 {
748 break;
749 }
750 }
751 if negative {
752 pos -= 1;
753 buf[pos] = b'-';
754 }
755 out.extend_from_slice(&buf[pos..]);
756}
757
758#[cold]
759fn out_of_range() -> Error {
760 Error::new(
761 ErrorKind::OutOfRange,
762 "integer out of range for PHP's serialization format",
763 )
764}
765
766#[cold]
767fn unsupported_key() -> Error {
768 Error::new(
769 ErrorKind::UnsupportedType,
770 "keys must be integers or strings",
771 )
772}