Skip to content

Repository files navigation

from-similar License: Apache-2.0 OR MIT from-similar on crates.io from-similar on docs.rs Source Code Repository Rust Version: 1.71.1

FromSimilar automatically implements From between two structs that are “similar”.

Specifically for structs where the fields have the same names. Or tuple structs with similar positional arguments.

This macro is mainly useful to generate predicable From implementations for:

  • Structs that are mostly identical, except for a few attributes like #[serde] exceptions for serializing BSON.
  • Structs with a subset of fields from the more complete one.

Struct attributes

#[from(InputType)] a required attribute to specify the input type.
Will generate impl From<InputType> for T.

#[from(.., bidirectional = true)] optional attribute to implement both directions.
Will generate impl From<InputType> for T and impl From<T> for InputType.

Field attributes

#[use_into] is an optional field attribute to use .into() when converting this field.

#[use_into_option] for Option<T> types that need a .map(Into::into) when converting this field.

#[use_into_collection] for impl IntoIterator<T> types that should map each item and collect.

Example with database models

A bidirectional FromSimilar that can be used for MongoDB.

use from_similar::FromSimilar;

#[derive(Default)]
struct NormalModel {
    id: String,
    date: chrono::DateTime<chrono::Utc>,
    date_option: Option<chrono::DateTime<chrono::Utc>>,
    date_list: Vec<chrono::DateTime<chrono::Utc>>,
}

#[derive(FromSimilar, serde::Serialize, serde::Deserialize)]
#[from(NormalModel, bidirectional = true)]
struct DatabaseModel {
    #[serde(rename = "_id")]
    id: String,

    #[use_into]
    date: bson::DateTime,

    #[use_into_option]
    date_option: Option<bson::DateTime>,

    #[use_into_collection]
    date_list: Vec<bson::DateTime>,
}

let normal = NormalModel::default();
let db: DatabaseModel = normal.into();
let _: NormalModel = db.into();

Example with views

Note: #[from(.., bidirectional = true)] would break here, because it’s a lossy conversion.

use from_similar::FromSimilar;

#[derive(Default)]
struct FullModel {
    id: String,
    pretty_name: String,
    secret: String,
}

#[derive(FromSimilar)]
#[from(FullModel)]
struct PublicView {
    id: String,
    pretty_name: String,
    // ... omits `secret` field
}

let full = FullModel::default();
let _: PublicView = full.into();

Example with tuple struct

use from_similar::FromSimilar;

#[derive(Default)]
struct Data(pub String, pub usize);

#[derive(FromSimilar)]
#[from(Data)]
struct SealedData(#[use_into] std::sync::Arc<str>, usize);

let mut data = Data::default();
data.0 += "Pushing ";
data.0 += "some text";
data.1 = 42;
let data: SealedData = data.into();

About

Automatically implements `From` between two structs that are similar.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages