diff --git a/Cargo.lock b/Cargo.lock index 4eb15d6..9c49412 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,7 +103,7 @@ dependencies = [ [[package]] name = "axum_duper" -version = "0.1.2" +version = "0.2.0" dependencies = [ "axum", "serde", @@ -308,7 +308,7 @@ dependencies = [ [[package]] name = "duper" -version = "0.1.1" +version = "0.2.0" dependencies = [ "insta", "miette", @@ -316,13 +316,12 @@ dependencies = [ "pest", "pest_derive", "ryu", - "serde_core", "unicode-general-category", ] [[package]] name = "duper-python" -version = "0.1.2" +version = "0.2.0" dependencies = [ "duper", "miette", @@ -1077,7 +1076,7 @@ dependencies = [ [[package]] name = "serde_duper" -version = "0.1.2" +version = "0.2.0" dependencies = [ "bytes", "chrono", diff --git a/axum_duper/CHANGELOG.md b/axum_duper/CHANGELOG.md index 395733c..7092c18 100644 --- a/axum_duper/CHANGELOG.md +++ b/axum_duper/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.2.0 (2025-10-23) + +### Changed + +- Bump `serde_duper` to 0.2.0. + ## 0.1.2 (2025-10-22) ### Changed @@ -10,7 +16,7 @@ ### Changed -- Update `serde_duper` to 0.1.1. +- Bump `serde_duper` to 0.1.1. - Update README. ## 0.1.0 (2025-10-20) diff --git a/axum_duper/Cargo.toml b/axum_duper/Cargo.toml index b46ed46..97ebbbf 100644 --- a/axum_duper/Cargo.toml +++ b/axum_duper/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "axum_duper" description = "Axum extractor/response for Duper." -version = "0.1.2" +version = "0.2.0" edition = "2024" rust-version = "1.88" license = "MIT" @@ -15,7 +15,7 @@ keywords = ["duper", "serde", "axum"] [dependencies] axum = { version = "0.8", default-features = false } serde_core = "1" -serde_duper = { path = "../serde_duper", version = "0.1.2" } +serde_duper = { path = "../serde_duper", version = "0.2.0" } [dev-dependencies] serde = { version = "1.0.228", features = ["derive"] } diff --git a/duper-python/CHANGELOG.md b/duper-python/CHANGELOG.md index 369e813..7b16a7a 100644 --- a/duper-python/CHANGELOG.md +++ b/duper-python/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 0.2.0 (2025-10-23) + +### Added + +- Add Pydantic v2 as a dependency. +- Support Pydantic network types and `pydantic-extra-types` for serialization. +- `Duper` annotation to control identifiers in Pydantic. + +### Changed + +- Bump `duper` to 0.2.0. +- `load` / `loads` will output an anonymous `duper.BaseModel` for objects. + ## 0.1.2 (2025-10-22) ### Changed @@ -10,7 +23,7 @@ ### Changed -- Update `duper` to 0.1.1. +- Bump `duper` to 0.1.1. - Update README. - Update package information. diff --git a/duper-python/Cargo.toml b/duper-python/Cargo.toml index 07c2b46..3b9b222 100644 --- a/duper-python/Cargo.toml +++ b/duper-python/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "duper-python" description = "The format that's super!" -version = "0.1.2" +version = "0.2.0" edition = "2024" rust-version = "1.88" license = "MIT" @@ -18,7 +18,7 @@ name = "_duper" crate-type = ["cdylib"] [dependencies] -duper = { path = "../duper", version = "0.1.1" } +duper = { path = "../duper", version = "0.2.0" } miette = "7.6.0" pyo3 = { version = "0.27.1", features = [ "extension-module", diff --git a/duper-python/pyproject.toml b/duper-python/pyproject.toml index cb3df30..a93fc2e 100644 --- a/duper-python/pyproject.toml +++ b/duper-python/pyproject.toml @@ -16,9 +16,13 @@ classifiers = [ "Framework :: Pydantic", "Framework :: Pydantic :: 2", ] -urls = { homepage = "https://github.com/EpicEric/duper", source = "https://github.com/EpicEric/duper" } dependencies = ["pydantic>=2,<3"] +[project.urls] +homepage = "https://github.com/EpicEric/duper" +source = "https://github.com/EpicEric/duper" +changelog = "https://github.com/EpicEric/duper/blob/main/duper-python/CHANGELOG.md" + [build-system] requires = ["maturin>=1.9,<2.0"] build-backend = "maturin" diff --git a/duper-vs-code/CHANGELOG.md b/duper-vs-code/CHANGELOG.md index 42abb44..45c30be 100644 --- a/duper-vs-code/CHANGELOG.md +++ b/duper-vs-code/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.2.0 (2025-10-23) + +### Changed + +- Implement changes from specification 0.2.0. + ## 0.1.2 (2025-10-22) ### Fixed diff --git a/duper-vs-code/package.json b/duper-vs-code/package.json index 59f699e..a87d846 100644 --- a/duper-vs-code/package.json +++ b/duper-vs-code/package.json @@ -2,7 +2,7 @@ "name": "duper-vs-code", "displayName": "Duper", "description": "Duper support for Visual Studio Code", - "version": "0.1.2", + "version": "0.2.0", "engines": { "vscode": "^1.105.0" }, diff --git a/duper/CHANGELOG.md b/duper/CHANGELOG.md index 311b4b8..9c3a74a 100644 --- a/duper/CHANGELOG.md +++ b/duper/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 0.2.0 (2025-10-23) + +### Changed + +- Implement changes from specification 0.2.0. + +### Fixed + +- Fix bug when parsing identifiers with underscores or hyphens. + +### Removed + +- Unused `serde` feature. + ## 0.1.1 (2025-10-22) ### Changed diff --git a/duper/Cargo.toml b/duper/Cargo.toml index 6781036..c2b6879 100644 --- a/duper/Cargo.toml +++ b/duper/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "duper" description = "The format that's super!" -version = "0.1.1" +version = "0.2.0" edition = "2024" rust-version = "1.88" license = "MIT" @@ -15,14 +15,12 @@ keywords = ["duper", "parser", "serialization"] [features] default = [] ansi = ["dep:owo-colors"] -serde = ["dep:serde_core"] [dependencies] owo-colors = { version = "4.2.3", optional = true } pest = { version = "2.8.3", features = ["miette-error"] } pest_derive = "2.8.3" ryu = "1.0.20" -serde_core = { version = "1", optional = true } unicode-general-category = "1.1.0" [dev-dependencies] diff --git a/duper/src/lib.rs b/duper/src/lib.rs index 692c144..14703f7 100644 --- a/duper/src/lib.rs +++ b/duper/src/lib.rs @@ -42,8 +42,6 @@ mod builder; mod escape; mod format; mod parser; -#[cfg(feature = "serde")] -mod serde; pub mod visitor; pub use ast::{ diff --git a/duper/src/serde.rs b/duper/src/serde.rs deleted file mode 100644 index 3e13111..0000000 --- a/duper/src/serde.rs +++ /dev/null @@ -1,380 +0,0 @@ -use crate::{ - DuperArray, DuperBytes, DuperIdentifier, DuperInner, DuperKey, DuperObject, DuperString, - DuperTuple, DuperValue, -}; -use serde_core::de::{VariantAccess, Visitor}; -use std::borrow::Cow; - -struct DuperValueDeserializerVisitor; - -impl<'a> serde_core::Serialize for DuperValue<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: serde_core::Serializer, - { - self.inner.serialize(serializer) - } -} - -impl<'a> serde_core::Serialize for DuperInner<'a> { - fn serialize(&self, serializer: S) -> Result - where - S: serde_core::Serializer, - { - match self { - DuperInner::Object(object) => { - use serde_core::ser::SerializeMap; - let mut map = serializer.serialize_map(Some(object.len()))?; - for (key, value) in object.iter() { - map.serialize_entry(key.as_ref(), value)?; - } - map.end() - } - DuperInner::Array(array) => { - use serde_core::ser::SerializeSeq; - let mut seq = serializer.serialize_seq(Some(array.len()))?; - for value in array.iter() { - seq.serialize_element(value)?; - } - seq.end() - } - DuperInner::Tuple(tuple) => { - use serde_core::ser::SerializeTuple; - let mut seq = serializer.serialize_tuple(tuple.len())?; - for value in tuple.iter() { - seq.serialize_element(value)?; - } - seq.end() - } - DuperInner::String(string) => serializer.serialize_str(string.as_ref()), - DuperInner::Bytes(bytes) => serializer.serialize_bytes(bytes.as_ref()), - DuperInner::Integer(integer) => serializer.serialize_i64(*integer), - DuperInner::Float(float) => serializer.serialize_f64(*float), - DuperInner::Boolean(boolean) => serializer.serialize_bool(*boolean), - DuperInner::Null => serializer.serialize_none(), - } - } -} - -impl<'de> Visitor<'de> for DuperValueDeserializerVisitor { - type Value = DuperValue<'de>; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a valid Duper value") - } - - fn visit_bool(self, v: bool) -> Result - where - E: serde_core::de::Error, - { - Ok(DuperValue { - identifier: None, - inner: DuperInner::Boolean(v), - }) - } - - fn visit_i8(self, v: i8) -> Result - where - E: serde_core::de::Error, - { - self.visit_i64(v as i64) - } - - fn visit_i16(self, v: i16) -> Result - where - E: serde_core::de::Error, - { - self.visit_i64(v as i64) - } - - fn visit_i32(self, v: i32) -> Result - where - E: serde_core::de::Error, - { - self.visit_i64(v as i64) - } - - fn visit_i64(self, v: i64) -> Result - where - E: serde_core::de::Error, - { - Ok(DuperValue { - identifier: None, - inner: DuperInner::Integer(v), - }) - } - - fn visit_i128(self, v: i128) -> Result - where - E: serde_core::de::Error, - { - if let Ok(i) = v.try_into() { - self.visit_i64(i) - } else if let float = v as f64 - && float as i128 == v - { - Ok(DuperValue { - identifier: Some( - DuperIdentifier::try_from(Cow::Borrowed("I128")).expect("valid identifier"), - ), - inner: DuperInner::Float(float), - }) - } else { - Ok(DuperValue { - identifier: Some( - DuperIdentifier::try_from(Cow::Borrowed("I128")).expect("valid identifier"), - ), - inner: DuperInner::String(DuperString::from(Cow::Owned(v.to_string()))), - }) - } - } - - fn visit_u8(self, v: u8) -> Result - where - E: serde_core::de::Error, - { - self.visit_i64(v as i64) - } - - fn visit_u16(self, v: u16) -> Result - where - E: serde_core::de::Error, - { - self.visit_i64(v as i64) - } - - fn visit_u32(self, v: u32) -> Result - where - E: serde_core::de::Error, - { - self.visit_i64(v as i64) - } - - fn visit_u64(self, v: u64) -> Result - where - E: serde_core::de::Error, - { - if let Ok(i) = v.try_into() { - self.visit_i64(i) - } else if let float = v as f64 - && float as u64 == v - { - Ok(DuperValue { - identifier: Some( - DuperIdentifier::try_from(Cow::Borrowed("U64")).expect("valid identifier"), - ), - inner: DuperInner::Float(float), - }) - } else { - Ok(DuperValue { - identifier: Some( - DuperIdentifier::try_from(Cow::Borrowed("U64")).expect("valid identifier"), - ), - inner: DuperInner::String(DuperString::from(Cow::Owned(v.to_string()))), - }) - } - } - - fn visit_u128(self, v: u128) -> Result - where - E: serde_core::de::Error, - { - if let Ok(i) = v.try_into() { - self.visit_i64(i) - } else if let float = v as f64 - && float as u128 == v - { - Ok(DuperValue { - identifier: Some( - DuperIdentifier::try_from(Cow::Borrowed("U128")).expect("valid identifier"), - ), - inner: DuperInner::Float(float), - }) - } else { - Ok(DuperValue { - identifier: Some( - DuperIdentifier::try_from(Cow::Borrowed("U128")).expect("valid identifier"), - ), - inner: DuperInner::String(DuperString::from(Cow::Owned(v.to_string()))), - }) - } - } - - fn visit_f32(self, v: f32) -> Result - where - E: serde_core::de::Error, - { - self.visit_f64(v as f64) - } - - fn visit_f64(self, v: f64) -> Result - where - E: serde_core::de::Error, - { - Ok(DuperValue { - identifier: None, - inner: DuperInner::Float(v), - }) - } - - fn visit_char(self, v: char) -> Result - where - E: serde_core::de::Error, - { - self.visit_str(&v.to_string()) - } - - fn visit_str(self, v: &str) -> Result - where - E: serde_core::de::Error, - { - self.visit_string(v.to_string()) - } - - fn visit_borrowed_str(self, v: &'de str) -> Result - where - E: serde_core::de::Error, - { - Ok(DuperValue { - identifier: None, - inner: DuperInner::String(DuperString::from(Cow::Borrowed(v))), - }) - } - - fn visit_string(self, v: String) -> Result - where - E: serde_core::de::Error, - { - Ok(DuperValue { - identifier: None, - inner: DuperInner::String(DuperString::from(Cow::Owned(v))), - }) - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: serde_core::de::Error, - { - self.visit_byte_buf(v.to_vec()) - } - - fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result - where - E: serde_core::de::Error, - { - Ok(DuperValue { - identifier: None, - inner: DuperInner::Bytes(DuperBytes::from(Cow::Borrowed(v))), - }) - } - - fn visit_byte_buf(self, v: Vec) -> Result - where - E: serde_core::de::Error, - { - Ok(DuperValue { - identifier: None, - inner: DuperInner::Bytes(DuperBytes::from(Cow::Owned(v))), - }) - } - - fn visit_none(self) -> Result - where - E: serde_core::de::Error, - { - Ok(DuperValue { - identifier: None, - inner: DuperInner::Null, - }) - } - - fn visit_some(self, deserializer: D) -> Result - where - D: serde_core::Deserializer<'de>, - { - serde_core::Deserialize::deserialize(deserializer) - } - - fn visit_unit(self) -> Result - where - E: serde_core::de::Error, - { - Ok(DuperValue { - identifier: None, - inner: DuperInner::Tuple(DuperTuple::from(Vec::new())), - }) - } - - fn visit_newtype_struct(self, deserializer: D) -> Result - where - D: serde_core::Deserializer<'de>, - { - deserializer.deserialize_any(Self) - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: serde_core::de::SeqAccess<'de>, - { - let mut values = seq.size_hint().map(Vec::with_capacity).unwrap_or_default(); - - while let Some(value) = seq.next_element()? { - values.push(value); - } - - Ok(DuperValue { - identifier: None, - inner: DuperInner::Array(DuperArray::from(values)), - }) - } - - fn visit_map(self, mut map: A) -> Result - where - A: serde_core::de::MapAccess<'de>, - { - let mut entries = map.size_hint().map(Vec::with_capacity).unwrap_or_default(); - - while let Some((key, value)) = map.next_entry()? { - entries.push((DuperKey::from(Cow::Owned(key)), value)); - } - - Ok(DuperValue { - identifier: None, - inner: DuperInner::Object( - DuperObject::try_from(entries).expect("no duplicate entries in map"), - ), - }) - } - - fn visit_enum(self, data: A) -> Result - where - A: serde_core::de::EnumAccess<'de>, - { - let (identifier, value) = data.variant::()?; - Ok(DuperValue { - identifier: Some( - DuperIdentifier::try_from_lossy(Cow::Owned(identifier)) - .map_err(|error| serde_core::de::Error::custom(error.to_string()))?, - ), - inner: value.newtype_variant()?, - }) - } -} - -impl<'de> serde_core::Deserialize<'de> for DuperValue<'de> { - fn deserialize(deserializer: D) -> Result - where - D: serde_core::Deserializer<'de>, - { - deserializer.deserialize_any(DuperValueDeserializerVisitor) - } -} - -impl<'de> serde_core::Deserialize<'de> for DuperInner<'de> { - fn deserialize(deserializer: D) -> Result - where - D: serde_core::Deserializer<'de>, - { - Ok(DuperValue::deserialize(deserializer)?.inner) - } -} diff --git a/serde_duper/CHANGELOG.md b/serde_duper/CHANGELOG.md index d0dc99d..4fa2041 100644 --- a/serde_duper/CHANGELOG.md +++ b/serde_duper/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.2.0 (2025-10-23) + +- Bump `duper` to 0.2.0. + ## 0.1.2 (2025-10-22) ### Changed @@ -10,7 +14,7 @@ ### Changed -- Update `duper` to 0.1.1. +- Bump `duper` to 0.1.1. - Update README. ## 0.1.0 (2025-10-20) diff --git a/serde_duper/Cargo.toml b/serde_duper/Cargo.toml index eb0cde2..ef2e86f 100644 --- a/serde_duper/Cargo.toml +++ b/serde_duper/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "serde_duper" description = "Serde support for Duper." -version = "0.1.2" +version = "0.2.0" edition = "2024" rust-version = "1.88" license = "MIT" @@ -28,7 +28,7 @@ uuid = ["dep:uuid"] [dependencies] # Core dependencies -duper = { path = "../duper", version = "0.1.1", features = ["serde"] } +duper = { path = "../duper", version = "0.2.0" } miette = "7.6.0" pest = "2.8.3" serde_bytes = "0.11"