Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Sorry, if this is a bit messy, I will try my best to explain
- // what is going on:
- // I am creating a recursive type to keep track of the transaction.
- // This should allow the compiler to optimize most of the overhead
- // away and does not rely on std or the use of an internal buffer.
- /// A single transaction step
- #[derive(Debug)]
- enum Step<'a> {
- Write(&'a [u8]),
- Read(&'a mut [u8]),
- }
- /// Marker for the end of the transaction list
- #[derive(Debug)]
- struct End;
- /// Type for the recursive step list
- ///
- /// In practice, the types will look like
- /// TStep(Step::Write(..), TStep(Step::Read(..), End))
- #[derive(Debug)]
- struct TStep<A, B>(A, B);
- /// A transactable transaction. The idea is that a type that implements
- /// this trait is given to the bus to perform the transaction.
- /// The bus can then call `transact` to iterate over the steps.
- trait Transact<'a> {
- fn transact<F: FnMut(&mut Step<'a>)>(&'a mut self, f: F) -> F;
- }
- // Implementation for the last step
- impl<'a> Transact<'a> for TStep<Step<'a>, End> {
- fn transact<F: FnMut(&mut Step<'a>)>(&'a mut self, mut f: F) -> F {
- f(&mut self.0);
- f
- }
- }
- // Implementation for not last steps, calls transact recursively
- //
- // Needs to be depth first, because the list is backwards. I am unsure
- // if this can be done differently.
- impl<'a, S: Transact<'a>> Transact<'a> for TStep<Step<'a>, S> {
- fn transact<F: FnMut(&mut Step<'a>)>(&'a mut self, f: F) -> F {
- let mut f = self.1.transact(f);
- f(&mut self.0);
- f
- }
- }
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- // NEW //
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- impl<'a, T: std::iter::Iterator<Item = &'a mut Step<'a>>> Transact<'a> for T {
- fn transact<F: FnMut(&mut Step<'a>)>(&'a mut self, mut f: F) -> F {
- for mut s in self {
- f(s);
- }
- f
- }
- }
- /// A transaction that is bound to a bus and an address
- ///
- /// While the transaction is being created, it takes a mutable
- /// reference to the bus and only releases it once the transaction
- /// is done (goes out of scope).
- #[derive(Debug)]
- struct Transaction<'a, B: Transactor + 'a, S> {
- addr: u8,
- bus: &'a mut B,
- steps: S,
- }
- impl<'a, B: Transactor + 'a, S> Transaction<'a, B, S> {
- /// Add a new write step using the Builder pattern
- pub fn write(self, data: &'a [u8]) -> Transaction<'a, B, TStep<Step<'a>, S>> {
- println!(" Adding write for {} bytes", data.len());
- Transaction {
- addr: self.addr,
- bus: self.bus,
- steps: TStep(Step::Write(data), self.steps),
- }
- }
- /// Add a new read step using the Builder pattern
- pub fn read(self, buf: &'a mut [u8]) -> Transaction<'a, B, TStep<Step<'a>, S>> {
- println!(" Adding read for {} bytes", buf.len());
- Transaction {
- addr: self.addr,
- bus: self.bus,
- steps: TStep(Step::Read(buf), self.steps),
- }
- }
- }
- impl<'a, B: Transactor + 'a, S: Transact<'a>> Transaction<'a, B, S> {
- /// Commit this transaction
- ///
- /// Can only be called if the transaction contains transactable steps
- /// (= called .write() or .read() at least once)
- pub fn commit(&'a mut self) -> Result<(), ()> {
- println!("Committing transaction!");
- self.bus.commit(&mut self.steps)
- }
- }
- /// This is the trait that your Bus type needs to implement.
- /// It provides the `transaction` method which a user will call to start
- /// a transaction. `commit` needs to be implemented by the bus and should
- /// perform the transaction. It is not usually called directly by a user.
- ///
- /// `shared-bus` could provide a blanket implementation for this trait
- trait Transactor: Sized {
- /// Start a new transaction for an address
- fn transaction<'a>(&'a mut self, addr: u8) -> Transaction<Self, End> {
- println!("Starting transaction ...");
- Transaction {
- addr,
- bus: self,
- steps: End,
- }
- }
- /// Commit, ie actually perform a transaction
- fn commit<'a, S: Transact<'a>>(&'a mut self, steps: &'a mut S) -> Result<(), ()>;
- }
- /// Example bus type
- #[derive(Debug)]
- struct Bus;
- // Example `Transactor` implementation
- impl Transactor for Bus {
- fn commit<'a, S: Transact<'a>>(&'a mut self, steps: &'a mut S) -> Result<(), ()> {
- let mut i = 0;
- println!(" I2C: Start");
- // The closure is called for each step of the transaction
- steps.transact(|s| match s {
- Step::Write(d) => println!(" I2C: Write {:?}", d),
- Step::Read(buf) => {
- println!(" I2C: Read {:?} bytes", buf.len());
- for b in buf.iter_mut() {
- *b = i;
- i += 1;
- }
- }
- });
- println!(" I2C: End");
- Ok(())
- }
- }
- // Example
- fn main() {
- let mut bus = Bus;
- let mut buf1 = [0x00; 8];
- let mut buf2 = [0x00; 8];
- bus.transaction(0x48)
- .write(&[0xde, 0xad, 0xbe, 0xef])
- .read(&mut buf1)
- .write(&[0xc0, 0xff, 0xee])
- .read(&mut buf2)
- .commit().unwrap();
- println!("Take a look at the results:");
- println!(" Buf1: {:?}", buf1);
- println!(" Buf2: {:?}", buf2);
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- // NEW //
- ////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////
- println!("Example using a slice:");
- bus.commit(&mut [
- Step::Write(&[0x35, 0xc3]),
- Step::Read(&mut buf1),
- Step::Write(&[0x35, 0xc3]),
- ].iter_mut()).unwrap();
- println!("Take a look at the results:");
- println!(" Buf1: {:?}", buf1);
- }
Add Comment
Please, Sign In to add comment