deser_php/lib.rs
1//! Parse and serialize PHP's serialization format (the format of PHP's
2//! `serialize` and `unserialize`) compatible with deser.
3//!
4//! ```rust
5//! use deser::{Deserialize, Serialize};
6//!
7//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
8//! struct Session {
9//! user_id: u64,
10//! roles: Vec<String>,
11//! }
12//!
13//! let session = Session { user_id: 42, roles: vec!["admin".into()] };
14//! let bytes = deser_php::to_vec(&session).unwrap();
15//! assert_eq!(
16//! bytes,
17//! br#"a:2:{s:7:"user_id";i:42;s:5:"roles";a:1:{i:0;s:5:"admin";}}"#
18//! );
19//! assert_eq!(deser_php::from_slice::<Session>(&bytes).unwrap(), session);
20//! ```
21//!
22//! # Data Model
23//!
24//! PHP's values map onto the deser data model as follows:
25//!
26//! | PHP | deser |
27//! |--------------------------------------|-----------------------------------------|
28//! | `null` (`N;`) | `Null` |
29//! | booleans (`b:`) | `Bool` |
30//! | integers (`i:`) | `U64`, `I64` |
31//! | floats (`d:`) | `F64` |
32//! | strings (`s:` and `S:`) | `Str` if valid UTF-8, `Bytes` otherwise |
33//! | arrays with the keys `0`, `1`, ... | sequences |
34//! | other arrays | maps |
35//! | objects (`O:`) | maps with a [class](#classes) |
36//! | enum cases (`E:`) | `Str` (the case) with a [class](#classes) |
37//! | custom serialized objects (`C:`) | `Bytes` (the payload) with a [class](#classes) |
38//! | references (`r:` and `R:`) | [`Reference`] (see [References](#references)) |
39//!
40//! Arrays are both lists and maps in PHP. Arrays whose keys are `0`, `1`,
41//! `2`, ... in this order are sequences, all others are maps. The empty
42//! array is both: it's an empty sequence that types which expect a map
43//! (like structs) take as an empty map (see
44//! [`ContainerShape::set_ambiguous_empty`](deser_core::ContainerShape::set_ambiguous_empty)).
45//! The keys of maps are integers and strings, integers
46//! are passed on as [`Implicit`](deser_core::Atom::Implicit) atoms: maps
47//! with string keys take their text, maps with integer keys their value.
48//! Like PHP, strings that are the text of an integer (`"5"` but not `"05"`)
49//! are integer keys.
50//!
51//! PHP strings are bytes. Strings that are valid UTF-8 are passed on as
52//! text, all others as bytes. Types that expect bytes (like `Vec<u8>`)
53//! take the bytes of the text rather than decoding it as base64 (unless the
54//! context configures a [`BytesFormat`](deser_core::BytesFormat)).
55//!
56//! Deserialization is strict where PHP is lenient: data after the value is
57//! an error (PHP ignores it with a warning) and so are integers that do not
58//! fit into 64 bits (PHP clamps them). The functions that deserialize a
59//! value never instantiate classes or run code, objects are just maps.
60//!
61//! # Classes
62//!
63//! Objects, enum cases and custom serialized objects have a class. It's
64//! passed on out of band as event data of the value: [`take_class`]
65//! returns it, [`set_class`] sets it for serialization and [`Object`]
66//! captures it. Types that do not care about classes never see them, an
67//! object deserializes into a struct or map like an array:
68//!
69//! ```rust
70//! use deser_php::Object;
71//!
72//! #[derive(Debug, deser::Deserialize, deser::Serialize)]
73//! struct User {
74//! name: String,
75//! }
76//!
77//! let input = br#"O:4:"User":1:{s:4:"name";s:4:"Jane";}"#;
78//! let user: User = deser_php::from_slice(input).unwrap();
79//! assert_eq!(user.name, "Jane");
80//!
81//! let user: Object<User> = deser_php::from_slice(input).unwrap();
82//! assert_eq!(user.class.as_deref(), Some("User"));
83//! assert_eq!(deser_php::to_vec(&user).unwrap(), input);
84//! ```
85//!
86//! The names of protected and private properties have a prefix in PHP's
87//! format (`\0*\0name` and `\0Class\0name`). The deserializer removes it,
88//! so properties deserialize into fields of the same name whatever their
89//! visibility. The visibility is event data of the key (see
90//! [`take_visibility`] and [`set_visibility`]).
91//!
92//! Enum cases are strings, so they deserialize into enums with unit
93//! variants of the same name. Custom serialized objects (classes that
94//! implement `Serializable`) are written in a format that only the class
95//! knows, their payload is passed on as bytes.
96//!
97//! # References
98//!
99//! PHP writes values that appear more than once (the same object, or
100//! values that were assigned by reference) once and refers back to them
101//! with a number. **References are not resolved:** they are passed on as
102//! [`Reference`] markers which hold the number and the serializer writes
103//! them back as they are. The marker is close to useless for anything but
104//! detecting references and writing the input back unchanged: the number
105//! refers to the position of a value in the whole input, and there is no
106//! way to get from it to the value (see [`Reference`]). Other types than
107//! [`Reference`] receive the number as integer.
108//!
109//! # Serialization
110//!
111//! The serializer writes what PHP's `serialize` writes for the same values:
112//!
113//! * sequences are arrays with the keys `0`, `1`, ..., maps and structs are
114//! arrays with their keys. Maps with a [class](#classes) are objects.
115//! * keys are integers or strings. Strings that are the text of an
116//! integer are written as integer like PHP does, booleans are `0` and
117//! `1`. Other keys are an error.
118//! * floats are written with the shortest text that reads back as the same
119//! value, like PHP does (`0.1`, `1.0E+25`, `INF`, `NAN`).
120//! * bytes are strings, PHP strings are bytes. Integers out of the range
121//! of `i64` are an error.
122//! * other extension types (such as UUIDs and decimals) are written as
123//! their fallback, usually a string.
124//!
125//! # Features
126//!
127//! * `io` (enabled by default): reading and writing streams of the
128//! standard library with [`from_reader`] and [`to_writer`] and the
129//! readers and writers of [`deser::io`](deser_core::io)
130//! ([`DeserializerConfig::reader`] and [`SerializerConfig::writer`]).
131//! Values are validated before they are deserialized, the whole stream
132//! is read before its values are parsed. Requires `std`. The stream
133//! serializer ([`Serializer`]) and deserializer ([`StreamDeserializer`])
134//! do not need it.
135//! * `std` (enabled by default): uses the standard library. Without it
136//! this crate only needs `alloc` (see [`no_std`](https://docs.rs/deser/latest/deser/#no_std)).
137#![doc(html_logo_url = "https://raw.githubusercontent.com/mitsuhiko/deser/main/artwork/logo.svg")]
138#![cfg_attr(not(any(feature = "std", test)), no_std)]
139
140extern crate alloc;
141
142mod de;
143mod float;
144mod object;
145mod parser;
146mod reference;
147mod ser;
148mod stream;
149
150pub use self::de::{
151 Deserializer, DeserializerConfig, DeserializerConfigBuilder, Iter, from_slice, from_str,
152};
153pub use self::object::{
154 Object, Visibility, set_class, set_visibility, take_class, take_visibility,
155};
156pub use self::reference::{Reference, ReferenceKind};
157#[cfg(feature = "io")]
158pub use self::ser::to_writer;
159pub use self::ser::{Serializer, SerializerConfig, SerializerConfigBuilder, to_vec};
160pub use self::stream::StreamDeserializer;
161#[cfg(feature = "io")]
162pub use self::stream::from_reader;
163
164// the examples of the readme are tested
165#[cfg(doctest)]
166#[doc = include_str!("../README.md")]
167struct ReadmeDoctests;