Skip to content

Instantly share code, notes, and snippets.

@Rahix
Last active January 19, 2019 20:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Rahix/1c6290db092aa96996f49046ca331e49 to your computer and use it in GitHub Desktop.
Save Rahix/1c6290db092aa96996f49046ca331e49 to your computer and use it in GitHub Desktop.
Proof of concept for moveable parts
https://start.duckduckgo.com/// These are our "fake" pins
#[derive(Debug)]
pub struct PA;
#[derive(Debug)]
pub struct PB;
#[derive(Debug)]
pub struct PC;
#[derive(Debug)]
pub struct PD;
/// Parts
#[moveable_parts::parts]
#[derive(Debug)]
pub struct Parts {
// Pin A
pub pa: PA,
// Pin B
pub pb: PB,
// Pin C
pub pc: PC,
// Pin D
pub pd: PD,
}
/// LED Wrapper
#[derive(Debug)]
pub struct Led<Pin> {
pin: Pin,
}
impl<Pin> Led<Pin> {
// Normal interface
pub fn new(pin: Pin) -> Led<Pin> {
Led {
pin
}
}
// This interface takes the part and moves out one pin
pub fn from_parts<P: moveable_parts::TakePart<Pin>>(parts: P) -> (Self, P::Remainder) {
let (pin, rem) = parts.take_part();
(Led::new(pin), rem)
}
}
fn main() {
use moveable_parts::TakePart;
// Mockup, you would get these parts from GPIO.split()
let parts = Parts {
pa: PA,
pb: PB,
pc: PC,
pd: PD,
};
println!("Parts: {:?}", parts);
// Output: Parts: Parts { pa: PA, pb: PB, pc: PC, pd: PD }
// All parts are available
let (a, parts): (PA, _) = parts.take_part();
let led_a = Led::new(a);
println!("Led A: {:?}", led_a);
// Output: Led A: Led { pin: PA }
println!("Parts: {:?}", parts);
// Output: Parts: Parts { pa: Moved, pb: PB, pc: PC, pd: PD }
// Pin A is gone!
let (led_b, parts) = Led::<PB>::from_parts(parts);
println!("Led B: {:?}", led_b);
// Led B: Led { pin: PC }
println!("Parts: {:?}", parts);
// Parts: Parts { pa: Moved, pb: Moved, pc: PC, pd: PD }
// A and B are moved!
let (led_d, parts) = Led::<PD>::from_parts(parts);
println!("Led D: {:?}", led_d);
// Led D: Led { pin: PD }
println!("Parts: {:?}", parts);
// Parts: Parts { pa: Moved, pb: Moved, pc: PC, pd: Moved }
// Only C is still available!
}
pub trait TakePart<P> {
type Remainder;
fn take_part(self) -> (P, Self::Remainder);
}
/// Parts
#[derive(Debug)]
pub struct Parts<_P0 = PA, _P1 = PB, _P2 = PC, _P3 = PD> {
// Pin A
pub pa: _P0,
// Pin B
pub pb: _P1,
// Pin C
pub pc: _P2,
// Pin D
pub pd: _P3,
}
impl<_P1, _P2, _P3> moveable_parts::TakePart<PA> for Parts<PA, _P1, _P2, _P3> {
type Remainder = Parts<moveable_parts::Moved, _P1, _P2, _P3>;
fn take_part(self) -> (PA, Self::Remainder) {
(
self.pa,
Parts {
pa: moveable_parts::Moved,
pb: self.pb,
pc: self.pc,
pd: self.pd,
},
)
}
}
impl<_P0, _P2, _P3> moveable_parts::TakePart<PB> for Parts<_P0, PB, _P2, _P3> {
type Remainder = Parts<_P0, moveable_parts::Moved, _P2, _P3>;
fn take_part(self) -> (PB, Self::Remainder) {
(
self.pb,
Parts {
pb: moveable_parts::Moved,
pa: self.pa,
pc: self.pc,
pd: self.pd,
},
)
}
}
impl<_P0, _P1, _P3> moveable_parts::TakePart<PC> for Parts<_P0, _P1, PC, _P3> {
type Remainder = Parts<_P0, _P1, moveable_parts::Moved, _P3>;
fn take_part(self) -> (PC, Self::Remainder) {
(
self.pc,
Parts {
pc: moveable_parts::Moved,
pa: self.pa,
pb: self.pb,
pd: self.pd,
},
)
}
}
impl<_P0, _P1, _P2> moveable_parts::TakePart<PD> for Parts<_P0, _P1, _P2, PD> {
type Remainder = Parts<_P0, _P1, _P2, moveable_parts::Moved>;
fn take_part(self) -> (PD, Self::Remainder) {
(
self.pd,
Parts {
pd: moveable_parts::Moved,
pa: self.pa,
pb: self.pb,
pc: self.pc,
},
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment