Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support json cow of jiter 0.1.0 #1231

Merged
merged 1 commit into from Mar 20, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -44,7 +44,7 @@ base64 = "0.21.7"
num-bigint = "0.4.4"
python3-dll-a = "0.2.7"
uuid = "1.7.0"
jiter = {version = "0.0.7", features = ["python"]}
jiter = { version = "0.1.0", features = ["python"] }

[lib]
name = "_pydantic_core"
Expand Down
2 changes: 1 addition & 1 deletion src/errors/line_error.rs
Expand Up @@ -151,7 +151,7 @@ impl ValLineError {
#[derive(Clone)]
pub enum InputValue {
Python(PyObject),
Json(JsonValue),
Json(JsonValue<'static>),
}

impl ToPyObject for InputValue {
Expand Down
7 changes: 7 additions & 0 deletions src/errors/location.rs
@@ -1,5 +1,6 @@
use pyo3::exceptions::PyTypeError;
use pyo3::sync::GILOnceCell;
use std::borrow::Cow;
use std::fmt;

use pyo3::prelude::*;
Expand Down Expand Up @@ -52,6 +53,12 @@ impl From<&str> for LocItem {
}
}

impl From<Cow<'_, str>> for LocItem {
fn from(s: Cow<'_, str>) -> Self {
Self::S(s.into_owned())
}
}

impl From<i64> for LocItem {
fn from(i: i64) -> Self {
Self::I(i)
Expand Down
2 changes: 1 addition & 1 deletion src/input/input_abstract.rs
Expand Up @@ -180,7 +180,7 @@ pub trait Input<'py>: fmt::Debug + ToPyObject {

fn validate_frozenset(&self, strict: bool) -> ValMatch<Self::Set<'_>>;

fn validate_iter(&self) -> ValResult<GenericIterator>;
fn validate_iter(&self) -> ValResult<GenericIterator<'static>>;

fn validate_date(&self, strict: bool) -> ValMatch<EitherDate<'py>>;

Expand Down
100 changes: 50 additions & 50 deletions src/input/input_json.rs
Expand Up @@ -24,26 +24,26 @@ use super::{
};

/// This is required but since JSON object keys are always strings, I don't think it can be called
impl From<&JsonValue> for LocItem {
impl From<&JsonValue<'_>> for LocItem {
fn from(json_value: &JsonValue) -> Self {
match json_value {
JsonValue::Int(i) => (*i).into(),
JsonValue::Str(s) => s.as_str().into(),
JsonValue::Str(s) => s.clone().into(),
v => format!("{v:?}").into(),
}
}
}

impl From<JsonValue> for LocItem {
impl From<JsonValue<'_>> for LocItem {
fn from(json_value: JsonValue) -> Self {
(&json_value).into()
}
}

impl<'py> Input<'py> for JsonValue {
impl<'py, 'data> Input<'py> for JsonValue<'data> {
fn as_error_value(&self) -> InputValue {
// cloning JsonValue is cheap due to use of Arc
InputValue::Json(self.clone())
InputValue::Json(self.to_static())
}

fn is_none(&self) -> bool {
Expand All @@ -63,19 +63,19 @@ impl<'py> Input<'py> for JsonValue {
}
}

type Arguments<'a> = JsonArgs<'a>
type Arguments<'a> = JsonArgs<'a, 'data>
where
Self: 'a,;

fn validate_args(&self) -> ValResult<JsonArgs<'_>> {
fn validate_args(&self) -> ValResult<JsonArgs<'_, 'data>> {
match self {
JsonValue::Object(object) => Ok(JsonArgs::new(None, Some(object))),
JsonValue::Array(array) => Ok(JsonArgs::new(Some(array), None)),
_ => Err(ValError::new(ErrorTypeDefaults::ArgumentsType, self)),
}
}

fn validate_dataclass_args<'a>(&'a self, class_name: &str) -> ValResult<JsonArgs<'a>> {
fn validate_dataclass_args<'a>(&'a self, class_name: &str) -> ValResult<JsonArgs<'a, 'data>> {
match self {
JsonValue::Object(object) => Ok(JsonArgs::new(None, Some(object))),
_ => {
Expand All @@ -98,7 +98,7 @@ impl<'py> Input<'py> for JsonValue {
// TODO: in V3 we may want to make JSON str always win if in union, for consistency,
// see https://github.com/pydantic/pydantic-core/pull/867#discussion_r1386582501
match self {
JsonValue::Str(s) => Ok(ValidationMatch::strict(s.as_str().into())),
JsonValue::Str(s) => Ok(ValidationMatch::strict(s.as_ref().into())),
JsonValue::Int(i) if !strict && coerce_numbers_to_str => Ok(ValidationMatch::lax(i.to_string().into())),
JsonValue::BigInt(b) if !strict && coerce_numbers_to_str => Ok(ValidationMatch::lax(b.to_string().into())),
JsonValue::Float(f) if !strict && coerce_numbers_to_str => Ok(ValidationMatch::lax(f.to_string().into())),
Expand Down Expand Up @@ -142,7 +142,7 @@ impl<'py> Input<'py> for JsonValue {

fn exact_str(&self) -> ValResult<EitherString<'_>> {
match self {
JsonValue::Str(s) => Ok(s.as_str().into()),
JsonValue::Str(s) => Ok(s.as_ref().into()),
_ => Err(ValError::new(ErrorTypeDefaults::StringType, self)),
}
}
Expand All @@ -168,7 +168,7 @@ impl<'py> Input<'py> for JsonValue {
}
}

type Dict<'a> = &'a JsonObject;
type Dict<'a> = &'a JsonObject<'data> where Self: 'a;

fn validate_dict(&self, _strict: bool) -> ValResult<Self::Dict<'_>> {
match self {
Expand All @@ -181,51 +181,51 @@ impl<'py> Input<'py> for JsonValue {
self.validate_dict(false)
}

type List<'a> = &'a JsonArray;
type List<'a> = &'a JsonArray<'data> where Self: 'a;

fn validate_list(&self, _strict: bool) -> ValMatch<&JsonArray> {
fn validate_list(&self, _strict: bool) -> ValMatch<&JsonArray<'data>> {
match self {
JsonValue::Array(a) => Ok(ValidationMatch::exact(a)),
_ => Err(ValError::new(ErrorTypeDefaults::ListType, self)),
}
}

type Tuple<'a> = &'a JsonArray;
type Tuple<'a> = &'a JsonArray<'data> where Self: 'a;

fn validate_tuple(&self, _strict: bool) -> ValMatch<&JsonArray> {
fn validate_tuple(&self, _strict: bool) -> ValMatch<&JsonArray<'data>> {
// just as in set's case, List has to be allowed
match self {
JsonValue::Array(a) => Ok(ValidationMatch::strict(a)),
_ => Err(ValError::new(ErrorTypeDefaults::TupleType, self)),
}
}

type Set<'a> = &'a JsonArray;
type Set<'a> = &'a JsonArray<'data> where Self: 'a;

fn validate_set(&self, _strict: bool) -> ValMatch<&JsonArray> {
fn validate_set(&self, _strict: bool) -> ValMatch<&JsonArray<'data>> {
// we allow a list here since otherwise it would be impossible to create a set from JSON
match self {
JsonValue::Array(a) => Ok(ValidationMatch::strict(a)),
_ => Err(ValError::new(ErrorTypeDefaults::SetType, self)),
}
}

fn validate_frozenset(&self, _strict: bool) -> ValMatch<&JsonArray> {
fn validate_frozenset(&self, _strict: bool) -> ValMatch<&JsonArray<'data>> {
// we allow a list here since otherwise it would be impossible to create a frozenset from JSON
match self {
JsonValue::Array(a) => Ok(ValidationMatch::strict(a)),
_ => Err(ValError::new(ErrorTypeDefaults::FrozenSetType, self)),
}
}

fn validate_iter(&self) -> ValResult<GenericIterator> {
fn validate_iter(&self) -> ValResult<GenericIterator<'static>> {
match self {
JsonValue::Array(a) => Ok(a.clone().into()),
JsonValue::Array(a) => Ok(GenericIterator::from(a.clone()).into_static()),
JsonValue::Str(s) => Ok(string_to_vec(s).into()),
JsonValue::Object(object) => {
// return keys iterator to match python's behavior
let keys: JsonArray = JsonArray::new(object.keys().map(|k| JsonValue::Str(k.clone())).collect());
Ok(keys.into())
Ok(GenericIterator::from(keys).into_static())
}
_ => Err(ValError::new(ErrorTypeDefaults::IterableType, self)),
}
Expand Down Expand Up @@ -303,7 +303,7 @@ impl<'py> Input<'py> for str {
fn as_error_value(&self) -> InputValue {
// Justification for the clone: this is on the error pathway and we are generally ok
// with errors having a performance penalty
InputValue::Json(JsonValue::Str(self.to_owned()))
InputValue::Json(JsonValue::Str(self.to_owned().into()))
}

fn as_kwargs(&self, _py: Python<'py>) -> Option<Bound<'py, PyDict>> {
Expand Down Expand Up @@ -394,7 +394,7 @@ impl<'py> Input<'py> for str {
Err(ValError::new(ErrorTypeDefaults::SetType, self))
}

fn validate_iter(&self) -> ValResult<GenericIterator> {
fn validate_iter(&self) -> ValResult<GenericIterator<'static>> {
Ok(string_to_vec(self).into())
}

Expand Down Expand Up @@ -441,21 +441,21 @@ impl BorrowInput<'_> for String {
}
}

impl BorrowInput<'_> for JsonValue {
type Input = JsonValue;
impl<'data> BorrowInput<'_> for JsonValue<'data> {
type Input = JsonValue<'data>;
fn borrow_input(&self) -> &Self::Input {
self
}
}

fn string_to_vec(s: &str) -> JsonArray {
JsonArray::new(s.chars().map(|c| JsonValue::Str(c.to_string())).collect())
fn string_to_vec(s: &str) -> JsonArray<'static> {
JsonArray::new(s.chars().map(|c| JsonValue::Str(c.to_string().into())).collect())
}

impl<'py> ValidatedDict<'py> for &'_ JsonObject {
impl<'py, 'data> ValidatedDict<'py> for &'_ JsonObject<'data> {
type Key<'a> = &'a str where Self: 'a;

type Item<'a> = &'a JsonValue where Self: 'a;
type Item<'a> = &'a JsonValue<'data> where Self: 'a;

fn get_item<'k>(&self, key: &'k LookupKey) -> ValResult<Option<(&'k LookupPath, Self::Item<'_>)>> {
key.json_get(self)
Expand All @@ -469,12 +469,12 @@ impl<'py> ValidatedDict<'py> for &'_ JsonObject {
&'a self,
consumer: impl ConsumeIterator<ValResult<(Self::Key<'a>, Self::Item<'a>)>, Output = R>,
) -> ValResult<R> {
Ok(consumer.consume_iterator(LazyIndexMap::iter(self).map(|(k, v)| Ok((k.as_str(), v)))))
Ok(consumer.consume_iterator(LazyIndexMap::iter(self).map(|(k, v)| Ok((k.as_ref(), v)))))
}
}

impl<'a, 'py> ValidatedList<'py> for &'a JsonArray {
type Item = &'a JsonValue;
impl<'a, 'py, 'data> ValidatedList<'py> for &'a JsonArray<'data> {
type Item = &'a JsonValue<'data>;

fn len(&self) -> Option<usize> {
Some(SmallVec::len(self))
Expand All @@ -487,8 +487,8 @@ impl<'a, 'py> ValidatedList<'py> for &'a JsonArray {
}
}

impl<'a, 'py> ValidatedTuple<'py> for &'a JsonArray {
type Item = &'a JsonValue;
impl<'a, 'data> ValidatedTuple<'_> for &'a JsonArray<'data> {
type Item = &'a JsonValue<'data>;

fn len(&self) -> Option<usize> {
Some(SmallVec::len(self))
Expand All @@ -498,29 +498,29 @@ impl<'a, 'py> ValidatedTuple<'py> for &'a JsonArray {
}
}

impl<'a, 'py> ValidatedSet<'py> for &'a JsonArray {
type Item = &'a JsonValue;
impl<'a, 'data> ValidatedSet<'_> for &'a JsonArray<'data> {
type Item = &'a JsonValue<'data>;

fn iterate<R>(self, consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R> {
Ok(consumer.consume_iterator(self.iter().map(Ok)))
}
}

#[cfg_attr(debug_assertions, derive(Debug))]
pub struct JsonArgs<'a> {
args: Option<&'a [JsonValue]>,
kwargs: Option<&'a JsonObject>,
pub struct JsonArgs<'a, 'data> {
args: Option<&'a [JsonValue<'data>]>,
kwargs: Option<&'a JsonObject<'data>>,
}

impl<'a> JsonArgs<'a> {
fn new(args: Option<&'a [JsonValue]>, kwargs: Option<&'a JsonObject>) -> Self {
impl<'a, 'data> JsonArgs<'a, 'data> {
fn new(args: Option<&'a [JsonValue<'data>]>, kwargs: Option<&'a JsonObject<'data>>) -> Self {
Self { args, kwargs }
}
}

impl<'a> Arguments<'_> for JsonArgs<'a> {
type Args = [JsonValue];
type Kwargs = JsonObject;
impl<'a, 'data> Arguments<'_> for JsonArgs<'a, 'data> {
type Args = [JsonValue<'data>];
type Kwargs = JsonObject<'data>;

fn args(&self) -> Option<&Self::Args> {
self.args
Expand All @@ -531,8 +531,8 @@ impl<'a> Arguments<'_> for JsonArgs<'a> {
}
}

impl PositionalArgs<'_> for [JsonValue] {
type Item<'a> = &'a JsonValue;
impl<'data> PositionalArgs<'_> for [JsonValue<'data>] {
type Item<'a> = &'a JsonValue<'data> where Self: 'a;

fn len(&self) -> usize {
<[JsonValue]>::len(self)
Expand All @@ -545,9 +545,9 @@ impl PositionalArgs<'_> for [JsonValue] {
}
}

impl KeywordArgs<'_> for JsonObject {
type Key<'a> = &'a str;
type Item<'a> = &'a JsonValue;
impl<'data> KeywordArgs<'_> for JsonObject<'data> {
type Key<'a> = &'a str where Self: 'a;
type Item<'a> = &'a JsonValue<'data> where Self: 'a;

fn len(&self) -> usize {
LazyIndexMap::len(self)
Expand All @@ -556,6 +556,6 @@ impl KeywordArgs<'_> for JsonObject {
key.json_get(self)
}
fn iter(&self) -> impl Iterator<Item = ValResult<(Self::Key<'_>, Self::Item<'_>)>> {
LazyIndexMap::iter(self).map(|(k, v)| Ok((k.as_str(), v)))
LazyIndexMap::iter(self).map(|(k, v)| Ok((k.as_ref(), v)))
}
}
2 changes: 1 addition & 1 deletion src/input/input_python.rs
Expand Up @@ -475,7 +475,7 @@ impl<'py> Input<'py> for Bound<'py, PyAny> {
Err(ValError::new(ErrorTypeDefaults::FrozenSetType, self))
}

fn validate_iter(&self) -> ValResult<GenericIterator> {
fn validate_iter(&self) -> ValResult<GenericIterator<'static>> {
if self.iter().is_ok() {
Ok(self.into())
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/input/input_string.rs
Expand Up @@ -171,7 +171,7 @@ impl<'py> Input<'py> for StringMapping<'py> {
Err(ValError::new(ErrorTypeDefaults::FrozenSetType, self))
}

fn validate_iter(&self) -> ValResult<GenericIterator> {
fn validate_iter(&self) -> ValResult<GenericIterator<'static>> {
Err(ValError::new(ErrorTypeDefaults::IterableType, self))
}

Expand Down