};
use enum_map::{enum_map, EnumMap};
use num_bigint::BigUint;
-use num_traits::Zero;
+use num_traits::{Num, Zero};
use once_cell::race::OnceBox;
-use serde::{Deserialize, Serialize};
+use serde::{de, Deserialize, Serialize};
use std::{
- borrow::Borrow,
+ borrow::{Borrow, Cow},
cell::Cell,
collections::{
btree_map::{self, Entry},
)
}
-#[derive(Deserialize)]
-struct LocSetSerialized {
- starts_map: BTreeMap<NonZeroU32, EnumMap<LocKind, BigUint>>,
+#[derive(Debug, Clone)]
+struct BigUintAsHexString<'a>(Cow<'a, BigUint>);
+
+impl<'de, 'a> Deserialize<'de> for BigUintAsHexString<'a> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ let text = String::deserialize(deserializer)?;
+ if let Some(text) = text.strip_prefix("0x") {
+ Ok(Self(Cow::Owned(
+ BigUint::from_str_radix(text, 0x10).map_err(<D::Error as de::Error>::custom)?,
+ )))
+ } else {
+ Err(<D::Error as de::Error>::custom(
+ "expected hex string to start with `0x`",
+ ))
+ }
+ }
+}
+
+impl Serialize for BigUintAsHexString<'_> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ format!("{:#x}", &*self.0).serialize(serializer)
+ }
+}
+
+#[derive(Deserialize, Serialize)]
+struct LocSetSerialized<'a> {
+ starts_map: BTreeMap<NonZeroU32, BTreeMap<LocKind, BigUintAsHexString<'a>>>,
}
-impl TryFrom<LocSetSerialized> for LocSet {
+impl TryFrom<LocSetSerialized<'_>> for LocSet {
type Error = Error;
fn try_from(value: LocSetSerialized) -> Result<Self, Self::Error> {
- Self::from_starts_map(value.starts_map)
+ Self::from_starts_map(
+ value
+ .starts_map
+ .into_iter()
+ .map(|(k, mut v)| {
+ let v = enum_map! {
+ k => v.remove(&k).map_or_else(BigUint::zero, |v| v.0.into_owned())
+ };
+ (k, v)
+ })
+ .collect(),
+ )
}
}
-#[derive(Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[derive(Clone, Default, PartialEq, Eq, Hash, Deserialize)]
#[serde(try_from = "LocSetSerialized")]
pub struct LocSet {
starts_map: BTreeMap<NonZeroU32, EnumMap<LocKind, BigUint>>,
}
+impl Serialize for LocSet {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ LocSetSerialized {
+ starts_map: self
+ .starts_map
+ .iter()
+ .map(|(&k, v)| {
+ let v = v
+ .iter()
+ .map(|(k, v)| (k, BigUintAsHexString(Cow::Borrowed(v))))
+ .collect::<BTreeMap<_, _>>();
+ (k, v)
+ })
+ .collect(),
+ }
+ .serialize(serializer)
+ }
+}
+
impl<'a> arbitrary::Arbitrary<'a> for LocSet {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
u.arbitrary_iter()?.collect()