Skip to main content

deser_php/
ser.rs

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/// Configures how values are serialized.
17///
18/// The output is what PHP's `serialize` writes for the same values (see
19/// the [crate documentation](crate#serialization)).  The only option is
20/// the [`Context`](deser_core::Context) (see
21/// [`set_context`](Self::set_context)).
22///
23/// ```
24/// use deser_php::SerializerConfig;
25///
26/// const CONFIG: SerializerConfig = SerializerConfig::new();
27/// assert_eq!(CONFIG.to_vec(&vec![1, 2]).unwrap(), b"a:2:{i:0;i:1;i:1;i:2;}");
28/// ```
29#[derive(Debug, Clone, Default, PartialEq, Eq)]
30pub struct SerializerConfig {
31    context: deser_core::Context,
32}
33
34impl SerializerConfig {
35    /// Creates the default configuration.
36    pub const fn new() -> SerializerConfig {
37        SerializerConfig {
38            context: deser_core::Context::new(),
39        }
40    }
41
42    /// Returns a builder for the configuration (see [`SerializerConfigBuilder`]).
43    pub const fn builder() -> SerializerConfigBuilder {
44        SerializerConfigBuilder::new()
45    }
46
47    /// Returns a builder that starts with this configuration.
48    pub const fn into_builder(self) -> SerializerConfigBuilder {
49        SerializerConfigBuilder { value: self }
50    }
51
52    /// Sets the context the values are serialized in.
53    ///
54    /// The values of the context are the defaults of the extension values
55    /// of the state (see [`Context`](deser_core::Context)).  The
56    /// serializers and writers created with the configuration use this
57    /// context.  A context set on the driver takes precedence.
58    pub fn set_context(&mut self, context: deser_core::Context) {
59        self.context = context;
60    }
61
62    /// Returns the context the values are serialized in.
63    pub fn context(&self) -> &deser_core::Context {
64        &self.context
65    }
66
67    /// Gives the context to a driver which has none.
68    #[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    /// Serializes the given value.
76    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    /// Serializes the given value with a configured driver.
81    ///
82    /// The callback is invoked with the driver before the serialization
83    /// starts, for instance to add [`Layer`](deser_core::ser::Layer)s.
84    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    /// Serializes a value whose type is erased (see
99    /// [`to_vec`](Self::to_vec)).
100    ///
101    /// This is not generic: the code that exists for every type only
102    /// erases it.
103    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/// Builds a [`SerializerConfig`].
111///
112/// The methods have the names of the setters of [`SerializerConfig`] (without `set_`).
113#[derive(Debug, Clone)]
114#[must_use]
115pub struct SerializerConfigBuilder {
116    value: SerializerConfig,
117}
118
119impl SerializerConfigBuilder {
120    /// Creates a builder that starts with the default.
121    pub const fn new() -> SerializerConfigBuilder {
122        SerializerConfigBuilder {
123            value: SerializerConfig::new(),
124        }
125    }
126
127    /// Sets the context the values are serialized in.
128    ///
129    /// See [`SerializerConfig::set_context`].
130    pub fn context(mut self, context: deser_core::Context) -> SerializerConfigBuilder {
131        self.value.set_context(context);
132        self
133    }
134
135    /// Returns the built [`SerializerConfig`].
136    pub const fn build(self) -> SerializerConfig {
137        // the value cannot be moved out of the builder in a const fn as the
138        // builder needs dropping (the context has a destructor)
139        // SAFETY: the value is read once and the builder is forgotten
140        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/// Serializes values into PHP's serialization format.
153///
154/// The values are appended to the output one after another (they can be
155/// read back with [`Deserializer::iter`](crate::Deserializer::iter)).
156///
157/// ```
158/// use deser_php::Serializer;
159///
160/// let mut serializer = Serializer::new();
161/// serializer.serialize(&true).unwrap();
162/// serializer.serialize(&"hi").unwrap();
163/// assert_eq!(serializer.output(), b"b:1;s:2:\"hi\";");
164/// ```
165///
166/// The serializer is also the stream serializer of the format (see
167/// [`StreamSerializer`](ser::StreamSerializer)).  Values are written once
168/// they are complete as the lengths of arrays are written in front of
169/// them.  To write to a [`Write`](std::io::Write) use
170/// [`SerializerConfig::writer`].
171#[derive(Debug, Clone, Default)]
172pub struct Serializer {
173    config: SerializerConfig,
174    out: Vec<u8>,
175}
176
177impl Serializer {
178    /// Creates a serializer.
179    pub fn new() -> Serializer {
180        Serializer::with_config(SerializerConfig::new())
181    }
182
183    /// Creates a serializer with the given configuration.
184    pub fn with_config(config: SerializerConfig) -> Serializer {
185        Serializer {
186            config,
187            out: Vec::new(),
188        }
189    }
190
191    /// Returns the configuration.
192    pub fn config(&self) -> &SerializerConfig {
193        &self.config
194    }
195
196    /// Serializes a value and appends it to the output.
197    pub fn serialize<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
198        ser::Serializer::serialize(self, value)
199    }
200
201    /// Serializes a value with a configured driver.
202    ///
203    /// The callback is invoked with the driver before the value is
204    /// serialized, for instance to add [`Layer`](deser_core::ser::Layer)s.
205    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    /// Returns the output written so far (that was not cleared).
217    pub fn output(&self) -> &[u8] {
218        &self.out
219    }
220
221    /// Returns the output.
222    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    /// Creates a writer of values (see
249    /// [`deser::io::Writer`](deser_core::io::Writer)).
250    ///
251    /// The values are written one after another, each once it's complete.
252    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    /// Serializes a value to a writer.
257    ///
258    /// See [`to_writer`].
259    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/// Serializes a value to a writer.
269///
270/// ```
271/// let mut out = Vec::new();
272/// deser_php::to_writer(&mut out, &vec!["a", "b"]).unwrap();
273/// assert_eq!(out, br#"a:2:{i:0;s:1:"a";i:1;s:1:"b";}"#);
274/// ```
275#[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
283/// Serializes a value into PHP's serialization format.
284///
285/// This uses the default [`SerializerConfig`].
286///
287/// ```
288/// #[derive(deser::Serialize)]
289/// struct Package {
290///     name: String,
291///     tags: Vec<String>,
292/// }
293/// let package = Package { name: "deser".into(), tags: vec!["a".into()] };
294/// assert_eq!(
295///     deser_php::to_vec(&package).unwrap(),
296///     br#"a:2:{s:4:"name";s:5:"deser";s:4:"tags";a:1:{i:0;s:1:"a";}}"#
297/// );
298/// ```
299pub fn to_vec<T: Serialize + ?Sized>(value: &T) -> Result<Vec<u8>, Error> {
300    SerializerConfig::new().to_vec(value)
301}
302
303/// Serializes the value of a driver.
304fn 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
310/// The kind of an open container.
311enum Container {
312    /// A sequence, written as array with the keys `0`, `1`, ...
313    List(u64),
314    Array,
315    Object(String),
316}
317
318/// An open container.
319struct Open {
320    container: Container,
321    /// The index of the header in `Writer::headers`.
322    header: usize,
323    /// The number of entries.
324    count: usize,
325    /// `true` if a key comes next (maps only).
326    expects_key: bool,
327}
328
329/// Writes the events of a value.
330///
331/// The number of entries is written in front of the entries of arrays and
332/// objects.  The headers are inserted once the value is complete.
333#[derive(Default)]
334struct Writer {
335    out: Vec<u8>,
336    stack: Vec<Open>,
337    /// The headers of the arrays and objects and where they go, in the
338    /// order of the output.
339    headers: Vec<(usize, Vec<u8>)>,
340    /// `true` once the top-level value started.
341    started: bool,
342    /// For every value that has a number (see [`Reference`]), `true` if
343    /// it's an object, references can only refer to earlier values.
344    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    /// Returns the output with the headers inserted.
402    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    /// Writes the first event of a value.
426    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                    // references are numbered when they are written
439                    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    /// Closes the innermost container and writes its header.
485    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            // values whose type was inferred from text are written as value
529            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            // like the deserializer, references refer to an earlier value,
540            // `r:` to an object.  `r:` has a number itself, `R:` does not.
541            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        // numbers from text formats are integers if their text is one
567        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    /// Writes an atom with a class: an enum case or a custom serialized
583    /// object.
584    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    /// Writes a key.
645    ///
646    /// Arrays have integer and string keys, strings which are the text of
647    /// an integer are integers (like in PHP).  The keys of objects are the
648    /// names of properties, which are strings (with the prefix of their
649    /// visibility).
650    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
689/// A key of an array or object.
690enum Key<'a> {
691    Int(i64),
692    Str(Cow<'a, [u8]>),
693}
694
695/// Converts the atom of a key.
696fn 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        // like PHP: `true` is the key `1`
707        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
737/// Returns the value of the extension types for integers.
738fn ext_int(ext: &ExtValue<'_>) -> Option<i128> {
739    if let Some(&value) = ext.downcast_ref::<u128>() {
740        // out of range values fail
741        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
765/// Appends the decimal text of an integer.
766fn 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}