Command pattern in Rust - rust

I'm trying to implement a command line server application in Rust.
I'd like to have a list (or hash table) of commands that I can iterate over for printing usage and looking up/executing commands.
My problem is that each Command needs mutable references to the thing the command uses to execute (such as inserting a user into a database or something). The borrow checker obviously doesn't like passing multiple mutable references around. Is there a way to do this? I started by having the execute method take in a reference to the things it needed but then I need a separate list for commands that need different things which sounds like it would get unwieldy.
Here's an example of the problem:
struct SomeStruct {
pub some_field: String,
}
impl SomeStruct {
pub fn new(field: String) -> SomeStruct {
let some_struct = SomeStruct {
some_field: field,
};
return some_struct;
}
pub fn change_field(&mut self) {
self.some_field = "Something else".to_string();
}
}
struct SomeCommand<'a> {
pub some_struct: &'a mut SomeStruct,
}
impl<'a> SomeCommand<'a> {
pub fn new(the_struct: &'a mut SomeStruct) -> SomeCommand {
let some_command = SomeCommand {
some_struct: the_struct,
};
return some_command;
}
pub fn execute(&mut self) {
self.some_struct.change_field();
}
}
fn main() {
let mut some_struct = SomeStruct::new("hey".to_string());
let some_command1 = SomeCommand::new(&mut some_struct);
// Compiler complains because I'm making another mutable binding to some_struct
let some_command2 = SomeCommand::new(&mut some_struct);
}
Is there a better way to do this?

I was trying to do the same in Rust, following examples in book Design Patterns. The problem here is that we need to maintain the generic interface of the Command trait, which means we should not design the trait such that it takes specific objects of certain types. The only solution we are left with is to store a mutable reference to the object itself within the concrete instance of object that implements Command trait. However, if we use &'a mut ..., Rust compiler will not like multiple mutable references to a single object, which means we can only ever have one Command instance for any given object we want to execute the command on, and we can only call execute once.
This can be achieved by using RefCell or Arc<Mutex<>>. I have implemented both and they both work very well. The difference is that RefCell is not thread-safe, so you cannot share the same Command object across threads if you choose to implement it in this way; whereas Arc<Mutex<>> is thread-safe.
Below is my implementation:
trait Command {
fn execute(&mut self); // Execute command.
fn is_reversible(&self) -> bool; // Undoable operation?
fn unexecute(&mut self); // Undo command.
}
// ------ Using RefCell ------
struct ChangeFontSizeCommand<'a> {
text: &'a RefCell<dyn Text>,
old_size: Option<usize>,
new_size: usize
}
impl<'a> Command for ChangeFontSizeCommand<'a> {
// Implementation... (many calls to .borrow() and .borrow_mut())
}
impl<'a> ChangeFontSizeCommand<'a> {
pub fn new(text: &'a RefCell<dyn Text>, new_size: usize) -> Self {
// Implementation...
}
}
// ------ Using Arc and Mutex ------
struct ChangeFontColorCommand {
text: Arc<Mutex<dyn Text>>,
old_color: Option<Color>,
new_color: Color
}
impl Command for ChangeFontColorCommand {
// Implementation... (many calls to .lock().unwrap())
}
impl ChangeFontColorCommand {
pub fn new(text: Arc<Mutex<dyn Text>>, new_color: Color) -> Self {
// Implementation...
}
}
Notice that in both examples, instance of RefCell or Arc<Mutex<>> has to be created outside of object initializer, we cannot pass in a mutable reference and create them inside of the command implementation struct, that would violate Rust's borrow checker rules.

I think passing the mutable reference as a parameter of execute() instead of storing it within SomeCommand is the way to go. Don't keep references living longer than they need to live.
But this is a fairly broad question: I can think of a dozen possible solutions -- it's hard to tell what's best in your case, since your example is pretty generic. Maybe we could be more specific after you told us a little more (maybe a small subset of features you want to implement).
Just looking at the title of your post: docopt is used by many Rust project -- AFAIK even cargo uses it. However, I suspect it doesn't help you with your main design problem.
Besides: in your new methods you can delete some code thanks to implicit returns. This:
pub fn new(field: String) -> SomeStruct {
let some_struct = SomeStruct {
some_field: field,
};
return some_struct;
}
... becomes this:
pub fn new(field: String) -> SomeStruct {
SomeStruct {
some_field: field,
}
}

Related

How do I call a function that requires a 'static lifetime with a variable created in main?

I've got a struct defined that has a function which defines a static lifetime:
impl MyStruct {
pub fn doSomething(&'static self) {
// Some code goes here
}
}
I'm consuming it from main like so:
fn main() {
let obj = MyStruct {};
obj.doSomething();
}
It's intended for the doSomething call to block and execute for the lifetime of the application.
I'm running into issues with the lifetime checks where it's stating that it may outlive the main function, which seems strange to me as once main is complete the application should exit.
Is there a way to achieve this?
The primary way to create a reference that has the 'static lifetime is to make the variable static. A static variable is one that can be created at compile time:
struct MyStruct;
impl MyStruct {
pub fn do_something(&'static self) {}
}
static OBJ: MyStruct = MyStruct;
fn main() {
OBJ.do_something();
}
As Rust's constant evaluation story improves, this will be more common, but it will never allow configuration at runtime.
A far less common method is to deliberately leak memory, producing a reference that will last "forever". This should be discouraged because leaking memory isn't a good thing:
fn main() {
let obj = Box::leak(Box::new(MyStruct));
obj.do_something();
}
There's also the possibility of creating a singleton:
How do I create a global, mutable singleton?
How can you make a safe static singleton in Rust?
as once main is complete the application should exit.
Perhaps, but the compiler doesn't treat main specially for lifetime purposes.
hyper requires a static runtime when running the server and processing each request.
No, it doesn't. It has a bound of : 'static, which means that any references passed in must be 'static, but you don't have to pass in a bare reference at all.
For patterns like this, the most common thing is to pass in something like an Arc. This allows sharing of the underlying resource.
pub fn do_something<F, T>(f: F)
where
F: Fn() -> T + 'static,
T: 'static,
{
// "spawn" 3 threads
f();
f();
f();
}
struct MyStruct;
static OBJ: MyStruct = MyStruct;
fn main() {
// OK
do_something(|| &OBJ);
// Not OK
let another = MyStruct;
do_something(|| &another);
// OK
use std::sync::Arc;
let shared = Arc::new(MyStruct);
do_something(move || shared.clone());
}
You can even use interior mutability if you wanted dynamic reconfiguration.
See also:
How do I use static lifetimes with threads?
The naive way to do this is with a static variable, but it will require unsafe code if you need to actually set the value inside your main function:
static mut OBJ: MyStruct = MyStruct;
fn main() {
unsafe {
OBJ = MyStruct {};
OBJ.doSomething();
}
}
It's also unsafe to do pretty much anything with a mutable static thereafter.
The much better way to do it is to let a library (lazy_static) take care of the unsafe code.
use lazy_static::lazy_static;
fn main() {
lazy_static!{
static ref OBJ: MyStruct = MyStruct {};
}
OBJ.doSomething();
}

Can I create an owned pointer to a stack object

I would like to pass a FnOnce closure to an object to be used later, but I would like to avoid any heap allocation. I can avoid heap allocation by keeping the closure on the stack. But the problem is that I can't pass a reference to the object because the FnOnce call_once consumes the closure. So I need to pass an owned pointer (e.g. Box) without heap allocation.
Is this possible? What I'd like to do is this:
fn main() {
let mut scheduler = NoHeapScheduler();
// allocate the task on the stack
let task = move ||;
// somehow pass ownership of the closure, while keeping it allocated on the stack.
scheduler.add_task(StaticBox::new(task));
schedule.run();
}
As far as I know this should be safe as long as the scheduler doesn't outlive the task. Is there any way to make this happen?
Can I create an owned pointer to a stack object?
No. This is non-sensical actually, since by definition a stack object is owned by the stack, so it cannot also be owned by something else.
So I need to pass an owned pointer (e.g. Box) without heap allocation.
There are other owned pointers than Box.
At the moment, I know of none without a heap allocation, but there is little reason it cannot be done.
I envision a InlineFnOnceBox<S: Default, R, A> used as InlineFnOnceBox<[u8; 48], (), ()> in this case, which would contain both the array itself, used as backing storage, plus a virtual pointer to the FnOnce<A -> R> v-table for the type instantiated.
It requires some care (and unsafe code) to instantiate, but otherwise seems feasible.
Can I create an owned pointer to a stack object?
No, but you can simply move the stack object into your scheduler. Your scheduler will increase in size with every closure you schedule, but it will be completely self contained an can even be moved around.
The basic idea is that your Scheduler becomes a kind of singly linked list:
pub trait Scheduler: Sized {
fn run(self);
}
pub struct NoHeapScheduler<F: FnOnce(), T: Scheduler> {
inner: T,
f: F,
}
impl<F: FnOnce(), T: Scheduler> Scheduler for NoHeapScheduler<F, T> {
fn run(self) {
self.inner.run();
(self.f)()
}
}
The Scheduler trait is here to break the recursion chain in the NoHeapScheduler (Otherwise we'd need a feature like variadic generics).
To terminate the chain we also implement Scheduler for some no-op type, e.g. ():
impl Scheduler for () {
fn run(self) {}
}
Now the only thing left is a way to add new closures.
impl<F: FnOnce(), T: Scheduler> NoHeapScheduler<F, T> {
fn add_task<F2: FnOnce()>(self, f: F2) -> NoHeapScheduler<F2, Self> {
NoHeapScheduler {
inner: self,
f: f,
}
}
}
This method moves The current scheduler into a new scheduler and adds the scheduled closure.
You can use this function like so:
let scheduler = scheduler.add_task(task);
Fully working example in the playground
As stated, the answer to the question is "no".
If you pass ownership of the closure, you have to by definition move it into the owner (otherwise what you've got is a reference). You can do that if you've only got one callback using a generic type:
pub struct NoHeapScheduler<F:FnOnce()> {
f: Option<F>,
}
impl<F:FnOnce()> NoHeapScheduler<F> {
pub fn add_task(&mut self, f: F) {
self.f = Some(f);
}
pub fn run(&mut self) {
let f = self.f.take().unwrap();
f()
}
}
fn main() {
let mut scheduler = NoHeapScheduler{ f: None };
let task = move || {};
scheduler.add_task(task);
scheduler.run();
}
Playground
However you'd run into problems adding more than one closure, since they all have different types.
If you're willing to allow allocations and an unstable feature on the nightly compiler, you could use FnBox. This is like FnOnce but works with Box:
#![feature(fnbox)]
use std::boxed::FnBox;
pub struct NoHeapScheduler {
v: Vec<Box<FnBox()>>,
}
impl NoHeapScheduler {
pub fn add_task(&mut self, f: Box<FnBox()>) {
self.v.push(f);
}
pub fn run(&mut self) {
for f in self.v.drain(0..) {
f();
}
}
}
fn main() {
let mut scheduler = NoHeapScheduler{ v: Vec::new() };
let task = move || {println!("Hello,"); };
let other_task = move || {println!("world!"); };
scheduler.add_task(Box::new(task));
scheduler.add_task(Box::new(other_task));
scheduler.run();
}
Playground
I can use an Option to do this. I can keep the Option on the stack and pass a mutable reference around, and then when I'm ready to consume the closure I can use Option::take to take ownership of the closure and consume it.
To handle different implementations of FnOnce, I can lift this out into a trait and use trait objects:
trait Callable {
fn call(&mut self);
}
impl<F: FnOnce()> Callable for Option<F> {
fn call(&mut self) {
if let Some(func) = self.take() {
func();
}
}
}
Then I can pass around trait objects that live on the stack but can be consumed by having the reference.

Same object with different API faces at compile time?

I have an object that can be in either of two modes: a source or a sink. It is always in one of them and it is always known at compile time (when passed the object you know if you are going to read or write to it obviously).
I can put all the methods on the same object, and just assume I won't be called improperly or error when I do, or I was thinking I could be make two
tuple structs of the single underlying object and attach the methods to those tuple structs instead. The methods are almost entirely disjoint.
It is kind of abusing the fact that both tuple structs have the same layout and there is zero overhead for the casts and tuple storage.
Think of this similar to the Java ByteBuffer and related classes where you write then flip then read then flip back and write more. Except this would catch errors in usage.
However, it does seem a little unusual and might be overly confusing for such a small problem. And it seems like there is a better way to do this -- only requirement is zero overhead so no dynamic dispatch.
https://play.rust-lang.org/?gist=280d2ec2548e4f38e305&version=stable
#[derive(Debug)]
struct Underlying {
a: u32,
b: u32,
}
#[derive(Debug)]
struct FaceA(Underlying);
impl FaceA {
fn make() -> FaceA { FaceA(Underlying{a:1,b:2}) }
fn doa(&self) { println!("FaceA do A {:?}", *self); }
fn dou(&self) { println!("FaceA do U {:?}", *self); }
fn tob(&self) -> &FaceB { unsafe{std::mem::transmute::<&FaceA,&FaceB>(self)} }
}
#[derive(Debug)]
struct FaceB(Underlying);
impl FaceB {
fn dob(&self) { println!("FaceB do B {:?}", *self); }
fn dou(&self) { println!("FaceB do U {:?}", *self); }
fn toa(&self) -> &FaceA { unsafe{std::mem::transmute::<&FaceB,&FaceA>(self)} }
}
fn main() {
let a = FaceA::make();
a.doa();
a.dou();
let b = a.tob();
b.dob();
b.dou();
let aa = b.toa();
aa.doa();
aa.dou();
}
First of all, it seems like you don't understand how ownership works in Rust; you may want to read the Ownership chapter of the Rust Book. Specifically, the way you keep re-aliasing the original FaceA is how you would specifically enable the very thing you say you want to avoid. Also, all the borrows are immutable, so it's not clear how you intend to do any sort of mutation.
As such, I've written a new example from scratch that involves going between two types with disjoint interfaces (view on playpen).
#[derive(Debug)]
pub struct Inner {
pub value: i32,
}
impl Inner {
pub fn new(value: i32) -> Self {
Inner {
value: value,
}
}
}
#[derive(Debug)]
pub struct Upper(Inner);
impl Upper {
pub fn new(inner: Inner) -> Self {
Upper(inner)
}
pub fn into_downer(self) -> Downer {
Downer::new(self.0)
}
pub fn up(&mut self) {
self.0.value += 1;
}
}
#[derive(Debug)]
pub struct Downer(Inner);
impl Downer {
pub fn new(inner: Inner) -> Self {
Downer(inner)
}
pub fn into_upper(self) -> Upper {
Upper::new(self.0)
}
pub fn down(&mut self) {
self.0.value -= 1;
}
}
fn main() {
let mut a = Upper::new(Inner::new(0));
a.up();
let mut b = a.into_downer();
b.down();
b.down();
b.down();
let mut c = b.into_upper();
c.up();
show_i32(c.0.value);
}
#[inline(never)]
fn show_i32(v: i32) {
println!("v: {:?}", v);
}
Here, the into_upper and into_downer methods consume the subject value, preventing anyone from using it afterwards (try accessing a after the call to a.into_downer()).
This should not be particularly inefficient; there is no heap allocation going on here, and Rust is pretty good at moving values around efficiently. If you're curious, this is what the main function compiles down to with optimisations enabled:
mov edi, -1
jmp _ZN8show_i3220h2a10d619fa41d919UdaE
It literally inlines the entire program (save for the show function that I specifically told it not to inline). Unless profiling shows this to be a serious performance problem, I wouldn't worry about it.

How do I pass Rc<RefCell<Box<MyStruct>>> to a function accepting Rc<RefCell<Box<dyn MyTrait>>>?

I have originally asked this question here, but it was marked as duplicate, although it duplicates only a part of it in my opinion, so I have created a more specific one:
Consider the following code:
use std::rc::Rc;
trait MyTrait {
fn trait_func(&self);
}
struct MyStruct1;
impl MyStruct1 {
fn my_fn(&self) {
// do something
}
}
impl MyTrait for MyStruct1 {
fn trait_func(&self) {
// do something
}
}
fn my_trait_fn(t: Rc<dyn MyTrait>) {
t.trait_func();
}
fn main() {
let my_str: Rc<MyStruct1> = Rc::new(MyStruct1);
my_trait_fn(my_str.clone());
my_str.my_fn();
}
This code works fine. Now I want to change the definition of trait_func to accept a &mut self, but it won't work as Rc works with immutable data only. The solution I use is to wrap MyTrait into RefCell:
use std::cell::RefCell;
fn my_trait_fn(t: Rc<RefCell<Box<dyn MyTrait>>>) {
t.borrow_mut().trait_func();
}
fn main() {
let my_str: Rc<RefCell<Box<MyStruct1>>> = Rc::new(RefCell::new(Box::new(MyStruct1)));
my_trait_fn(my_str.clone());
my_str.my_fn();
}
When I compile it I get an error:
error[E0308]: mismatched types
--> src/main.rs:27:17
|
27 | my_trait_fn(my_str.clone());
| ^^^^^^^^^^^^^^ expected trait MyTrait, found struct `MyStruct1`
|
= note: expected type `std::rc::Rc<std::cell::RefCell<std::boxed::Box<dyn MyTrait + 'static>>>`
found type `std::rc::Rc<std::cell::RefCell<std::boxed::Box<MyStruct1>>>`
= help: here are some functions which might fulfill your needs:
- .into_inner()
What's the best way to go around this problem?
(An older revision of this answer essentially advised to clone the underlying struct and put it in a new Rc<RefCell<Box<MyTrait>> object; this was necessary at the time on stable Rust, but since not long after that time, Rc<RefCell<MyStruct>> will coerce to Rc<RefCell<MyTrait>> without trouble.)
Drop the Box<> wrapping, and you can coerce Rc<RefCell<MyStruct>> to Rc<RefCell<MyTrait>> freely and easily. Recalling that cloning an Rc<T> just produces another Rc<T>, increasing the refcount by one, you can do something like this:
use std::rc::Rc;
use std::cell::RefCell;
trait MyTrait {
fn trait_func(&self);
}
#[derive(Clone)]
struct MyStruct1;
impl MyStruct1 {
fn my_fn(&self) {
// do something
}
}
impl MyTrait for MyStruct1 {
fn trait_func(&self) {
// do something
}
}
fn my_trait_fn(t: Rc<RefCell<MyTrait>>) {
t.borrow_mut().trait_func();
}
fn main() {
// (The type annotation is not necessary here, but helps explain it.
// If the `my_str.borrow().my_fn()` line was missing, it would actually
// be of type Rc<RefCell<MyTrait>> instead of Rc<RefCell<MyStruct1>>,
// essentially doing the coercion one step earlier.)
let my_str: Rc<RefCell<MyStruct1>> = Rc::new(RefCell::new(MyStruct1));
my_trait_fn(my_str.clone());
my_str.borrow().my_fn();
}
As a general rule, see if you can make things take the contained value by reference, ideally even generically—fn my_trait_fn<T: MyTrait>(t: &T) and similar, which can typically be called as my_str.borrow() with automatic referencing and dereferencing taking care of the rest—rather than the whole Rc<RefCell<MyTrait>> thing.

Unable to hold/pass reference of parent to the composition object

In C++ it would something like struct A is composed of struct B and some function of B takes a pointer to the parent object A. So function of A calling that function of B will simply pass the this pointer to it. I'm trying this in Rust but failing to get it to work - this is what I want to achieve:
struct A<Type: T> {
composition: Type,
value: usize,
}
impl<Type> A<Type> where Type: T {
fn new(obj: Type) -> A<Type> {
A {
composition: obj,
value: 999,
}
}
fn f(&mut self) {
println!("Value: {:?}", self.value);
}
fn call(&mut self) {
self.composition.f(&mut self);
}
}
trait T {
fn f(&mut self, &mut A<Self>);
}
struct B {
value: usize,
}
impl B {
fn new() -> B {
B { value: 0, }
}
}
impl T for B {
fn f(&mut self, parent: &mut A<B>) {
println!("B::f");
parent.f();
}
}
fn main() {
let objA = A::new(B::new());
// I want call sequence -> A::call() -> B::f() -> A::f()
objA.call();
}
Note that i require mutability in all the functions although in example above it might seem that &mut self in most function parameters don't make much sense. How do it do this in Rust?
This cannot work because you're violating mutable aliasing requirements - you're trying to mutably borrow A and its substructure at the same time:
self.composition.f(self);
// roughtly equivalent to:
let c = &mut self.composition; // borrow substructure
c.f(self /* borrow self */);
(I've removed explicit &mut self because it is incorrect (as it gives you &mut &mut A<...>, but it does not change the whole picture at all.)
This is a natural error in Rust framework. Suppose that f implementation on this particular composition X rewrites composition field on the passed object:
impl T for X {
fn f(&mut self, a: &mut A<X>) {
a.composition = create_x_somehow();
}
}
And suddenly the object this method is called on is destroyed, and self is invalidated!
Naturally, the compiler prevents you from doing this even if you know that you don't modify composition, because such kind of knowledge cannot be encoded statically (especially given that this is a trait method which can be implemented by anyone having access to your trait).
You have essentially two choices in such situations:
reformulate the problem so it does not require such architecture anymore, or
use special language/library constructs to work around such static checks.
The second point is about using such things as Cell/RefCell (they are safe, i.e. don't require unsafe blocks, but they can panic at runtime - probably these can work in your case) or, if nothing else helps, dropping to raw pointers and unsafe code. But, frankly, the first option usually is better: if you design your code based on ownership semantics and aliasing rules enforced by the compiler, almost always the resulting architecture would be of much better quality.

Resources