State machines with lib, expected lifetime parameter

I’m trying out this nice state machine library at https://github.com/rust-bakery/machine.

It complains about:
–> src/main.rs:27:15
|
27 | (IsTaken, DropItem) => IsDropped,
| ^^^^^^^^ expected lifetime parameter

because the struct DropItem is apparently not allowed to have lifetime references, maybe a limitation of the library. The mutable reference is called bang and I’d like to have it available on transition.

Using a second parameter for IsTaken::on_drop_item also errors out.

Is there a way to use mutable references in this case for messages/state change at all?
The last resort would be to kill the macros and write everything by hand.

My code: (playground does not compile because it’s missing the lib called machine)

#[macro_use]
extern crate machine;

enum State {
	TakeItem,
	DropItem,
}

machine!(
  #[derive(Clone,Debug,PartialEq)]
  enum Weight {
    IsTaken { weight: usize },
    IsDropped,
  }
);

#[derive(Clone,Debug,PartialEq)]
//pub struct DropItem; //without reference
pub struct DropItem<'a> { //this does not work
    bang: &'a mut Bang,
}

#[derive(Clone,Debug,PartialEq)]
pub struct TakeItem;

transitions!(Weight,
  [
    (IsTaken, DropItem) => IsDropped,
    (IsDropped, DropItem) => IsDropped, 
    (IsDropped, TakeItem) => IsTaken,
    (IsTaken, TakeItem) => IsTaken
  ]
);

impl IsTaken {
	pub fn on_drop_item(self, message: DropItem) -> IsDropped {
	//pub fn on_drop_item(self, message: DropItem, bang: &mut Bang) -> IsDropped {
        //message.bang can be used here...
		println!("drops weight {}", self.weight);

		IsDropped {}
	}

	pub fn on_take_item(self, _: TakeItem) -> IsTaken {
		self
	}

}

impl IsDropped {
	pub fn on_take_item(self, _: TakeItem) -> IsTaken {
		let weight = 24;//@fixme set real value here
		println!("takes weight {}", weight);

		IsTaken {
			weight
		}
	}

	pub fn on_drop_item(self, _: DropItem) -> IsDropped {
		self
	}
}

impl Weight {
	fn new() -> Self {
		Weight::IsDropped(IsDropped{})
	}

	fn step(self, state: State, bang: &mut Bang) -> Weight {
		let next = match state {
			State::TakeItem{} => {
				self.on_take_item(TakeItem)
			},
			State::DropItem => {
				self.on_drop_item(DropItem{ bang })
			},
		};
		if next == Weight::error()
		{
            //reset machine
			return next.on_drop_item(DropItem{ bang })
		}
		next
	}
}

struct Bang {}

fn main() {
	let mut t = Weight::new();
	assert_eq!(t, Weight::isdropped());

	let mut bang = Bang {};

	t = t.step(State::TakeItem, &mut bang);
	assert_eq!(t, Weight::istaken(24));

	t = t.step(State::TakeItem, &mut bang);
	assert_eq!(t, Weight::istaken(24));

	t = t.step(State::DropItem, &mut bang);
	assert_eq!(t, Weight::isdropped());

	t = t.step(State::DropItem, &mut bang);
	assert_eq!(t, Weight::isdropped());
}

Thank you

1 Like

Apparently manually implementing an enum helps.

pub struct DropItem<'a> {
	bang: &'a mut Bang,
}

pub enum WeightMessages<'a> {
	DropItem(DropItem<'a>),
	TakeItem(TakeItem),
}

This works, but I have to write everything by hand, so I guess this is something the lib could support in future. I’ll file a ticket…

2 Likes

Looking at the source code of the crate, they parse the message element for each transition as an identifier; there is no parsing of generic parameters such as lifetimes, which therefore cannot be added in the generated code.

They could add support for parsing lifetimes parameters (at least one, since 99% of the time there aren’t more), so that you could be able to write:

transitions!(Weight,
  [
    (IsTaken, DropItem<'a>) => IsDropped,
    (IsDropped, DropItem<'a>) => IsDropped, 
    (IsDropped, TakeItem) => IsTaken,
    (IsTaken, TakeItem) => IsTaken
  ]
);

or something like that.

1 Like

Thank you. Here is the issue.