diff --git a/.github/workflows/tests_impl.yml b/.github/workflows/tests_impl.yml index d3b1afd..4c413c2 100644 --- a/.github/workflows/tests_impl.yml +++ b/.github/workflows/tests_impl.yml @@ -60,7 +60,9 @@ jobs: with: tool: cargo-nextest - uses: actions/checkout@v4 - - run: RUSTFLAGS=" + - run: + MIRIFLAGS="-Zmiri-disable-isolation" + RUSTFLAGS=" ${{ inputs.rustflags }} --cfg ${{ inputs.cache_type_flag }} --cfg ${{ inputs.config_type_flag }} diff --git a/Cargo.toml b/Cargo.toml index 347d6d4..99248da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ arrayvec = { version = "0.7", optional = true } base64 = { version = "0.22", optional = true } [dev-dependencies] +anyhow = "1" +tempfile = "3" serde_json = "1.0" bincode = { version = "2.0", features = ["serde"] } rand = "0.8" diff --git a/miri_test_64.bat b/miri_test_64.bat new file mode 100644 index 0000000..749ef45 --- /dev/null +++ b/miri_test_64.bat @@ -0,0 +1,6 @@ +@echo off +setlocal +set MIRIFLAGS=-Zmiri-disable-isolation +set RUSTFLAGS=--cfg hisparsebitset_test_64 +cargo +nightly miri nextest run -j6 --all-features +endlocal \ No newline at end of file diff --git a/src/bitset/serde.rs b/src/bitset/serde.rs index 8ddaccb..c4e6023 100644 --- a/src/bitset/serde.rs +++ b/src/bitset/serde.rs @@ -1,7 +1,8 @@ +use std::fmt; +use std::fmt::Formatter; use std::io::Cursor; use std::marker::PhantomData; use serde::{Deserialize, Serialize}; -use serde::de::SeqAccess; use crate::{BitBlock, BitSet}; use crate::bitset::level::IBlock; use crate::config::Config; @@ -20,7 +21,7 @@ impl Serialize for BitSet{ // real_len <= approx_len let approx_len = - Conf::DataBitBlock::size() // root block + Conf::DataBitBlock::size() // root block + (1 + self.level0.mask().count_ones()) * Conf::Level1BitBlock::size() // lvl1 blocks + (1 + self.data.blocks().len()) * Conf::DataBitBlock::size(); // approx data blocks @@ -52,48 +53,35 @@ impl<'de, Conf: Config> Deserialize<'de> for BitSet{ where D: serde::Deserializer<'de> { + use serde::de::Error; + if deserializer.is_human_readable() { - use base64::{read::DecoderReader, engine::general_purpose::STANDARD}; - - let s: &str = <&str>::deserialize(deserializer)?; - let mut decoder = DecoderReader::new(Cursor::new(s), &STANDARD); - - BitSet::deserialize(&mut decoder).map_err(serde::de::Error::custom) + struct Visitor(PhantomData); + impl<'de, Conf: Config> serde::de::Visitor<'de> for Visitor { + type Value = BitSet; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a string") + } + + fn visit_str(self, v: &str) -> Result { + use base64::{read::DecoderReader, engine::general_purpose::STANDARD}; + let mut decoder = DecoderReader::new(Cursor::new(v), &STANDARD); + BitSet::deserialize(&mut decoder).map_err(Error::custom) + } + } + deserializer.deserialize_str(Visitor(PhantomData)) } else { struct Visitor(PhantomData); impl<'de, Conf: Config> serde::de::Visitor<'de> for Visitor { type Value = BitSet; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { formatter.write_str("a byte slice") } - fn visit_bytes(self, v: &[u8]) -> Result - where - E: serde::de::Error, - { - BitSet::deserialize(&mut Cursor::new(v)).map_err(serde::de::Error::custom) - } - - // Not in use now - bincode does not support deserialize_any - /// This is a fallback implementation for serializers that - /// lie in is_human_readable(). - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let mut v: Vec = - if let Some(len) = seq.size_hint() { - Vec::with_capacity(len) - } else { - Vec::new() - }; - - while let Some(byte) = seq.next_element::()? { - v.push(byte); - } - - BitSet::deserialize(&mut Cursor::new(v)).map_err(serde::de::Error::custom) + fn visit_bytes(self, v: &[u8]) -> Result { + BitSet::deserialize(&mut Cursor::new(v)).map_err(Error::custom) } } deserializer.deserialize_bytes(Visitor(PhantomData)) @@ -103,6 +91,7 @@ impl<'de, Conf: Config> Deserialize<'de> for BitSet{ #[cfg(test)] mod tests { + use std::io::Seek; use itertools::assert_equal; use crate::config; use super::*; @@ -141,4 +130,17 @@ mod tests { assert_eq!(bitset, deserialized_bitset); assert_equal(bitset.iter(), deserialized_bitset.iter()); // check by iter too. } + + #[test] + fn serde_json_w_file() -> anyhow::Result<()> { + type BitSet = crate::BitSet; + let set = BitSet::from_iter(0..260_000usize); + + let mut file = tempfile::tempfile()?; + serde_json::to_writer(&mut file, &set)?; + + file.rewind()?; + let _s: BitSet = serde_json::from_reader(file)?; + Ok(()) + } } \ No newline at end of file