use thisversion::VersionFamily;
use thisversion::traits::{IntoModel, IntoSchema};
#[derive(Debug, PartialEq, Eq)]
pub struct Contact {
pub name: String,
pub email: String,
pub phone: Option<String>,
}
#[derive(VersionFamily)]
pub enum GoogleContactVersions {
V1(GoogleContactV1),
V2(GoogleContactV2),
V3(GoogleContactV3),
}
pub struct GoogleContactV1 {
pub name: String,
pub email: String,
}
pub struct GoogleContactV2 {
pub name: String,
pub email: String,
pub phone: Option<String>,
}
impl From<GoogleContactV1> for GoogleContactV2 {
fn from(prev: GoogleContactV1) -> Self {
Self {
name: prev.name,
email: prev.email,
phone: None,
}
}
}
pub struct GoogleContactV3 {
pub name: String,
pub email_address: String,
pub phone: Option<String>,
}
impl From<GoogleContactV2> for GoogleContactV3 {
fn from(prev: GoogleContactV2) -> Self {
Self {
name: prev.name,
email_address: prev.email,
phone: prev.phone,
}
}
}
impl IntoModel for GoogleContactV3 {
type Model = Contact;
fn into_model(self) -> Self::Model {
Contact {
name: self.name,
email: self.email_address,
phone: self.phone,
}
}
}
impl IntoSchema<GoogleContactVersions> for Contact {
fn into_schema(self) -> GoogleContactVersions {
GoogleContactVersions::V3(GoogleContactV3 {
name: self.name,
email_address: self.email,
phone: self.phone,
})
}
}
#[derive(VersionFamily)]
pub enum OutlookContactVersions {
V1(OutlookContactV1),
V2(OutlookContactV2),
V3(OutlookContactV3),
}
pub struct OutlookContactV1 {
pub first_name: String,
pub last_name: String,
pub email: String,
}
pub struct OutlookContactV2 {
pub first_name: String,
pub last_name: String,
pub email: String,
pub phone: Option<String>,
}
impl From<OutlookContactV1> for OutlookContactV2 {
fn from(prev: OutlookContactV1) -> Self {
Self {
first_name: prev.first_name,
last_name: prev.last_name,
email: prev.email,
phone: None,
}
}
}
pub struct OutlookContactV3 {
pub first_name: String,
pub last_name: String,
pub display_name: String,
pub email: String,
pub phone: Option<String>,
}
impl From<OutlookContactV2> for OutlookContactV3 {
fn from(prev: OutlookContactV2) -> Self {
let display_name = format!("{} {}", prev.first_name, prev.last_name);
Self {
first_name: prev.first_name,
last_name: prev.last_name,
display_name,
email: prev.email,
phone: prev.phone,
}
}
}
impl IntoModel for OutlookContactV3 {
type Model = Contact;
fn into_model(self) -> Self::Model {
Contact {
name: self.display_name,
email: self.email,
phone: self.phone,
}
}
}
fn main() {
let google = GoogleContactVersions::V1(GoogleContactV1 {
name: "Ada Lovelace".to_owned(),
email: "ada@example.com".to_owned(),
});
let from_google = google.into_model();
assert_eq!(from_google.name, "Ada Lovelace");
assert_eq!(from_google.email, "ada@example.com");
assert_eq!(from_google.phone, None);
let outlook = OutlookContactVersions::V1(OutlookContactV1 {
first_name: "Ada".to_owned(),
last_name: "Lovelace".to_owned(),
email: "ada@example.com".to_owned(),
});
let from_outlook = outlook.into_model();
assert_eq!(from_outlook.name, "Ada Lovelace");
assert_eq!(from_outlook.email, "ada@example.com");
assert_eq!(from_outlook.phone, None);
assert_eq!(from_google, from_outlook);
let contact = Contact {
name: "Ada Lovelace".to_owned(),
email: "ada@example.com".to_owned(),
phone: None,
};
let google: GoogleContactVersions = contact.into_schema();
assert!(matches!(google, GoogleContactVersions::V3(_)));
}