I need some help for removing a lot of duplicates in my code (but I'm afraid I can't).
Let's assume we have a struct Bar who owns a value of type T
. You can either read of it, if it is an Input
-Bar, write to it if it is an Output
-Bar or do both operations, if it is an InOut
-Bar.
On top of that, I want to be able to get the opposite of that, in case of an Output
-Bar, I want to get an Input
-bar and vice versa. Inout
is the opposite to itself.
Below is my approach, I like it, but is very verbose.
There is no way, that a user can implement Direction
and Input
, Output
and InOut
are the only possible structs for Direction
.
use std::marker::PhantomData;
mod private {
pub trait Sealed {}
impl Sealed for super::Input {}
impl Sealed for super::Output {}
impl Sealed for super::InOut {}
}
pub trait Direction: private::Sealed {}
pub struct Input;
pub struct Output;
pub struct InOut;
impl Direction for Input {}
impl Direction for Output {}
impl Direction for InOut {}
pub struct Bar<T, D: Direction> {
value: T,
_marker: PhantomData<D>,
}
impl<T: Default, D: Direction> Bar<T, D> {
pub fn new() -> Bar<T, D> {
Bar {
value: T::default(),
_marker: PhantomData,
}
}
}
impl<T> Bar<T, Input> {
pub fn create_opposite(self) -> Bar<T, Output> {
Bar {
value: self.value,
_marker: PhantomData,
}
}
}
impl<T> Bar<T, Output> {
pub fn create_opposite(self) -> Bar<T, Input> {
Bar {
value: self.value,
_marker: PhantomData,
}
}
}
impl<T> Bar<T, InOut> {
pub fn create_opposite(self) -> Bar<T, InOut> {
self
}
}
impl<T> Bar<T, Input> {
pub fn read(&self) -> &T {
&self.value
}
}
impl<T> Bar<T, Output> {
pub fn set(&mut self, value: T) {
self.value = value
}
}
impl<T> Bar<T, InOut> {
pub fn read(&self) -> &T {
&self.value
}
pub fn set(&mut self, value: T) {
self.value = value
}
}