4

I'm using the Iron framework to create a simple endpoint. I have stateful, mutable data that the endpoint needs access to.

Here's some code that shows my intention:

extern crate iron;
extern crate mount;

use iron::{Iron, Request, Response, IronResult};
use iron::status;
use mount::Mount;

static mut s_counter: Option<Counter> = None;

struct Counter {
    pub count: u8
}

impl Counter {
    pub fn new() -> Counter {
        Counter {
            count: 0
        }
    }

    pub fn inc(&mut self) {
        self.count += 1;
    }
}

fn main() {
    unsafe { s_counter = Some(Counter::new()); }
    let mut mount = Mount::new();
    mount.mount("/api/inc", inc);
    println!("Server running on http://localhost:3000");
    Iron::new(mount).http("127.0.0.1:3000").unwrap();
}

fn inc(req: &mut Request) -> IronResult<Response> {
    let mut counter: Counter;
    unsafe {
        counter = match s_counter {
            Some(counter) => counter,
            None => { panic!("counter not initialized"); }
        };
    }
    counter.inc();
    let resp = format!("{}", counter.count);
    Ok(Response::with((status::Ok, resp)))
}

This code doesn't compile:

error: cannot move out of static item

I'm hoping that there is nicer way to do this, not involving any unsafe code or static mut. My question is, what is the idiomatic way to accomplish this?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
w.brian
  • 16,296
  • 14
  • 69
  • 118
  • 2
    I was in a Situation where i needed a static module variable that comes out of functions (glium display). My idea was to have a Outer Module with a Controlling Struct, that contains this data. The problem is somehow different, but you could still think about this idea though. – stubiklaus Sep 21 '15 at 05:52

1 Answers1

5

I'd highly recommend reading the entirety of The Rust Programming Language, especially the chapter on concurrency. The Rust community has put a lot of effort into producing high quality documentation to help people out.

In this case, I'd probably just make the Counter struct an Iron Handler. Then, I'd use an atomic variable inside the struct to hold the count without requiring mutablity:

extern crate iron;
extern crate mount;

use std::sync::atomic::{AtomicUsize, Ordering};

use iron::{Iron, Request, Response, IronResult};
use iron::status;
use mount::Mount;

struct Counter {
    count: AtomicUsize,
}

impl Counter {
    pub fn new() -> Counter {
        Counter {
            count: AtomicUsize::new(0),
        }
    }
}

fn main() {
    let mut mount = Mount::new();
    mount.mount("/api/inc", Counter::new());
    println!("Server running on http://localhost:3000");
    Iron::new(mount).http("127.0.0.1:3000").unwrap();
}

impl iron::Handler for Counter {
    fn handle(&self, _: &mut Request) -> IronResult<Response> {
        let old_count = self.count.fetch_add(1, Ordering::SeqCst);

        let resp = format!("{}", old_count);

        Ok(Response::with((status::Ok, resp)))
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • So my example was a bit simplified and I couldn't get away with an atomic variable in reality. The actual strict I'm using represents an emulated 6502. – w.brian Sep 21 '15 at 02:56
  • 2
    @w.brian Then a [`Mutex`](http://doc.rust-lang.org/std/sync/struct.Mutex.html) or a [`RwLock`](http://doc.rust-lang.org/std/sync/struct.RwLock.html) plus an [`Arc`](http://doc.rust-lang.org/std/sync/struct.Arc.html)? Or maybe a [`channel`](http://doc.rust-lang.org/std/sync/mpsc/fn.channel.html)? Two out of the three of those are documented in the book chapter I linked. – Shepmaster Sep 21 '15 at 03:00