From 79fc02ffa0cf73677bc9690d8c717b7600436cfc Mon Sep 17 00:00:00 2001 From: Amos Wenger Date: Fri, 29 Nov 2024 20:41:14 +0100 Subject: [PATCH] Move things around re: absorbing merde_time in merde_core --- Justfile | 5 +- merde/README.md | 21 +++--- merde/examples/simple.rs | 17 +---- merde/src/lib.rs | 3 - merde_core/Cargo.toml | 1 + merde_core/src/array.rs | 4 +- merde_core/src/cowbytes.rs | 4 +- merde_core/src/cowstr.rs | 2 +- merde_core/src/error.rs | 2 +- merde_core/src/event.rs | 4 +- merde_core/src/into_static.rs | 4 +- merde_core/src/lib.rs | 3 +- merde_core/src/map.rs | 2 +- merde_core/src/{rfc3339.rs => time.rs} | 80 ++++++++++++++++----- merde_core/src/value.rs | 10 +-- merde_core/src/with_lifetime.rs | 6 +- merde_json/src/jiter_lite/string_decoder.rs | 2 +- merde_json/src/lib.rs | 8 +-- 18 files changed, 101 insertions(+), 77 deletions(-) rename merde_core/src/{rfc3339.rs => time.rs} (57%) diff --git a/Justfile b/Justfile index 85b1697..f3bd575 100644 --- a/Justfile +++ b/Justfile @@ -4,9 +4,6 @@ check: cargo check --all-features --all-targets cargo hack --each-feature --exclude-features=default,full check - cargo check --example simple --no-default-features --features=json - cargo run --example simple --features=core,json - # can't use cargo-nextest because we want to run doctests cargo test -F full @@ -27,5 +24,5 @@ check: just miri miri: - cargo +nightly miri run --example opinions -F json + cargo +nightly miri run --example opinions -F deserialize,json cargo +nightly miri test -p merde_core fieldslot diff --git a/merde/README.md b/merde/README.md index 626cebc..7428758 100644 --- a/merde/README.md +++ b/merde/README.md @@ -463,9 +463,8 @@ Which solves two problems at once: `merde` solves both of these with wrapper types: ```rust -use merde::time::OffsetDateTime; // re-export from the time crate use merde::CowStr; -use merde::time::Rfc3339; +use merde::time::{Rfc3339, OffsetDateTime}; #[derive(Debug)] struct Person<'s> { @@ -477,17 +476,15 @@ merde::derive! { impl (Deserialize, Serialize) for struct Person<'s> { name, birth } } -fn main() { - let input = r#" - { - "name": "Jane Smith", - "birth": "1990-01-01T00:00:00Z" - } - "#; +let input = r#" + { + "name": "Jane Smith", + "birth": "1990-01-01T00:00:00Z" + } +"#; - let person: Person = merde::json::from_str(input).unwrap(); - println!("person = {:?}", person); -} +let person: Person = merde::json::from_str(input).unwrap(); +println!("person = {:?}", person); ``` You can of course make your own newtype wrappers to control how a field gets deserialized. diff --git a/merde/examples/simple.rs b/merde/examples/simple.rs index 4b15910..ac31ca0 100644 --- a/merde/examples/simple.rs +++ b/merde/examples/simple.rs @@ -1,13 +1,7 @@ -#[cfg(feature = "core")] use merde::CowStr; +use merde_json::JsonSerialize; -#[cfg(not(feature = "core"))] -type CowStr<'s> = std::borrow::Cow<'s, str>; - -#[cfg(all(feature = "core", feature = "json"))] fn main() { - use merde::json::JsonSerialize; - let input = r#" { "name": "John Doe", @@ -36,15 +30,6 @@ fn main() { assert_eq!(person, person2); } -#[cfg(not(all(feature = "core", feature = "json")))] -fn main() { - eprintln!("Well if the `core` feature is not enabled,"); - eprintln!("we can't call `from_str_via_value` and stuff,"); - eprintln!("but this still serves as an example that"); - eprintln!("you can keep your `merde::derive!` in place,"); - eprintln!("they'll just not generate any code."); -} - #[derive(Debug, PartialEq, Eq)] #[allow(dead_code)] struct Address<'s> { diff --git a/merde/src/lib.rs b/merde/src/lib.rs index 0f060b0..7405ea3 100644 --- a/merde/src/lib.rs +++ b/merde/src/lib.rs @@ -12,9 +12,6 @@ pub use merde_yaml as yaml; #[allow(unused_imports)] use json::JsonSerialize; -#[cfg(feature = "time")] -pub use merde_time as time; - #[cfg(feature = "core")] pub use merde_core::*; diff --git a/merde_core/Cargo.toml b/merde_core/Cargo.toml index 6a7a740..face97d 100644 --- a/merde_core/Cargo.toml +++ b/merde_core/Cargo.toml @@ -39,3 +39,4 @@ rusqlite = ["dep:rusqlite"] [dev-dependencies] insta = "1.40.0" trybuild = "1.0.101" +time = { version = "0.3.36", features = ["macros"] } diff --git a/merde_core/src/array.rs b/merde_core/src/array.rs index 0beba6f..00963aa 100644 --- a/merde_core/src/array.rs +++ b/merde_core/src/array.rs @@ -45,7 +45,7 @@ impl<'s> IntoIterator for Array<'s> { } } -impl<'s> Default for Array<'s> { +impl Default for Array<'_> { fn default() -> Self { Self::new() } @@ -65,7 +65,7 @@ impl<'s> Deref for Array<'s> { } } -impl<'s> DerefMut for Array<'s> { +impl DerefMut for Array<'_> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } diff --git a/merde_core/src/cowbytes.rs b/merde_core/src/cowbytes.rs index f120c97..4d29c0e 100644 --- a/merde_core/src/cowbytes.rs +++ b/merde_core/src/cowbytes.rs @@ -52,7 +52,7 @@ impl<'a> From<&'a [u8]> for CowBytes<'a> { } } -impl<'a> From> for CowBytes<'a> { +impl From> for CowBytes<'_> { fn from(v: Vec) -> Self { CowBytes::Owned(CompactBytes::from(v)) } @@ -67,7 +67,7 @@ impl<'a> From> for CowBytes<'a> { } } -impl<'a, 'b> PartialEq> for CowBytes<'b> { +impl<'a> PartialEq> for CowBytes<'_> { fn eq(&self, other: &CowBytes<'a>) -> bool { self.deref() == other.deref() } diff --git a/merde_core/src/cowstr.rs b/merde_core/src/cowstr.rs index df3fc16..2889f73 100644 --- a/merde_core/src/cowstr.rs +++ b/merde_core/src/cowstr.rs @@ -141,7 +141,7 @@ impl From> for Box { } } -impl<'a, 'b> PartialEq> for CowStr<'b> { +impl<'a> PartialEq> for CowStr<'_> { #[inline] fn eq(&self, other: &CowStr<'a>) -> bool { crate::compatibility_check_once(); diff --git a/merde_core/src/error.rs b/merde_core/src/error.rs index 45a175b..b613d39 100644 --- a/merde_core/src/error.rs +++ b/merde_core/src/error.rs @@ -171,7 +171,7 @@ impl std::fmt::Display for MerdeError<'_> { } } -impl<'s> std::error::Error for MerdeError<'s> {} +impl std::error::Error for MerdeError<'_> {} impl Value<'_> { /// Returns the [ValueType] for a given [Value]. diff --git a/merde_core/src/event.rs b/merde_core/src/event.rs index 058652d..cd03de3 100644 --- a/merde_core/src/event.rs +++ b/merde_core/src/event.rs @@ -71,7 +71,7 @@ impl<'s> From<&'s str> for Event<'s> { } } -impl<'s> From for Event<'s> { +impl From for Event<'_> { fn from(v: String) -> Self { Event::Str(v.into()) } @@ -89,7 +89,7 @@ impl<'s> From<&'s [u8]> for Event<'s> { } } -impl<'s> From> for Event<'s> { +impl From> for Event<'_> { fn from(v: Vec) -> Self { Event::Bytes(v.into()) } diff --git a/merde_core/src/into_static.rs b/merde_core/src/into_static.rs index 3a87f38..aed241a 100644 --- a/merde_core/src/into_static.rs +++ b/merde_core/src/into_static.rs @@ -36,7 +36,7 @@ where } } -impl<'a, T> IntoStatic for Cow<'a, T> +impl IntoStatic for Cow<'_, T> where T: ToOwned + ?Sized + 'static, { @@ -51,7 +51,7 @@ where } } -impl<'s> IntoStatic for Event<'s> { +impl IntoStatic for Event<'_> { type Output = Event<'static>; fn into_static(self) -> Self::Output { diff --git a/merde_core/src/lib.rs b/merde_core/src/lib.rs index 86b0885..573d195 100644 --- a/merde_core/src/lib.rs +++ b/merde_core/src/lib.rs @@ -45,8 +45,7 @@ pub use deserialize::DeserializeOwned; pub use deserialize::Deserializer; pub use deserialize::FieldSlot; -mod rfc3339; -pub use rfc3339::Rfc3339; +pub mod time; rubicon::compatibility_check! { ("merde_core_pkg_version", env!("CARGO_PKG_VERSION")), diff --git a/merde_core/src/map.rs b/merde_core/src/map.rs index 9e7aa2d..43b253a 100644 --- a/merde_core/src/map.rs +++ b/merde_core/src/map.rs @@ -66,7 +66,7 @@ impl<'s> IntoIterator for Map<'s> { } } -impl<'s> Default for Map<'s> { +impl Default for Map<'_> { fn default() -> Self { Self::new() } diff --git a/merde_core/src/rfc3339.rs b/merde_core/src/time.rs similarity index 57% rename from merde_core/src/rfc3339.rs rename to merde_core/src/time.rs index 0efa019..450a3e2 100644 --- a/merde_core/src/rfc3339.rs +++ b/merde_core/src/time.rs @@ -7,12 +7,21 @@ use std::{ ops::{Deref, DerefMut}, }; +use crate::WithLifetime; + /// A wrapper around date-time types that implements `Serialize` and `Deserialize` /// when the right cargo features are enabled. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] pub struct Rfc3339(pub T); +impl WithLifetime<'_> for Rfc3339 +where + T: 'static, +{ + type Lifetimed = Self; +} + impl From for Rfc3339 { fn from(t: T) -> Self { Rfc3339(t) @@ -51,6 +60,9 @@ where } } +#[cfg(feature = "time")] +pub use time::OffsetDateTime; + #[cfg(feature = "time")] mod time_impls { use super::*; @@ -99,28 +111,64 @@ mod time_impls { #[cfg(all(test, feature = "full"))] mod tests { use super::*; - use merde_json::{from_str, JsonSerialize}; + use crate::{Deserialize, Deserializer, Event, IntoStatic, MerdeError, Serializer}; + use std::collections::VecDeque; use time::macros::datetime; - #[test] - fn test_rfc3339_offset_date_time_roundtrip() { - let original = Rfc3339(datetime!(2023-05-15 14:30:00 UTC)); - let serialized = original.to_json_string().unwrap(); - let deserialized: Rfc3339 = from_str(&serialized).unwrap(); - assert_eq!(original, deserialized); + #[derive(Debug, Default)] + struct Journal { + events: VecDeque>, } - #[test] - fn test_rfc3339_offset_date_time_serialization() { - let dt = Rfc3339(datetime!(2023-05-15 14:30:00 UTC)); - let serialized = dt.to_json_string().unwrap(); - assert_eq!(serialized, r#""2023-05-15T14:30:00Z""#); + impl Serializer for Journal { + type Error = std::convert::Infallible; + + async fn write(&mut self, event: Event<'_>) -> Result<(), Self::Error> { + self.events.push_back(event.into_static()); + Ok(()) + } + } + + impl<'s> Deserializer<'s> for Journal { + type Error<'es> = MerdeError<'es>; + + fn next(&mut self) -> Result, Self::Error<'s>> { + Ok(self.events.pop_front().unwrap()) + } + + async fn t_starting_with>( + &mut self, + starter: Option>, + ) -> Result> { + if let Some(event) = starter { + self.events.push_front(event.into_static()); + } + T::deserialize(self).await + } } #[test] - fn test_rfc3339_offset_date_time_deserialization() { - let json = r#""2023-05-15T14:30:00Z""#; - let deserialized: Rfc3339 = from_str(json).unwrap(); - assert_eq!(deserialized, Rfc3339(datetime!(2023-05-15 14:30:00 UTC))); + fn test_rfc3339_offset_date_time_roundtrip() { + let original = Rfc3339(datetime!(2023-05-15 14:30:00 UTC)); + let mut journal: Journal = Default::default(); + + journal.serialize_sync(&original).unwrap(); + let deserialized: Rfc3339 = journal.deserialize_owned().unwrap(); + + assert_eq!(original, deserialized); } + + // #[test] + // fn test_rfc3339_offset_date_time_serialization() { + // let dt = Rfc3339(datetime!(2023-05-15 14:30:00 UTC)); + // let serialized = dt.to_json_string().unwrap(); + // assert_eq!(serialized, r#""2023-05-15T14:30:00Z""#); + // } + + // #[test] + // fn test_rfc3339_offset_date_time_deserialization() { + // let json = r#""2023-05-15T14:30:00Z""#; + // let deserialized: Rfc3339 = from_str(json).unwrap(); + // assert_eq!(deserialized, Rfc3339(datetime!(2023-05-15 14:30:00 UTC))); + // } } diff --git a/merde_core/src/value.rs b/merde_core/src/value.rs index a6ca55a..754c842 100644 --- a/merde_core/src/value.rs +++ b/merde_core/src/value.rs @@ -72,13 +72,13 @@ impl_from_for_value! { CowBytes<'s> => Bytes, } -impl<'s> From for Value<'s> { +impl From for Value<'_> { fn from(v: f32) -> Self { Value::Float((v as f64).into()) } } -impl<'s> From for Value<'s> { +impl From for Value<'_> { fn from(v: f64) -> Self { Value::Float(v.into()) } @@ -90,7 +90,7 @@ impl<'s> From<&'s str> for Value<'s> { } } -impl<'s> From for Value<'s> { +impl From for Value<'_> { fn from(v: String) -> Self { Value::Str(v.into()) } @@ -102,13 +102,13 @@ impl<'s> From<&'s String> for Value<'s> { } } -impl<'s> From<()> for Value<'s> { +impl From<()> for Value<'_> { fn from(_: ()) -> Self { Value::Null } } -impl<'s> From for Value<'s> { +impl From for Value<'_> { fn from(v: bool) -> Self { Value::Bool(v) } diff --git a/merde_core/src/with_lifetime.rs b/merde_core/src/with_lifetime.rs index d4bba76..a9f8730 100644 --- a/merde_core/src/with_lifetime.rs +++ b/merde_core/src/with_lifetime.rs @@ -36,11 +36,11 @@ macro_rules! impl_with_lifetime { }; } -impl<'a, 's, B: ToOwned + ?Sized + 's> WithLifetime<'s> for Cow<'a, B> { +impl<'s, B: ToOwned + ?Sized + 's> WithLifetime<'s> for Cow<'_, B> { type Lifetimed = Cow<'s, B>; } -impl<'a, 's> WithLifetime<'s> for &'a str { +impl<'s> WithLifetime<'s> for &str { type Lifetimed = &'s str; } @@ -66,7 +66,7 @@ impl_with_lifetime!( f64, ); -impl<'s> WithLifetime<'s> for () { +impl WithLifetime<'_> for () { type Lifetimed = (); } diff --git a/merde_json/src/jiter_lite/string_decoder.rs b/merde_json/src/jiter_lite/string_decoder.rs index 0f88c90..48023b8 100644 --- a/merde_json/src/jiter_lite/string_decoder.rs +++ b/merde_json/src/jiter_lite/string_decoder.rs @@ -52,7 +52,7 @@ impl<'t, 'j> From> for Cow<'j, str> { } } -impl<'t, 'j> StringOutput<'t, 'j> { +impl<'t> StringOutput<'t, '_> { pub fn as_str(&self) -> &'t str { match self { Self::Tape(s, _) => s, diff --git a/merde_json/src/lib.rs b/merde_json/src/lib.rs index ae41b1b..6269670 100644 --- a/merde_json/src/lib.rs +++ b/merde_json/src/lib.rs @@ -269,7 +269,7 @@ impl From for MerdeJsonError<'static> { } } -impl<'s> MerdeJsonError<'s> { +impl MerdeJsonError<'_> { /// Strip the 'source' field from the error, making it `'static` pub fn without_source(self) -> MerdeJsonError<'static> { match self { @@ -312,7 +312,7 @@ impl From for MerdeJsonError<'_> { } } -impl<'s> std::fmt::Display for MerdeJsonError<'s> { +impl std::fmt::Display for MerdeJsonError<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { MerdeJsonError::MerdeError(me) => write!(f, "Merde Error: {}", me), @@ -351,9 +351,9 @@ impl<'s> std::fmt::Display for MerdeJsonError<'s> { } } -impl<'s> std::error::Error for MerdeJsonError<'s> {} +impl std::error::Error for MerdeJsonError<'_> {} -impl<'s> std::fmt::Debug for MerdeJsonError<'s> { +impl std::fmt::Debug for MerdeJsonError<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self, f) }