Skip to content

Commit

Permalink
Merge pull request #1055 from dtolnay/boolkey
Browse files Browse the repository at this point in the history
Support bool in map keys
  • Loading branch information
dtolnay authored Aug 15, 2023
2 parents 8652bf2 + 9b69f16 commit 59d9f96
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 18 deletions.
37 changes: 36 additions & 1 deletion src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2203,6 +2203,41 @@ where
deserialize_numeric_key!(deserialize_f32, deserialize_f32);
deserialize_numeric_key!(deserialize_f64);

fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
where
V: de::Visitor<'de>,
{
self.de.eat_char();

let peek = match tri!(self.de.next_char()) {
Some(b) => b,
None => {
return Err(self.de.peek_error(ErrorCode::EofWhileParsingValue));
}
};

let value = match peek {
b't' => {
tri!(self.de.parse_ident(b"rue\""));
visitor.visit_bool(true)
}
b'f' => {
tri!(self.de.parse_ident(b"alse\""));
visitor.visit_bool(false)
}
_ => {
self.de.scratch.clear();
let s = tri!(self.de.read.parse_str(&mut self.de.scratch));
Err(de::Error::invalid_type(Unexpected::Str(&s), &visitor))
}
};

match value {
Ok(value) => Ok(value),
Err(err) => Err(self.de.fix_position(err)),
}
}

#[inline]
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
where
Expand Down Expand Up @@ -2258,7 +2293,7 @@ where
}

forward_to_deserialize_any! {
bool char str string unit unit_struct seq tuple tuple_struct map struct
char str string unit unit_struct seq tuple tuple_struct map struct
identifier ignored_any
}
}
Expand Down
17 changes: 15 additions & 2 deletions src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -827,8 +827,21 @@ where
type SerializeStruct = Impossible<(), Error>;
type SerializeStructVariant = Impossible<(), Error>;

fn serialize_bool(self, _value: bool) -> Result<()> {
Err(key_must_be_a_string())
fn serialize_bool(self, value: bool) -> Result<()> {
tri!(self
.ser
.formatter
.begin_string(&mut self.ser.writer)
.map_err(Error::io));
tri!(self
.ser
.formatter
.write_bool(&mut self.ser.writer, value)
.map_err(Error::io));
self.ser
.formatter
.end_string(&mut self.ser.writer)
.map_err(Error::io)
}

fn serialize_i8(self, value: i8) -> Result<()> {
Expand Down
20 changes: 18 additions & 2 deletions src/value/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,22 @@ impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> {
deserialize_numeric_key!(deserialize_i128, do_deserialize_i128);
deserialize_numeric_key!(deserialize_u128, do_deserialize_u128);

fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Error>
where
V: Visitor<'de>,
{
if self.key == "true" {
visitor.visit_bool(true)
} else if self.key == "false" {
visitor.visit_bool(false)
} else {
Err(serde::de::Error::invalid_type(
Unexpected::Str(&self.key),
&visitor,
))
}
}

#[inline]
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
where
Expand Down Expand Up @@ -1219,8 +1235,8 @@ impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> {
}

forward_to_deserialize_any! {
bool char str string bytes byte_buf unit unit_struct seq tuple
tuple_struct map struct identifier ignored_any
char str string bytes byte_buf unit unit_struct seq tuple tuple_struct
map struct identifier ignored_any
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/value/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,8 +483,8 @@ impl serde::Serializer for MapKeySerializer {
value.serialize(self)
}

fn serialize_bool(self, _value: bool) -> Result<String> {
Err(key_must_be_a_string())
fn serialize_bool(self, value: bool) -> Result<String> {
Ok(value.to_string())
}

fn serialize_i8(self, value: i8) -> Result<String> {
Expand Down
19 changes: 8 additions & 11 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1654,17 +1654,6 @@ fn test_deserialize_from_stream() {
assert_eq!(request, response);
}

#[test]
fn test_serialize_rejects_bool_keys() {
let map = treemap!(
true => 2,
false => 4,
);

let err = to_vec(&map).unwrap_err();
assert_eq!(err.to_string(), "key must be a string");
}

#[test]
fn test_serialize_rejects_adt_keys() {
let map = treemap!(
Expand Down Expand Up @@ -2018,6 +2007,14 @@ fn test_deny_non_finite_f64_key() {
assert!(serde_json::to_value(map).is_err());
}

#[test]
fn test_boolean_key() {
let map = treemap!(false => 0, true => 1);
let j = r#"{"false":0,"true":1}"#;
test_encode_ok(&[(&map, j)]);
test_parse_ok(vec![(j, map)]);
}

#[test]
fn test_borrowed_key() {
let map: BTreeMap<&str, ()> = from_str("{\"borrowed\":null}").unwrap();
Expand Down

0 comments on commit 59d9f96

Please sign in to comment.