impl Default sugar for large struct without derive - rust

If I have a struct I need Default implemented on, if all the field's types have Default implemented themsevles, then I can use the derive macro, otherwise I need to implement Default manually. However, there are some situations where I have a large struct where almost all the fields would be derivable, except there is a small number of fields with types which do not have Default implemented, and I can impl myself because the type is external. This ends up with the situation in the below example. I would prefer to avoid this as it means I need to keep the fields in sync between two places, which is more time consuming, error prone, and verbose. I'm hoping there might be some syntactical suagr to avoid this, but I'm new to rust and can't think of any. I'm thinking something like:
impl Default for Data2 {
fn default() -> Self {
Self {
external_data: ExternalType::One,
..Default::default(),
}
}
}
Example
#[derive(Default)]
struct Data {
name: Option<String>,
flag: bool,
selected: Vec<String>,
show_reference: Option<String>,
index: Option<usize>,
create_name: String,
create_type: String,
}
enum ExternalType {
One,
Two,
}
// #[derive(Default)]
struct Data2 {
name: Option<String>,
flag: bool,
selected: Vec<String>,
show_reference: Option<String>,
index: Option<usize>,
create_name: String,
create_type: String,
external_data: ExternalType,
}
impl Default for Data2 {
fn default() -> Self {
Self {
name: Default::default(),
flag: Default::default(),
selected: Default::default(),
show_reference: Default::default(),
index: Default::default(),
create_name: Default::default(),
create_type: Default::default(),
external_data: ExternalType::One,
}
}
}

I think the smart-default crate can handle this. It lets you derive SmartDefault, which derives Default for all fields except those with a #[default(my_default_value)] attribute.
Example:
use smart_default::SmartDefault;
#[derive(SmartDefault)]
enum Foo {
Bar,
#[default]
Baz {
#[default = 12]
a: i32,
b: i32,
#[default(Some(Default::default()))]
c: Option<i32>,
#[default(_code = "vec![1, 2, 3]")]
d: Vec<u32>,
#[default = "four"]
e: String,
},
Qux(i32),
}
There's also the more general derivative crate which lets you customize how all derives work, not just Default, but is a tad more verbose (because it's more general).
Example:
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Default)]
pub struct RegexOptions {
pub pats: Vec<String>,
#[derivative(Default(value="10 * (1 << 20)"))]
pub size_limit: usize,
#[derivative(Default(value="2 * (1 << 20)"))]
pub dfa_size_limit: usize,
pub case_insensitive: bool,
pub multi_line: bool,
pub dot_matches_new_line: bool,
pub swap_greed: bool,
pub ignore_whitespace: bool,
#[derivative(Default(value="true"))]
pub unicode: bool,
}

As with most Orphan rule problems the only option available is the New Type pattern but I'm not sure this is really an improvement over a manual default impl.
struct ExternalWithDefault(ExternalType);
impl Default for ExternalWithDefault {
fn default() -> Self {
Self(ExternalType::One)
}
}
...
#[derive(Default)]
struct Data2 {
name: Option<String>,
flag: bool,
selected: Vec<String>,
show_reference: Option<String>,
index: Option<usize>,
create_name: String,
create_type: String,
external_data: ExternalWithDefault,
}

Related

How to implement a function for different vector of structs with traits?

I have 3 Vec<T> structs that shared the same function:
Vec<RawTransaction>
Vec<RawCashTransaction>
Vec<RawAdjustmentTransaction>
All three shared the same VerifyableRaw traits and the verify() function. I use the verify() function check the validity of the content of that array/vector.
Here's my implementation. As you can see, all of them shared the same basic fields, namely: date, total, credit, and debit.
My problem is: since I use the same fields that those structs shared, the verify() function is the same for all of them. In verify function, I need to access the date, total, credit, and debit fields so I just copy and paste the code from one implementation to another.
My question is: Can I refactor this trait implementation into a single function definition ?
I found out that I need to repeat myself each time I need to use verify() function and VerifyableRaw trait to another struct that needs it
pub struct RawTransaction {
pub date: Option<NaiveDate>,
pub contact_name: String,
pub total: Option<Decimal>,
pub credit: String,
pub debit: String,
}
pub struct RawCashTransaction{
pub tr_type: String,
pub date: Option<NaiveDate>,
pub contact_name: String,
pub total: Option<Decimal>,
pub credit: String,
pub debit: String,
}
pub struct RawAdjustmentTransaction{
pub date: Option<NaiveDate>,
pub info: String,
pub total: Option<Decimal>,
pub credit: String,
pub debit: String,
}
Here's my trait implementation:
#[async_trait]
pub trait VerifyableRaw {
async fn verify(&self, cid: String, db: Database) -> Result<bool, Err>;
}
#[async_trait]
impl VerifyableRaw for Vec<RawTransaction> {
async fn verify(&self, cid: String, db: Database) -> Result<bool, Err> {
/// .... this function is the same for all three
let data = &self; // access the vector
for (i, row) in data.iter().enumerate() {
// enumerate each item in this vector
let date = row.date.unwrap(); // check if the date is valid, etc
let de = row.debit.clone(); // check if this value is valid
let cr = row.credit.clone(); // check if this value is valid
// ... another process here ...
}
}
}
#[async_trait]
impl VerifyableRaw for Vec<RawCashTransaction> {
async fn verify(&self, cid: String, db: Database) -> Result<bool, Err> {
/// .... this function is exactly the same as RawTransaction above
}
}
#[async_trait]
impl VerifyableRaw for Vec<RawAdjustmentTransaction> {
async fn verify(&self, cid: String, db: Database) -> Result<bool, Err> {
/// .... this function is exactly the same as RawTransaction above
}
}
To avoid repetition, you can put the common fields in a struct, and instead of copying every field into each concrete struct, simply include a single field whose type is the common one:
pub struct BaseTransaction {
pub date: Option<NaiveDate>,
pub total: Option<Decimal>,
pub credit: String,
pub debit: String,
}
pub struct RawTransaction {
pub base: BaseTransaction,
pub contact_name: String,
}
pub struct RawCashTransaction{
pub base: BaseTransaction,
pub tr_type: String,
pub contact_name: String,
}
pub struct RawAdjustmentTransaction{
pub base: BaseTransaction,
pub info: String,
}
Then impl AsRef<BaseTransaction> for each concrete type:
impl AsRef<BaseTransaction> for RawTransaction {
fn as_ref (&self) -> &BaseTransaction {
&self.base
}
}
impl AsRef<BaseTransaction> for RawCashTransaction {
fn as_ref (&self) -> &BaseTransaction {
&self.base
}
}
impl AsRef<BaseTransaction> for RawAdjustmentTransaction {
fn as_ref (&self) -> &BaseTransaction {
&self.base
}
}
and now you can have a single generic function that operates on AsRef<BaseTransaction>:
impl<T: AsRef<BaseTransaction>> VerifyableRaw for Vec<T> {
async fn verify(&self, cid: String, db: Database) -> Result<bool, Err> {
let base: BaseTransaction = self.as_ref();
unimplemented!()
}
}
Yes, you can:
pub trait VerifyableRaw {
fn date(&self) -> Option<NativeDate>;
fn credit(&self) -> &str;
fn debit(&self) -> &str;
}
pub trait VerifyableRaws {
async fn verify(&self, cid: String, db: Database) -> Result<bool, Err>;
}
impl VerifyableRaw for RawCashTransaction {
fn date(&self) -> Option<NativeDate> { self.date }
fn credit(&self) -> &str { &self.credit }
fn debit(&self) -> &str { &self.debit }
}
impl<T: VerifyableRaw> VerifyableRaws for Vec<T> {
async fn verify(&self, cid: String, db: Database) -> Result<bool, Err> {
// your implementation here, but replace field access with method calls
}
}
// other types have the same implementation
You still have to write implementation for the access method for every type, but I believe it's better than duplicate complex business logic.
If you have too many types like that and you don't want to write getters manually for each of them it's quite trivial to write a macro that will do it for you. But for just 3 types I would not recommend it for macros make things much more complicated than they need to be.

Is there a short way to implement Default for a struct that has a field that does not implement Default?

I have a struct that has 20 fields:
struct StructA {
value1: i32,
value2: i32,
// ...
value19: i32,
day: chrono::NaiveDate,
}
I'd like to impl Default trait for StructA. I tried to add #[derive(Default)] to the struct, but chrono::NaiveDate doesn't implement Default.
I then tried to implement Default for StructA:
impl Default for StructA {
fn default() -> Self {
Self {
value1: Default::default(),
value2: Default::default(),
// ...
value19: Default::default(),
day: chrono::NaiveDate::from_ymd(2021, 1, 1),
}
}
}
This code works fine, but the parts of value1 through value19 are redundant. Is there a solution with less code?
I defined StructA to deserialize JSON data via serde-json so I can't change the struct's definition.
A value of day: chrono::NaiveDate is always given from JSON data, so I want to avoid day: Option<chrono::NaiveDate>.
The derivative crate makes this kind of thing a breeze:
#[derive(Derivative)]
#[derivative(Default)]
struct StructA {
value1: i32,
value2: i32,
// ...
value19: i32,
#[derivative(Default(value = "NaiveDate::from_ymd(2021, 1, 1)"))]
day: NaiveDate,
}
If you want to avoid external crates, your options are:
the approach you already used, with the downside that you must name all the fields. Also note that you don't need to repeat Default::default() for each numeric field, a simple 0 will work as well.
make day an Option and derive Default, with the downside that it will default to None, bear a run-time cost, and you'll have to unwrap() to access it.
make day a newtype that wraps NaiveDate and implements Default to set it to the desired value, with the downside that you'll need to access the NaiveDate through a (zero-cost) field or method.
That's a rather dirty trick, but you can wrap your date in an Option, and it has an implementation of Default. Then you won't need to implement Default on your own, you can derive it. To keep the same semantics of StructA::default() you'll need to write your own method (luckily Rust allows to define default() method besides already derived Default::default()) Playground
use chrono;
#[derive(Debug, Default)]
struct StructA {
value1: i32,
value2: i32,
value19: i32,
day: Option<chrono::NaiveDate>,
}
impl StructA {
fn default() -> Self {
let mut instance: Self = Default::default();
instance.day = Some(chrono::NaiveDate::from_ymd(2021, 1, 1));
instance
}
}
fn main() {
println!("{:?}", StructA::default());
// StructA { value1: 0, value2: 0, value19: 0, day: Some(2021-01-01) }
}
Downsides of this version:
Need to .unwrap() the date everywhere it's used
Two methods with same name default, but one is Self::default which fills the date as I implemented and the other is Default::default which fills the date with None, you'll need to be careful which you call (calling StructA::default() invokes Self::default())
EDIT. Please be careful with this answer (details in the comments by #user4815162342)
In short - the last downside of having two different .default() methods in one type is dangerous in generic methods with T: Default arguments, because in this case will be called Default::default(), which initializes the day field to None. The worst part of this effect, is that compiler won't ever warn you about it, thus forcing you to spend your time debugging in case of a bug.
There's one similar approach suggested by #Ă–merErden, where you can again wrap the date into another type, to which you implement Default on your own. This will ensure that your field will always be initialized, but still forces you to somehow "unwrap" the value. In case of wrapping NaiveDate into a tuple struct, you can unwrap as simply as instance.day.0 or implement Deref to this wrapper and unwrap with *instance.day
use chrono;
use std::ops::Deref;
#[derive(Debug)]
struct NaiveDateWrapper(chrono::NaiveDate);
impl Default for NaiveDateWrapper {
fn default() -> Self {
Self(chrono::NaiveDate::from_ymd(2021, 1, 1))
}
}
impl Deref for NaiveDateWrapper {
type Target = chrono::NaiveDate;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Debug, Default)]
struct StructA {
value1: i32,
value2: i32,
value19: i32,
day: NaiveDateWrapper,
}
fn main() {
let v = StructA::default();
println!("{:?}", v.day.0);
println!("{:?}", *v.day);
}
There is another crate called Educe https://docs.rs/educe/latest/educe/#default
Some code snippets.
#[macro_use] extern crate educe;
#[derive(Educe)]
#[educe(Default)]
struct Struct {
#[educe(Default = 1)]
f1: u8,
#[educe(Default = 11111111111111111111111111111)]
f2: i128,
#[educe(Default = 1.1)]
f3: f64,
#[educe(Default = true)]
f4: bool,
#[educe(Default = "Hi")]
f5: &'static str,
#[educe(Default = "Hello")]
f6: String,
#[educe(Default = 'M')]
f7: char,
}
#[derive(Educe)]
#[educe(Default)]
enum Enum {
Unit,
#[educe(Default)]
Tuple(
#[educe(Default(expression = "0 + 1"))]
u8,
#[educe(Default(expression = "-11111111111111111111111111111 * -1"))]
i128,
#[educe(Default(expression = "1.0 + 0.1"))]
f64,
#[educe(Default(expression = "!false"))]
bool,
#[educe(Default(expression = "\"Hi\""))]
&'static str,
#[educe(Default(expression = "String::from(\"Hello\")"))]
String,
#[educe(Default(expression = "'M'"))]
char,
),
}
#[derive(Educe)]
#[educe(Default)]
union Union {
f1: u8,
f2: i128,
f3: f64,
f4: bool,
#[educe(Default = "Hi")]
f5: &'static str,
f6: char,
}

Rust - value of type cannot be built from `std::iter::Iterator<>`

I have struct from which I want to extract the data.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RunResult {
pub runs: Vec<RunDetails>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RunDetails {
pub details: String,
pub name: String,
pub id: String,
pub type: String,
}
I am getting the data which got inserted in above struct in the variable result which I am iterating below
let my_result:RunResult = result
.runs
.into_iter()
.filter(|line| line.details.contains(&"foo"))
.collect();
I am getting the error as
value of type `RunResult` cannot be built from `std::iter::Iterator<Item=RunDetails>`
I want to get the record where type=OK, details contains foo with highest id.
How can I achieve this?
Check out the documentation for collect here.
Your struct RunResult should implement FromIterator<RunDetails>.
Try adding this (untested by me):
impl FromIterator<RunDetails> for RunResult {
fn from_iter<I: IntoIterator<Item=RunDetails>>(iter: I) -> Self {
Self {
runs: Vec::from_iter(iter);
}
}
}

Simplest way to match multiple fields of a struct against `None`

I have a Rust struct like this:
pub struct SomeMapping {
pub id: String,
pub other_id: Option<String>,
pub yet_another_id: Option<String>,
pub very_different_id: Option<String>
}
What is the simplest way to check if all optional ids are not set? I know the syntax like
if let Some(x) = option_value {...}
to extract a value from an Option, but I don't get how to use this in a concise way to check multiple values for None.
You can destructure a structure in pattern matching like so:
pub struct SomeMapping {
pub id: String,
pub other_id: Option<String>,
pub yet_another_id: Option<String>,
pub very_different_id: Option<String>,
}
fn main() {
let x = SomeMapping {
id: "R".to_string(),
other_id: Some("u".to_string()),
yet_another_id: Some("s".to_string()),
very_different_id: Some("t".to_string()),
};
if let SomeMapping {
id: a,
other_id: Some(b),
yet_another_id: Some(c),
very_different_id: Some(d),
} = x {
println!("{} {} {} {}", a, b, c, d);
}
}
It is documented in the Rust book chapter 18.

Derive attribute for specific fields only, like serde does

Using derive syntax, can I implement traits like Hash or PartialEq using specific fields, not all of them?
It could look like:
#[derive(Debug, Hash, Eq, PartialEq)]
struct MyStruct {
id: i32,
name: String,
#[derive(hash_skip, eq_skip)]
aux_data1: f64,
#[derive(hash_skip, eq_skip)]
aux_data2: f64,
#[derive(hash_skip, eq_skip)]
aux_data3: String,
}
I want the hash method to only use id, and name and no others.
The serde library allows something like this for serialization.
No, there is no such feature in Rust at this moment. What I would suggest is to use the implementation for tuples available for these traits, like this:
use std::hash::{Hash, Hasher};
#[derive(Debug)]
struct MyStruct {
id: i32,
name: String,
aux_data1: f64,
aux_data2: f64,
aux_data3: String,
}
impl Hash for MyStruct {
fn hash<H>(&self, state: &mut H) where H: Hasher {
(&self.id, &self.name).hash(state);
}
}
impl PartialEq for MyStruct {
fn eq(&self, other: &Self) -> bool {
(&self.id, &self.name) == (&other.id, &other.name)
}
}
Edit: or as #Shepmaster suggested in a comment below, you can create a key function which returns a tuple of all useful fields and use it.
impl MyStruct {
fn key(&self) -> (&i32, &String) {
(&self.id, &self.name)
}
}
impl Hash for MyStruct {
fn hash<H>(&self, state: &mut H) where H: Hasher {
self.key().hash(state);
}
}
impl PartialEq for MyStruct {
fn eq(&self, other: &Self) -> bool {
self.key() == other.key()
}
}
This is possible by using derivative.
Example:
use derivative::Derivative;
#[derive(Derivative)]
#[derivative(Hash, PartialEq)]
struct Foo {
foo: u8,
#[derivative(Hash="ignore")]
#[derivative(PartialEq="ignore")]
bar: u8,
}

Resources