Created
October 28, 2019 08:30
-
-
Save timokroeger/e240a4ac2154bd405d8af99ce401aaa8 to your computer and use it in GitHub Desktop.
GPIO builder pattern prototype
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::marker::PhantomData; | |
| fn main() { | |
| let parts = Parts::new(); | |
| // Disabled by default | |
| let pa0: Pin<_, Disabled> = parts.pa0.into(); | |
| // Pull-up input | |
| let pa1: Pin<_, Input> = parts.pa1.pull_up().into(); | |
| // Push-pull output | |
| let pb0: Pin<_, Output<PushPull>> = parts.pb0.into(); | |
| // Push-pull output with pull-up not possible: | |
| // let pb1: Pin<_, Output<PushPull>> = parts.pb1.pull_up().into(); | |
| // ^^^^ the trait `std::convert::From<PinBuilder<PB1, PullUp>>` is not implemented for `Pin<_, Output<PushPull>>` | |
| // Open-drain output can be used with a pull-up | |
| let pb1: Pin<_, Output<OpenDrain>> = parts.pb1.pull_up().into(); | |
| } | |
| // ------------------------------------------------------------------------- // | |
| trait Mode {} | |
| struct Disabled; | |
| impl Mode for Disabled {} | |
| struct Input; | |
| impl Mode for Input {} | |
| struct Output<OM: OutputMode>(OM); | |
| impl<OM: OutputMode> Mode for Output<OM> {} | |
| trait OutputMode {} | |
| struct PushPull; | |
| impl OutputMode for PushPull {} | |
| struct OpenDrain; | |
| impl OutputMode for OpenDrain {} | |
| // ------------------------------------------------------------------------- // | |
| struct PinBuilder<T: PinTrait, P: Pull> { | |
| ty: T, | |
| _pull: P, | |
| } | |
| impl<T: PinTrait> PinBuilder<T, Floating> | |
| { | |
| fn pull_up(self) -> PinBuilder<T, PullUp> { | |
| PinBuilder { | |
| ty: self.ty, | |
| _pull: PullUp, | |
| } | |
| } | |
| } | |
| trait Pull {} | |
| struct Floating; | |
| impl Pull for Floating {} | |
| struct PullUp; | |
| impl Pull for PullUp {} | |
| // ------------------------------------------------------------------------- // | |
| struct Pin<T: PinTrait, M: Mode> { | |
| ty: T, | |
| _mode: PhantomData<M>, | |
| } | |
| impl<T: PinTrait> From<PinBuilder<T, Floating>> for Pin<T, Disabled> { | |
| fn from(mut pb: PinBuilder<T, Floating>) -> Self { | |
| pb.ty.modify_regs(); | |
| Self { | |
| ty: pb.ty, | |
| _mode: PhantomData, | |
| } | |
| } | |
| } | |
| impl<T: PinTrait> From<PinBuilder<T, PullUp>> for Pin<T, Disabled> { | |
| fn from(mut pb: PinBuilder<T, PullUp>) -> Self { | |
| pb.ty.modify_regs(); | |
| Self { | |
| ty: pb.ty, | |
| _mode: PhantomData, | |
| } | |
| } | |
| } | |
| impl<T: PinTrait> From<PinBuilder<T, Floating>> for Pin<T, Input> { | |
| fn from(mut pb: PinBuilder<T, Floating>) -> Self { | |
| pb.ty.modify_regs(); | |
| Self { | |
| ty: pb.ty, | |
| _mode: PhantomData, | |
| } | |
| } | |
| } | |
| impl<T: PinTrait> From<PinBuilder<T, PullUp>> for Pin<T, Input> { | |
| fn from(mut pb: PinBuilder<T, PullUp>) -> Self { | |
| pb.ty.modify_regs(); | |
| Self { | |
| ty: pb.ty, | |
| _mode: PhantomData, | |
| } | |
| } | |
| } | |
| impl<T: PinTrait> From<PinBuilder<T, Floating>> for Pin<T, Output<PushPull>> { | |
| fn from(mut pb: PinBuilder<T, Floating>) -> Self { | |
| pb.ty.modify_regs(); | |
| Self { | |
| ty: pb.ty, | |
| _mode: PhantomData, | |
| } | |
| } | |
| } | |
| impl<T: PinTrait> From<PinBuilder<T, Floating>> for Pin<T, Output<OpenDrain>> { | |
| fn from(mut pb: PinBuilder<T, Floating>) -> Self { | |
| pb.ty.modify_regs(); | |
| Self { | |
| ty: pb.ty, | |
| _mode: PhantomData, | |
| } | |
| } | |
| } | |
| impl<T: PinTrait> From<PinBuilder<T, PullUp>> for Pin<T, Output<OpenDrain>> { | |
| fn from(mut pb: PinBuilder<T, PullUp>) -> Self { | |
| pb.ty.modify_regs(); | |
| Self { | |
| ty: pb.ty, | |
| _mode: PhantomData, | |
| } | |
| } | |
| } | |
| /// Implemented by types that represent a specific pin. | |
| /// | |
| /// Register manipulation code generated by macros. | |
| trait PinTrait { | |
| fn modify_regs(&mut self); | |
| } | |
| macro_rules! pins { | |
| ($($pxy:ident, $PXy:ident;)*) => { | |
| $( | |
| struct $PXy; | |
| impl PinTrait for $PXy { | |
| fn modify_regs(&mut self) { | |
| // Something something | |
| } | |
| } | |
| )* | |
| struct Parts { | |
| $( | |
| $pxy: PinBuilder<$PXy, Floating>, | |
| )* | |
| } | |
| impl Parts { | |
| fn new() -> Self { | |
| Self { | |
| $( | |
| $pxy: PinBuilder { | |
| ty: $PXy, | |
| _pull: Floating, | |
| }, | |
| )* | |
| } | |
| } | |
| } | |
| } | |
| } | |
| pins!( | |
| pa0, PA0; | |
| pa1, PA1; | |
| // ... | |
| pb0, PB0; | |
| pb1, PB1; | |
| // ... | |
| ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment