default.rs
Overview
The [default.rs](/projects/287/68131) file provides an internal Rust implementation of a **default value serialization mechanism** used within a Python object serialization context. Specifically, it defines the `DefaultSerializer` struct, which acts as a fallback serializer that delegates to a user-provided Python callable (the "default" function) when the usual serialization fails or is unsupported.
This file is part of a serialization framework that bridges Python objects with Rust serialization traits (from Serde), allowing complex Python objects to be serialized into formats supported by Serde serializers (e.g., JSON, YAML). The `DefaultSerializer` handles cases where Python objects require a custom fallback serialization by invoking a Python callable provided by the user.
Detailed Documentation
Struct: DefaultSerializer<'a>
pub(crate) struct DefaultSerializer<'a> {
previous: &'a PyObjectSerializer,
}
Description
A transparent wrapper struct designed to serialize Python objects with a fallback mechanism.
Holds a reference to a
PyObjectSerializerinstance, which contains the Python object to serialize and serialization state, including the user-defined "default" callable.
Fields
Name | Type | Description |
|---|---|---|
`previous` | `&'a PyObjectSerializer` | Reference to the previous serializer state, including the Python object and configuration. |
Usage Example
let default_serializer = DefaultSerializer::new(&py_object_serializer);
let result = default_serializer.serialize(serde_json::Serializer::new(...));
Methods
new
pub fn new(previous: &'a PyObjectSerializer) -> Self
Constructs a new
DefaultSerializerinstance.Parameters:
previous: Reference to an existingPyObjectSerializerthat holds the Python object and serialization state.
Returns: A
DefaultSerializerinstance wrappingprevious.
Trait Implementation: Serialize for DefaultSerializer<'_>
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
Description
Implements Serde's `Serialize` trait for `DefaultSerializer`. This method attempts to serialize the underlying Python object using a default fallback function defined in Python.
Behavior
Checks if a user-defined default callable (
self.previous.default) is available.Enforces a recursion limit on default calls to avoid infinite recursion.
Calls the Python default function with the Python object as the argument.
The call is performed differently depending on the Python version (
Py_3_10conditional compilation).
If the call returns
null, signals an unsupported type error.Otherwise, creates a new
PyObjectSerializerfor the result of the default call and serializes it recursively.Decrements the Python reference count for the returned object.
Returns the serialization result or an error.
Parameters
serializer: A Serde serializer instance to which the serialized data should be written.
Returns
Result<S::Ok, S::Error>: The result of serialization, either successful Serde output or an error.
Errors
SerializeError::DefaultRecursionLimitif the default recursion limit is exceeded.SerializeError::UnsupportedTypeif no default callable is provided or the callable returns an invalid result.
Usage Example
This method is usually called internally by Serde when serializing with the fallback default serializer:
let default_serializer = DefaultSerializer::new(&py_object_serializer);
match default_serializer.serialize(serde_json::Serializer::new(...)) {
Ok(serialized) => println!("Serialization successful"),
Err(e) => eprintln!("Serialization failed: {:?}", e),
}
Important Implementation Details
Recursion Control: The method uses
self.previous.state.default_calls_limit()to prevent infinite recursion in default calls, returning a specific error if the limit is reached.Version Compatibility: The code differentiates Python versions to call the default Python callable correctly:
For Python versions prior to 3.10, it uses
PyObject_CallFunctionObjArgs.For Python 3.10 and above, it uses
PyObject_Vectorcallfor performance.
Reference Counting: After calling the Python default callable, the resulting Python object has its reference counted decremented (
Py_DECREF) to avoid memory leaks.Error Handling: Uses macros (
err!,nonnull!,unlikely!) to facilitate error reporting and branch prediction hints.
Interaction with Other Components
PyObjectSerializer:DefaultSerializerdepends onPyObjectSerializer, which encapsulates the Python object and serialization state. This file usespreviousto access the Python object pointer, the default callable, and the serialization state.SerializeError: Errors from serialization are reported through this error type.serde::ser::Serialize: This file provides an implementation of Serde'sSerializetrait, enabling integration with the Rust serialization ecosystem.Python C API (
pyo3_ffi): Interacts with the Python interpreter via thepyo3FFI bindings to call Python functions and manage Python object lifetimes.
File Structure and Workflow Diagram
flowchart TD
A[DefaultSerializer Struct]
A --> B[new() Constructor]
A --> C[serialize() Method]
C --> D{Check default callable exists}
D -- Yes --> E[Check recursion limit]
E -- Limit reached --> F[Return DefaultRecursionLimit Error]
E -- Limit OK --> G[Call Python default callable]
G --> H{Call success?}
H -- No --> I[Return UnsupportedType Error]
H -- Yes --> J[Create new PyObjectSerializer for result]
J --> K[Recursively serialize result]
K --> L[Decrement Python ref count]
L --> M[Return serialization result]
D -- No --> I
Summary
The [default.rs](/projects/287/68131) file implements a critical fallback serialization feature for Python objects in Rust, allowing custom Python callables to define how unsupported types should be serialized. It carefully manages Python reference counting, recursion limits, and compatibility across Python versions, integrating tightly with the overall Python-to-Rust serialization framework. This ensures extensible, safe, and efficient fallback serialization behavior within the broader system.