Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 45 additions & 5 deletions src/client/body/json.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,57 @@
use indexmap::IndexMap;
use pyo3::{FromPyObject, prelude::*};
use serde::{Deserialize, Serialize};
use pyo3::{FromPyObject, prelude::*, pybacked::PyBackedStr};
use serde::{Deserialize, Deserializer, Serialize, Serializer};

/// Represents a JSON value for HTTP requests.
/// Supports objects, arrays, numbers, strings, booleans, and null.
#[derive(Clone, FromPyObject, IntoPyObject, Serialize, Deserialize)]
#[derive(FromPyObject, IntoPyObject, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Json {
Object(IndexMap<String, Json>),
Object(IndexMap<JsonString, Json>),
Boolean(bool),
Number(isize),
Float(f64),
String(String),
String(JsonString),
Null(Option<isize>),
Array(Vec<Json>),
}

/// A string type that can represent either a Python-backed string
/// or a standard Rust `String`. This allows for zero-copy deserialization
/// of strings originating from Python, improving performance when handling
/// JSON data that includes string values.
#[derive(IntoPyObject, PartialEq, Eq, Hash)]
pub enum JsonString {
PyString(PyBackedStr),
RustString(String),
}

impl FromPyObject<'_> for JsonString {
#[inline]
fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<Self> {
ob.extract().map(Self::PyString)
}
}

impl Serialize for JsonString {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
JsonString::PyString(pb) => serializer.serialize_str(pb.as_ref()),
JsonString::RustString(s) => serializer.serialize_str(s),
}
}
}

impl<'de> Deserialize<'de> for JsonString {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
String::deserialize(deserializer).map(JsonString::RustString)
}
}
3 changes: 2 additions & 1 deletion src/client/body/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use std::{
task::{Context, Poll},
};

use crate::rt::Runtime;
use bytes::Bytes;
use futures_util::Stream;
use pyo3::{
Expand All @@ -20,6 +19,8 @@ use pyo3::{
pybacked::{PyBackedBytes, PyBackedStr},
};

use crate::rt::Runtime;

/// Represents the body of an HTTP request.
/// Supports text, bytes, synchronous and asynchronous streaming bodies.
pub enum Body {
Expand Down
Loading