Skip to main content

deser_pickle/
lib.rs

1//! Parse and serialize Python's pickle format compatible with deser.
2//!
3//! ```rust
4//! use deser::{Deserialize, Serialize};
5//!
6//! #[derive(Debug, PartialEq, Serialize, Deserialize)]
7//! struct Session {
8//!     user_id: u64,
9//!     roles: Vec<String>,
10//! }
11//!
12//! let session = Session { user_id: 42, roles: vec!["admin".into()] };
13//! let bytes = deser_pickle::to_vec(&session).unwrap();
14//! // what `pickle.dumps({"user_id": 42, "roles": ["admin"]}, 4)` reads back
15//! assert_eq!(deser_pickle::from_slice::<Session>(&bytes).unwrap(), session);
16//! ```
17//!
18//! **Pickles are programs.**  Python runs them and imports and calls
19//! whatever they ask for, which is why unpickling untrusted data in Python
20//! is unsafe.  This crate never runs code: it runs the pickle machine but
21//! instead of importing classes and calling them it records what would
22//! have been called (see [Objects](#objects)).
23//!
24//! # Data Model
25//!
26//! Python's values map onto the deser data model as follows:
27//!
28//! | Python                           | deser                                         |
29//! |----------------------------------|-----------------------------------------------|
30//! | `None`                           | `Null`                                        |
31//! | `bool`                           | `Bool`                                        |
32//! | `int`                            | `U64`, `I64`, `u128`, `i128` or [`BigInt`](deser_core::ext::BigInt) |
33//! | `float`                          | `F64`                                         |
34//! | `str`                            | `Str`                                         |
35//! | `bytes`                          | `Bytes`                                       |
36//! | `bytearray`                      | `Bytes` (with [`Kind::ByteArray`])            |
37//! | `str` of Python 2                | `Str` if valid UTF-8, `Bytes` otherwise       |
38//! | `list`                           | sequences                                     |
39//! | `tuple`, `set`, `frozenset`      | sequences (with a [`Kind`])                   |
40//! | `dict`                           | maps (keys can be any value)                  |
41//! | classes and functions            | [`Global`] (the dotted path as fallback)      |
42//! | other objects                    | their state with a [class](#objects)          |
43//! | a value that contains itself     | [`Reference`] (see [References](#references)) |
44//!
45//! Empty sequences and maps are both: an empty list deserializes into a
46//! struct (with defaults) and an empty dict into a `Vec`.
47//!
48//! Deserialization is strict where Python is lenient: data after the
49//! `STOP` opcode is an error (Python ignores it).  Strings that contain
50//! surrogates (which Python allows) cannot be held by Rust strings and are
51//! an error.  Python checks that the keys of dicts and the items of sets
52//! are hashable and merges equal ones, this crate passes them on as they
53//! are.  Persistent ids, extension codes and out-of-band buffers (which
54//! need help from the code that unpickles) are not supported.
55//!
56//! # Objects
57//!
58//! Pickles create instances of classes by calling them (or `__new__`) with
59//! arguments, then set their state (`BUILD`, which calls `__setstate__`)
60//! and add items (for list and dict subclasses).  Instead of calling them,
61//! this crate records the calls.  An object is emitted as
62//!
63//! * its items, if items were added to it (a map for `__setitem__`, a
64//!   sequence for `append` and `extend`),
65//! * else its state: a map if it's a dict (the instance dictionary) or a
66//!   tuple of two dicts (the dictionary and the slots, which are merged),
67//!   the state itself otherwise,
68//! * else its arguments: no arguments are an empty map (or the keyword
69//!   arguments), one is the argument, more are a tuple.
70//!
71//! A plain class instance (including dataclasses) is a map of its
72//! attributes, an `OrderedDict` a map of its items, a `Decimal` its text
73//! and an enum member its value.  The class is passed on out of band as
74//! event data together with the [`Form`] the object is created in from
75//! the value: [`take_class`] and [`take_form`] return them, [`set_class`]
76//! and [`set_form`] set them for serialization and [`Object`] captures
77//! them.  Types that do not care about classes never see them:
78//!
79//! ```rust
80//! use deser_pickle::{Form, Global, Object};
81//!
82//! #[derive(Debug, deser::Deserialize, deser::Serialize)]
83//! struct User {
84//!     name: String,
85//! }
86//!
87//! // `pickle.dumps(User(name="Jane"), 4)` with a class `User` of `app`
88//! let input = b"\x80\x04\x95%\x00\x00\x00\x00\x00\x00\x00\x8c\x03app\x94\x8c\x04User\x94\x93\x94)\x81\x94}\x94\x8c\x04name\x94\x8c\x04Jane\x94sb.";
89//! let user: User = deser_pickle::from_slice(input).unwrap();
90//! assert_eq!(user.name, "Jane");
91//!
92//! let user: Object<User> = deser_pickle::from_slice(input).unwrap();
93//! assert_eq!(user.class, Some(Global::new("app", "User")));
94//! assert_eq!(user.form, Some(Form::State));
95//!
96//! // written back as Python writes it: `User.__new__(User)` with the state
97//! assert_eq!(
98//!     deser_pickle::to_vec(&user).unwrap(),
99//!     b"\x80\x04\x8c\x03app\x8c\x04User\x93)\x81}(\x8c\x04name\x8c\x04Janeub."
100//! );
101//! ```
102//!
103//! Objects that need both arguments and state (like classes with
104//! `__getnewargs__`) are emitted as their state, their arguments are lost.
105//!
106//! The globals that stand for builtin types are understood: `set`,
107//! `frozenset`, `bytearray`, `bytes`, `_codecs.encode` (bytes of protocols
108//! 0 to 2) and `copyreg._reconstructor` (objects of protocols 0 and 1).
109//! Like Python, the names of Python 2 (such as `__builtin__.unicode`) are
110//! read as the ones of Python 3 (`builtins.str`) before protocol 3.
111//!
112//! # References
113//!
114//! A pickle is a graph: values can be reached more than once (the memo of
115//! the pickle refers back to them) and values can contain themselves (a
116//! list that contains itself, a child object that refers to its parent).
117//! The data model of deser is a tree:
118//!
119//! * A value that is reached more than once is emitted at every place.
120//!   Every time its first event carries the same id as event data (see
121//!   [`take_shared_id`]), which allows types to share them again.
122//!   [`DeserializerConfig::set_max_shared_events`] limits how much is
123//!   emitted for repeated values.
124//! * Where a value is reached again from within itself (a cycle) it cannot
125//!   be emitted again.  A [`Reference`] with its id is emitted instead,
126//!   whose fallback is `null`: types which do not understand references see
127//!   a missing value, an `Option` is `None`.
128//!
129//! ```rust
130//! #[derive(Debug, deser::Deserialize)]
131//! struct Node {
132//!     name: String,
133//!     parent: Option<Box<Node>>,
134//!     children: Vec<Node>,
135//! }
136//!
137//! // a root with a child whose parent is the root (`tree.Node`)
138//! let input = b"\x80\x04\x95[\x00\x00\x00\x00\x00\x00\x00\x8c\x04tree\x94\x8c\x04Node\x94\x93\x94)\x81\x94}\x94(\x8c\x04name\x94\x8c\x04root\x94\x8c\x06parent\x94N\x8c\x08children\x94]\x94h\x02)\x81\x94}\x94(h\x05\x8c\x05child\x94h\x07h\x03h\x08]\x94ubaub.";
139//! let root: Node = deser_pickle::from_slice(input).unwrap();
140//! assert_eq!(root.children[0].name, "child");
141//! assert!(root.children[0].parent.is_none());
142//! ```
143//!
144//! The serializer writes values with an id once and refers to them after
145//! that, so values deserialized into types that keep the event data (like
146//! [`deser_value::Value`](https://docs.rs/deser-value)) are written back
147//! with their sharing and cycles.  Tuples that contain themselves cannot be
148//! written.
149//!
150//! # Serialization
151//!
152//! The serializer writes protocol 4 by default (protocols 2 to 5 are
153//! supported, see [`SerializerConfig::set_protocol`]):
154//!
155//! * sequences are lists, unless they have a [`Kind`]: tuples, sets and
156//!   frozensets.  Sequences in keys of maps are tuples.
157//! * maps are dicts.  Keys can be any value but maps.
158//! * bytes are `bytes` (or `bytearray`s with [`Kind::ByteArray`]).
159//! * values with a [class](#objects) are objects, created in their
160//!   [`Form`].  Without a form, maps are the state of `cls.__new__(cls)`
161//!   (like Python pickles a class instance), lists are appended to the new
162//!   object (like a list subclass), tuples are the arguments of the class
163//!   (`cls(*value)`) and other values the argument (`cls(value)`).
164//! * before protocol 3 the globals are written with the names of Python 2
165//!   (like Python does).
166//! * [`Global`]s are globals, [`Reference`]s refer to the value of their id.
167//! * other extension types (such as UUIDs and decimals) are written as
168//!   their fallback, usually a string.
169//!
170//! # Features
171//!
172//! * `io` (enabled by default): reading and writing streams of the
173//!   standard library with [`from_reader`] and [`to_writer`] and the
174//!   readers and writers of [`deser::io`](deser_core::io)
175//!   ([`DeserializerConfig::reader`] and [`SerializerConfig::writer`]).
176//!   Requires `std`.  The stream serializer ([`Serializer`]) and
177//!   deserializer ([`StreamDeserializer`]) do not need it.
178//! * `std` (enabled by default): uses the standard library.  Without it
179//!   this crate only needs `alloc` (see [`no_std`](https://docs.rs/deser/latest/deser/#no_std)).
180#![doc(html_logo_url = "https://raw.githubusercontent.com/mitsuhiko/deser/main/artwork/logo.svg")]
181#![cfg_attr(not(any(feature = "std", test)), no_std)]
182
183extern crate alloc;
184
185mod compat;
186mod de;
187mod emit;
188mod ser;
189mod stream;
190mod text;
191mod types;
192mod vm;
193
194pub use self::de::{Deserializer, DeserializerConfig, DeserializerConfigBuilder, Iter, from_slice};
195#[cfg(feature = "io")]
196pub use self::ser::to_writer;
197pub use self::ser::{Serializer, SerializerConfig, SerializerConfigBuilder, to_vec};
198pub use self::stream::StreamDeserializer;
199#[cfg(feature = "io")]
200pub use self::stream::from_reader;
201pub use self::types::{
202    Form, Global, Kind, Object, Reference, set_class, set_form, set_kind, set_shared_id,
203    take_class, take_form, take_kind, take_shared_id,
204};
205
206// the examples of the readme are tested
207#[cfg(doctest)]
208#[doc = include_str!("../README.md")]
209struct ReadmeDoctests;