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

A way to use VersionOf and AnyVersion given reference to a struct #10

Open
iilyak opened this issue Aug 1, 2023 · 2 comments
Open

A way to use VersionOf and AnyVersion given reference to a struct #10

iilyak opened this issue Aug 1, 2023 · 2 comments

Comments

@iilyak
Copy link

iilyak commented Aug 1, 2023

Currently it doesn't seem to be possible to determine current version of a struct given a reference to a struct (clone() is not an option for the struct I have).

@doctorn
Copy link
Owner

doctorn commented Aug 2, 2023

I'm not sure I understand. Could you explain a little more? Maybe provide some code you'd like to work that doesn't?

@iilyak
Copy link
Author

iilyak commented Aug 2, 2023

My original problem is to detect the fact that configuration file need to be updated.
The idea is to use the version of the file encoded in the vsn field of a top level struct and
compare it with versions of all structs used in the configuration.

In order to do that I need to visit each node of the tree and collect versions of the struct involved.

It has been a challenge because obake doesn't support types with generics which means container types are not working
out of the box.

Here is some code showing the configuration structure

#[derive(Deserialize, Serialize, Debug, Default, PartialEq, Validate)]
#[obake::versioned]
#[obake(derive(serde::Serialize, serde::Deserialize))]
#[obake(version("0.0.1"))]
pub struct ConfigFile {
  pub vsn: u16,
  #[serde(with = "humantime_serde")]
  #[serde(skip_serializing_if = "Option::is_none")]
  #[serde(default)]
  pub delay: Option<Duration>,
  // I cannot use obake(version(xxx)) on container type
  pub profiles: Vec<Profile>,
}

#[obake::versioned]
#[obake(derive(serde::Serialize, serde::Deserialize, PartialEq, Debug))]
#[obake(version("0.0.3"))]
#[derive(Validate, serde::Deserialize, serde::Serialize, PartialEq, Debug)]
pub struct Profile {
  pub id: String,
  pub name: String,
}

I wanted to write a helper function for each struct which would return the greatest version

impl ConfigFile {
  pub fn vsn(self&) -> Version {
    // p in map function bellow has type &Profile_v0_0_1
    let profiles_vsn = self.profiles
      .first()
      .map(|p|
        Version::parse(<VersionedProfile as VersionTagged<Profile>>::version_str(p))
        .unwrap_or(Version::from("0.0.0")));

  }

}


The code above fails

331 | ...on::parse(<VersionedProfile as VersionTagged<Profile>>::version_str(p)).unwrap_or(Version::from("0.0.0")));
    |              --------------------------------------------------------- ^ expected `&VersionedProfile`, found `&Profile_v0_0_1`
    |              |
    |              arguments to this function are incorrect
    |
    = note: expected reference `&VersionedProfile`
               found reference `&Profile_v0_0_1`
  pub fn vsn(&self) -> Version {
    // p in map function bellow has type &Profile_v0_0_1
    let profiles_vsn = self.profiles.first().map(|p|{
        let v: obake::AnyVersion<Profile> = p.into();
        Version::parse(v.version_str)
    });
  }

The above fails with

334 |         let v: obake::AnyVersion<Profile> = p.into();
    |                                               ^^^^ the trait `From<&Profile_v0_0_1>` is not implemented for `VersionedProfile`
    |
    = note: required for `&Profile_v0_0_1` to implement `Into<VersionedProfile>`
  pub fn vsn(&self) -> Version {
    // p in map function bellow has type &Profile_v0_0_1
    let profiles_vsn = self.profiles.first().map(|p| {
      let v: obake::AnyVersion<Profile> = (*p).into();
      Version::parse(v.version_str())
    });
    profiles_vsn.unwrap().unwrap()
  }

The above fails

334 |       let v: obake::AnyVersion<Profile> = (*p).into();
    |                                           ^^^^ ------ `*p` moved due to this method call
    |                                           |
    |                                           move occurs because `*p` has type `Profile_v0_0_1`, which does not implement the `Copy` trait
    |
note: `into` takes ownership of the receiver `self`, which moves `*p`

As you can see there is no easy way to get the version. The following works

impl ConfigFile {
  pub fn version(&self) -> Version {
    Version::parse(Self::VERSION).expect("expect ConfigFile to be versioned")
  }

  pub fn vsn(&self) -> Version {
    let inner = self.profiles.first().map(|p| p.vsn());
    let inner = inner.unwrap();
    if inner < self.version() {
      self.version()
    } else {
      inner
    }
  }
}

impl Profile {
  pub fn version(&self) -> Version {
    Version::parse(Self::VERSION).expect("expect Profile to be versioned")
  }
  pub vsn(&self) -> Version {
      self.version()
  }
}

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

No branches or pull requests

2 participants