Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance cross-version support #23

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

wllenyj
Copy link

@wllenyj wllenyj commented Apr 20, 2023

Reason for This PR

In production use, we usually have multiple release branches, each branch corresponding to a minor version. When we develop between versions, there may be changes to fields of struct. This brings a lot of complexity and maintenance cost to version control.

Description of Changes

  1. Introduce semver as a version of the structure. Instead of a u16.
  2. Add multi-version support.
  3. serialize now only supports the current version, i.e. the current version of the application can only take snapshots of the current version.
  4. See [WIP] Enhance cross-version support versionize#58 for changes of versionize.

Now writing a Versionize derive for a structure can look like this.

#[derive(Versionize)]                                        
struct TypeA {                                               
    a: u32,                                                  
    #[version(start = "2.7.7, 2.8.3", end = "2.7.11, 2.8.7")]
    b: u32,                                                  
    #[version(start = "2.7.9, 2.8.3", end = "2.7.11, 2.8.8")]
    c: u32,                                                  
    #[version(start = "2.8.11")]                             
    aaa: String,                                             
}                                                            

or enum:

#[derive(Versionize)]                                                     
enum EnumB {                                                              
    AAA(u32),                                                             
    #[version(start = "2.8.11", end = "2.8.22", default_fn = "def_BBB")]
    BBB(String),                                                        
}

Advantages:

  • Now all dependencies of the open-source version are released separately to the crate. So the version of each structure is associated with the crate version. This makes it easier for the crate to test the compatibility of the crate version itself, instead of integrating it into applications and testing the compatibility afterward. Here TypeA's v2.7.7 represents the crate version of TypeA.
  • In theory, all versions of ser/der are compatible.

The code generated by the above example:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use dbs_versionize::{Version, Versionize};
struct TypeA {
    a: u32,
    #[version(start = "2.7.7, 2.8.3", end = "2.7.11, 2.8.7")]
    b: u32,
    #[version(start = "2.7.9, 2.8.3", end = "2.7.11, 2.8.8")]
    c: u32,
    #[version(start = "2.8.11")]
    aaa: String,
}
impl Versionize for TypeA {
    fn serialize<W: std::io::Write>(
        &self,
        mut writer: W,
        version_map: &mut VersionMap,
    ) -> VersionizeResult<()> {
        let current = version_map.set_crate_version("version_test", "0.1.0")?;
        let mut copy_of_self = self.clone();
        Versionize::serialize(&copy_of_self.a, &mut writer, version_map)?;
        Versionize::serialize(&copy_of_self.aaa, &mut writer, version_map)?;
        Ok(())
    }
    fn deserialize<R: std::io::Read>(
        mut reader: R,
        version_map: &VersionMap,
    ) -> VersionizeResult<Self> {
        let source = version_map.get_crate_version("version_test")?;
        match (source.minor, source.patch) {
            (0..=6u64, _) => {
                let mut object = TypeA {
                    a: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    b: Default::default(),
                    c: Default::default(),
                    aaa: Default::default(),
                };
                Ok(object)
            }
            (7u64, 0u64..=6u64) => {
                let mut object = TypeA {
                    a: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    b: Default::default(),
                    c: Default::default(),
                    aaa: Default::default(),
                };
                Ok(object)
            }
            (7u64, 7u64..=8u64) => {
                let mut object = TypeA {
                    a: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    b: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    c: Default::default(),
                    aaa: Default::default(),
                };
                Ok(object)
            }
            (7u64, 9u64..=10u64) => {
                let mut object = TypeA {
                    a: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    b: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    c: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    aaa: Default::default(),
                };
                Ok(object)
            }
            (7u64, 11u64..) => {
                let mut object = TypeA {
                    a: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    b: Default::default(),
                    c: Default::default(),
                    aaa: Default::default(),
                };
                Ok(object)
            }
            (8u64, 0u64..=2u64) => {
                let mut object = TypeA {
                    a: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    b: Default::default(),
                    c: Default::default(),
                    aaa: Default::default(),
                };
                Ok(object)
            }
            (8u64, 3u64..=6u64) => {
                let mut object = TypeA {
                    a: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    b: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    c: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    aaa: Default::default(),
                };
                Ok(object)
            }
            (8u64, 7u64..=7u64) => {
                let mut object = TypeA {
                    a: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    b: Default::default(),
                    c: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    aaa: Default::default(),
                };
                Ok(object)
            }
            (8u64, 8u64..=10u64) => {
                let mut object = TypeA {
                    a: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    b: Default::default(),
                    c: Default::default(),
                    aaa: Default::default(),
                };
                Ok(object)
            }
            (8u64, 11u64..) => {
                let mut object = TypeA {
                    a: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    b: Default::default(),
                    c: Default::default(),
                    aaa: <String as Versionize>::deserialize(
                        &mut reader,
                        version_map,
                    )?,
                };
                Ok(object)
            }
            (9u64.., _) => {
                let mut object = TypeA {
                    a: <u32 as Versionize>::deserialize(&mut reader, version_map)?,
                    b: Default::default(),
                    c: Default::default(),
                    aaa: <String as Versionize>::deserialize(
                        &mut reader,
                        version_map,
                    )?,
                };
                Ok(object)
            }
        }
    }
}
enum EnumB {
    AAA(u32),
    #[version(start = "2.8.11", end = "2.8.22", default_fn = "def_BBB")]
    BBB(String),
}
impl Versionize for EnumB {
    fn serialize<W: std::io::Write>(
        &self,
        mut writer: W,
        version_map: &mut VersionMap,
    ) ->VersionizeResult<()> {
        let current = version_map.set_crate_version("version_test", "0.1.0")?;
        let mut copy_of_self = self.clone();
        match self {
            Self::AAA(data_0) => {
                let index: u32 = 0u32;
                Versionize::serialize(&index, &mut writer, version_map)?;
                Versionize::serialize(data_0, &mut writer, version_map)?;
            }
            Self::BBB(..) => {
                let new_variant = self.def_BBB(current)?;
                new_variant.serialize(&mut writer, version_map)?;
            }
        }
        Ok(())
    }
    fn deserialize<R: std::io::Read>(
        mut reader: R,
        version_map: &VersionMap,
    ) -> VersionizeResult<Self> {
        let source = version_map.get_crate_version("version_test")?;
        let variant_index =
            <u32 as Versionize>::deserialize(&mut reader, version_map)?;
        match variant_index {
            0u32 => {
                let data_0 =
                    <u32 as Versionize>::deserialize(&mut reader, version_map)?;
                return Ok(Self::AAA(data_0));
            }
            1u32 => {
                let data_0 =
                    <String as Versionize>::deserialize(&mut reader, version_map)?;
                return Ok(Self::BBB(data_0));
            }
            x => {
                return Err(VersionizeError::Deserialize({
                    let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1(
                        &["Unknown variant_index "],
                        &[::core::fmt::ArgumentV1::new_display(&x)],
                    ));
                    res
                }))
            }
        }
    }
}
impl EnumB {
    fn def_BBB(&self, src: Version) -> String {
        String::new()
    }
}

License Acceptance

By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache 2.0 license.

PR Checklist

[Author TODO: Meet these criteria.]
[Reviewer TODO: Verify that these criteria are met. Request changes if not]

  • All commits in this PR are signed (git commit -s).
  • The reason for this PR is clearly provided (issue no. or explanation).
  • The description of changes is clear and encompassing.
  • Any required documentation changes (code and docs) are included in this PR.
  • Any newly added unsafe code is properly documented.
  • Any user-facing changes are mentioned in CHANGELOG.md.

In production use, we usually have multiple release branches, each
branch corresponding to a minor version. When we develop between
versions, there may be changes to fields of struct. This brings a
lot of complexity and maintenance cost to version control.

Signed-off-by: wanglei01 <[email protected]>
@wllenyj wllenyj changed the title introduce cross-version support Enhance cross-version support May 19, 2023
wllenyj added a commit to wllenyj/dragonball-sandbox that referenced this pull request May 21, 2023
Since our PR
(firecracker-microvm/versionize_derive#23) can't
be merged into upstream for a short time, here we fork it first.
After the upstream is merged, switch to the upstream dependency.

Signed-off-by: wllenyj <[email protected]>
wllenyj added a commit to wllenyj/dragonball-sandbox that referenced this pull request May 21, 2023
fork https://github.com/firecracker-microvm/versionize_derive.git

Since our PR
(firecracker-microvm/versionize_derive#23) can't
be merged into upstream for a short time, here we fork it first.
After the upstream is merged, switch to the upstream dependency.

Signed-off-by: wllenyj <[email protected]>
wllenyj added a commit to wllenyj/dragonball-sandbox that referenced this pull request May 24, 2023
fork https://github.com/firecracker-microvm/versionize_derive.git

Since our PR
(firecracker-microvm/versionize_derive#23) can't
be merged into upstream for a short time, here we fork it first.
After the upstream is merged, switch to the upstream dependency.

Signed-off-by: wllenyj <[email protected]>
wllenyj added a commit to wllenyj/dragonball-sandbox that referenced this pull request May 29, 2023
Since our PR
(firecracker-microvm/versionize_derive#23) can't
be merged into upstream for a short time, here we fork it first.
After the upstream is merged, switch to the upstream dependency.

Signed-off-by: wllenyj <[email protected]>
wllenyj added a commit to wllenyj/dragonball-sandbox that referenced this pull request May 29, 2023
fork https://github.com/firecracker-microvm/versionize_derive.git

Since our PR
(firecracker-microvm/versionize_derive#23) can't
be merged into upstream for a short time, here we fork it first.
After the upstream is merged, switch to the upstream dependency.

Signed-off-by: wllenyj <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant