Skip to content

Commit

Permalink
Added Compatibility + deserialize_any fix
Browse files Browse the repository at this point in the history
Closes #11

This set of changes adds new compatibility options that ensure no
breaking changes in v3.0, but allow users to opt into the new format
change that will become default in v4.0.

The issue that this new format change fixes is that an enum variant with
associated data and an enum variant with no assicated data were both
encoded using a `named` atom. In `deserialize_any` we have no way to
know whether the next atom after the name is actually data associated
with the enum variant or if it's the next value in the stream.

The new format encodes enum variants with no associated data as a symbol
atom only. Parsers before v3.0.1 will not be able to read this change.
  • Loading branch information
ecton committed Aug 11, 2024
1 parent 9dbf59c commit 4554256
Show file tree
Hide file tree
Showing 6 changed files with 897 additions and 785 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Added

- `Compatibility` is a new enum that controls compatibility of serialization and
deserialization. `Compatibility::Full` is the default compatibility level in
`v3.x`, and it serializes data in a way that even Pot `v1.0` deserializers can
deserialize.

`Compatibility::V4` is a new serialization format that serializes enum
variants without associated data in a way that allows `Value` deserialization
to be done unambiguously. See [#11][11] for an example of this issue. This bug
only affected `deserialize_any`-type deserialization. Typical deserialization
works correctly.

Compatibility can be configured using these new APIs:

- `Config::compatibility`
- `Serializer::new_with_compatibility`
- `SymbolMap::with_compatibility`
- `SymbolMap::set_compatibility`

[11]: https://github.com/khonsulabs/pot/issues/11


## 3.0.0

### Breaking Changes
Expand Down
22 changes: 14 additions & 8 deletions pot/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl<'s, 'de, R: Reader<'de>> Deserializer<'s, 'de, R> {

fn read_header(&mut self) -> Result<()> {
let version = format::read_header(&mut self.input)?;
if version == CURRENT_VERSION {
if version <= CURRENT_VERSION {
Ok(())
} else {
Err(Error::IncompatibleVersion)
Expand Down Expand Up @@ -996,15 +996,21 @@ impl<'a, 's, 'de, R: Reader<'de>> EnumAccess<'de> for &'a mut Deserializer<'s, '
V: DeserializeSeed<'de>,
{
// Have the seed deserialize the next atom, which should be the symbol.
let atom = self.read_atom()?;
if atom.kind == Kind::Special && matches!(atom.nucleus, Some(Nucleus::Named)) {
let val = seed.deserialize(&mut *self)?;
Ok((val, self))
} else {
Err(Error::custom(format!(
let atom = self.peek_atom()?;
match atom.kind {
Kind::Special if matches!(atom.nucleus, Some(Nucleus::Named)) => {
self.read_atom()?;
let val = seed.deserialize(&mut *self)?;
Ok((val, self))
}
Kind::Symbol => {
let val = seed.deserialize(&mut *self)?;
Ok((val, self))
}
_ => Err(Error::custom(format!(
"expected Named, got {:?}",
atom.kind
)))
))),
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion pot/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use std::fmt::Display;
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
use half::f16;

pub(crate) const CURRENT_VERSION: u8 = 0;
pub(crate) const INITIAL_VERSION: u8 = 0;
pub(crate) const V4_VERSION: u8 = 1;
pub(crate) const CURRENT_VERSION: u8 = V4_VERSION;

use crate::reader::{BufferedBytes, Reader};
use crate::Error;
Expand Down
Loading

0 comments on commit 4554256

Please sign in to comment.