Is there a macro for creating traits of shared properties? - rust

Let's say I have two structs that are quite similar:
struct Thing1 {
p1: i32,
p2: i32,
p3: i32
}
struct Thing2 {
p1: i32,
p2: i32,
p3: i32,
metadata: String
}
Having a trait for the common values is quite useful:
trait PValues {
fn p1(&self) -> i32;
fn p2(&self) -> i32;
fn p2(&self) -> i32;
}
impl PValues for Thing1 {
fn p1(&self) -> {self.p1};
fn p2(&self) -> {self.p2};
fn p3(&self) -> {self.p3};
}
impl PValues for Thing2 {
fn p1(&self) -> {self.p1};
fn p2(&self) -> {self.p2};
fn p3(&self) -> {self.p3};
}
However this is laborious, duplicative and error prone. Are there any commonly use rust macros that do this? If not, what is the idiomatic pattern for this?

Related

How to triple pendent traits un Rust without using dyn?

I have three traits that are dependent on each other, but I can't find a way to define these traits statically without using dyn.
Defining two seems very simple:
pub trait TA<B: TB<Self>> {
fn getB() -> Option<B>;
}
pub trait TB<A: TA<Self>> {
fn getA() -> Option<A>;
}
But defining similar thing with three traits seems impossible (the code bellow doesn't compile):
pub trait TA<B: TB, C: TC> {
fn getB() -> Option<B>;
fn getC() -> Option<C>;
}
pub trait TB<A: TA, C: TC> {
fn getA() -> Option<A>;
fn getC() -> Option<C>;
}
pub trait TC<A: TA, B: TB> {
fn getA() -> Option<A>;
fn getB() -> Option<B>;
}
It seems like with another thought it was easier than I thought.
pub trait TA<B: TB<Self, C>, C: TC<Self, B>> {
fn getB() -> Option<B>;
fn getC() -> Option<C>;
}
pub trait TB<A: TA<Self, C>, C: TC<Self, A>> {
fn getA() -> Option<A>;
fn getC() -> Option<C>;
}
pub trait TC<A: TA<A, Self>, B: TB<B, Self>> {
fn getA() -> Option<A>;
fn getB() -> Option<B>;
}
Edit: #trenctl solution bellow looks much cleaner
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=062b05bf63efb1b6bfb2575bf963ff62
trait Ta {
type B: Tb<A = Self, C = Self::C>;
type C: Tc<A = Self, B = Self::B>;
fn get_b(&self) -> Option<Self::B>;
fn get_c(&self) -> Option<Self::C>;
}
trait Tb {
type A: Ta<B = Self, C = Self::C>;
type C: Tc<B = Self, A = Self::A>;
fn get_a(&self) -> Option<Self::A>;
fn get_c(&self) -> Option<Self::C>;
}
trait Tc {
type A: Ta<C = Self, B = Self::B>;
type B: Tb<C = Self, A = Self::A>;
fn get_a(&self) -> Option<Self::A>;
fn get_b(&self) -> Option<Self::B>;
}

Automatic error conversion using the '?' operator for custom types

I'm struggling to understand the nuances of the ? operator. Take the following code:
link to playground
use std::{error::Error as StdError, fmt};
#[derive(Debug)]
struct MyError(Box<dyn StdError>);
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl StdError for MyError{}
impl From<Box<dyn StdError>> for MyError {
fn from(err: Box<dyn StdError>) -> Self {
MyError(err)
}
}
#[derive(Debug)]
struct RandomErr(String);
impl fmt::Display for RandomErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl StdError for RandomErr{}
fn no_custom() -> Result<(), Box<dyn StdError>> {
Err(RandomErr("hello there".to_owned()))?
}
// This fails to compile
fn custom() -> Result<(), MyError> {
Err(RandomErr("hello there".to_owned()))?
}
I would think that custom() should compile. RandomError is a StdError, so RandomErr should be convertable to MyError since there's an impl for converting from StdError, no?
I would think that custom() should compile. RandomError is a StdError, so RandomErr should be convertable to MyError since there's an impl for converting from StdError, no?
Nope. There is no transitivity in From (or any trait, as far as I know). Rustc generally does what you tell it and no more to avoid problems like combinatory explosions in trait resolution.
So that C: From<B> and B: From<A> does not imply / translate to C: From<A>, you can write that reduced case and will hit E0277 (trait not satisfied):
struct A;
struct B;
struct C;
impl From<A> for B {
fn from(a: A) -> Self { B }
}
impl From<B> for C {
fn from(b: B) -> Self { C }
}
fn main() {
let _: C = From::from(A);
}

How to generalize a function over two types with similar fields in different positions?

I have a function algo which works with a type S1, I also have
a type S2 which contains all of the fields of S1 plus some additional ones.
How should I modify algo to also accept S2 as input without
creating a temporary variable with type S1 and data from S2?
struct Moo1 {
f1: String,
f2: i32,
}
struct Moo2 {
f1: String,
f2: i32,
other_fields: f32,
}
struct S1 {
x: i32,
v: Vec<Moo1>,
}
struct S2 {
x: i32,
v: Vec<Moo2>,
}
//before fn algo(s: &S1)
fn algo<???>(???) {
//work with x and v (only with f1 and f2)
}
Where I'm stuck
Let's assume algo has this implementation (my real application has another implementation):
fn algo(s: &S1) {
println!("s.x: {}", s.x);
for y in &s.v {
println!("{} {}", y.f1, y.f2);
}
}
To access the field in Moo1 and Moo2 I introduce trait AsMoo, and to access x field and v I introduce trait AsS:
trait AsMoo {
fn f1(&self) -> &str;
fn f2(&self) -> i32;
}
trait AsS {
fn x(&self) -> i32;
// fn v(&self) -> ???;
}
fn algo<S: AsS>(s: &AsS) {
println!("s.x: {}", s.x());
}
I'm stuck at the implementation of the AsS::v method. I do not allocate memory to use my algo, but I need a Vec<&AsMoo> in some way.
Maybe I need to return some kind of Iterator<&AsMoo>, but have no idea how to do it and that looks complex for this problem.
Maybe I should use macros instead?
Any problem in computer science can be solved by adding another layer of indirection; at the exception of having too many such layers, of course.
Therefore, you are correct that you miss a S trait to generalize S1 and S2. In S, you can use a feature called associated type:
trait Moo {
fn f1(&self) -> &str;
fn f2(&self) -> i32;
}
trait S {
type Mooer: Moo;
fn x(&self) -> i32;
fn v(&self) -> &[Self::Mooer];
}
The bit type Mooer: Moo; says: I don't quite know what the exact type Mooer will end up being, but it'll implement the Moo trait.
This lets you write:
impl S for S1 {
type Mooer = Moo1;
fn x(&self) -> i32 { self.x }
fn v(&self) -> &[Self::Mooer] { &self.v }
}
impl S for S2 {
type Mooer = Moo2;
fn x(&self) -> i32 { self.x }
fn v(&self) -> &[Self::Mooer] { &self.v }
}
fn algo<T: S>(s: &T) {
println!("s.x: {}", s.x());
for y in s.v() {
println!("{} {}", y.f1(), y.f2());
}
}
And your generic algo knows that whatever type Mooer ends up being, it conforms to the Moo trait so the interface of Moo is available.

How can I reuse code for similar trait implementations?

I have a few traits with default implementations that require the same methods, which happen to be field getters.
trait AddPosition<T: Display>{
fn x(&self) -> T;
fn y(&self) -> T;
fn add(&self){
println!("{:}", self.x()+self.x());
}
}
trait SubPosition<T: Display>{
fn x(&self) -> T;
fn y(&self) -> T;
fn sub(&self){
println!("{:}", self.x()-self.y());
}
}
Instead of manually repeating the same code for each trait implementation, can I have something like this?
impl AddPosition<i32>, SubPosition<i32> for Point{
fn x(&self) -> i32{ self.x }
fn y(&self) -> i32{ self.y }
}
The best option is probably to factor out the fact that your objects can have a position:
trait Position<T: Display> {
fn x(&self) -> T;
fn y(&self) -> T;
}
// trait AAA: BBB --> means AAA must implement BBB
trait AddPosition<T: Add<Output=T> + Display>: Position<T> {
fn add(&self){
println!("{:}", self.x()+self.x()); // ?
}
}
trait SubPosition<T: Sub<Output=T> + Display>: Position<T> {
fn sub(&self){
println!("{:}", self.x()-self.y()); // ?
}
}
struct MyPosition {
x: i32,
y: i32,
}
impl Position<i32> for MyPosition {
fn x(&self) -> i32 { self.x }
fn y(&self) -> i32 { self.y }
}
impl SubPosition<i32> for MyPosition {}
impl AddPosition<i32> for MyPosition {}
(Playground)
However, I fail to understand how your code really makes sense (? annotated lines). If this is just for the sake of the minimal example, this is totally fine; however, if this is meant for any serious code, you may want to look into the Add and Sub trait, which will allow you to benefit from operator overloading + and -. Even if you don't use those traits directly, they may inspire you for meaningful signatures of a potential add(&self, rhs: &P) -> P function (where P: Position<T>).

How do I implement Into<MyType> for &str

I have a custom type pub struct Foo and I'd like to be able to say strings can be converted to Foo types. I'm trying to do impl<'a> Into<Foo> for &'a str, but I know from this answer that I can't do that. What other options do I have?
For context, I'm trying to do something like
trait Foo {
type ArgType;
fn new<I: Into<Self::ArgType>>(arg: I) -> Self;
}
struct MyType;
impl Into<MyType> for str {
fn into(self) -> MyType { MyType }
}
struct Bar;
impl Foo for Bar {
type ArgType = MyType;
fn new<I: Into<MyType>>(arg: I) -> Bar { Bar }
}
As Chris Morgan noted, FromStr is an option, From<&str> would be another. The latter would give you a builtin implementation of Into<Foo> for &str, too (because there is a blanket impl of Into<U> For T where U: From<T>).

Resources