diff --git a/savefile-test/build.rs b/savefile-test/build.rs index ff9d5a4..e0c8242 100644 --- a/savefile-test/build.rs +++ b/savefile-test/build.rs @@ -1,6 +1,13 @@ extern crate rustc_version; -use rustc_version::{version_meta, Channel}; +use rustc_version::{version, version_meta, Channel, Version}; fn main() { + println!("cargo:rustc-check-cfg=cfg(has_new_range)"); + // std::range::Range was stabilized in rust 1.96 + if let Ok(version) = version() { + if version >= Version::new(1, 96, 0) { + println!("cargo:rustc-cfg=has_new_range"); + } + } if version_meta().unwrap().channel == Channel::Nightly { println!("cargo:rustc-cfg=feature=\"nightly\""); } diff --git a/savefile-test/src/lib.rs b/savefile-test/src/lib.rs index e3f8e8b..62204df 100644 --- a/savefile-test/src/lib.rs +++ b/savefile-test/src/lib.rs @@ -134,6 +134,19 @@ pub fn roundtrip_version(sample: E, version: u32) -> assert_eq!(f.position() as usize, f_internal_size); roundtrip_result } +#[cfg(has_new_range)] +#[test] +pub fn test_new_range() { + assert_roundtrip(std::range::Range { start: 3u32, end: 7u32 }); + + // std::ops::Range and std::range::Range must be wire-compatible + let mut f = Cursor::new(Vec::new()); + Serializer::save(&mut f, 0, &(3u32..7u32), false).unwrap(); + f.set_position(0); + let new_range = Deserializer::load::>(&mut f, 0).unwrap(); + assert_eq!(new_range, std::range::Range { start: 3, end: 7 }); +} + #[derive(Debug, Savefile, PartialEq)] pub enum TestStructEnum { Variant1 { a: u8, b: u8 }, diff --git a/savefile/build.rs b/savefile/build.rs index 6aa53ff..c6e1a75 100644 --- a/savefile/build.rs +++ b/savefile/build.rs @@ -1,6 +1,15 @@ extern crate rustc_version; -use rustc_version::{version_meta, Channel}; +use rustc_version::{version, version_meta, Channel, Version}; fn main() { + println!("cargo:rustc-check-cfg=cfg(has_new_range)"); + + // std::range::Range was stabilized in rust 1.96 + if let Ok(version) = version() { + if version >= Version::new(1, 96, 0) { + println!("cargo:rustc-cfg=has_new_range"); + } + } + let version = version_meta().unwrap(); if version.channel == Channel::Nightly { println!("cargo:rustc-cfg=feature=\"nightly\""); diff --git a/savefile/src/lib.rs b/savefile/src/lib.rs index e724239..5193999 100644 --- a/savefile/src/lib.rs +++ b/savefile/src/lib.rs @@ -7274,6 +7274,49 @@ impl Introspect for Range { } } + +// std::range::Range requires rust 1.96 or later. Serialized format is +// identical to that of std::ops::Range, so the two are wire-compatible. +#[cfg(has_new_range)] +impl Packed for std::range::Range {} +#[cfg(has_new_range)] +impl WithSchema for std::range::Range { + fn schema(version: u32, context: &mut WithSchemaContext) -> Schema { + Schema::new_tuple2::(version, context) + } +} +#[cfg(has_new_range)] +impl Serialize for std::range::Range { + fn serialize(&self, serializer: &mut Serializer) -> Result<(), SavefileError> { + self.start.serialize(serializer)?; + self.end.serialize(serializer)?; + Ok(()) + } +} +#[cfg(has_new_range)] +impl Deserialize for std::range::Range { + fn deserialize(deserializer: &mut Deserializer) -> Result { + Ok((T1::deserialize(deserializer)?..T1::deserialize(deserializer)?).into()) + } +} +#[cfg(has_new_range)] +impl Introspect for std::range::Range { + fn introspect_value(&self) -> String { + return "Range".to_string(); + } + + fn introspect_child(&self, index: usize) -> Option + '_>> { + if index == 0 { + return Some(introspect_item("start".to_string(), &self.start)); + } + if index == 1 { + return Some(introspect_item("end".to_string(), &self.end)); + } + return None; + } +} + + impl Packed for (T1,) { unsafe fn repr_c_optimization_safe(version: u32) -> IsPacked { if offset_of_tuple!((T1,), 0) == 0 && std::mem::size_of::() == std::mem::size_of::<(T1,)>() {