0

I am trying to implement an abstraction for key-value stores in Rust. Therefore I have two traits: The IStorageSystem which is partitioned into multiple IStores that provide the actual key-value pairs. If a store is opened, the internal tree-map should be locked until the opened store goes out of scope. Further the whole access should be thread-safe:

use std::collections::BTreeMap;
use std::sync::{Arc, RwLock, RwLockReadGuard};

pub type Bytes = Vec<u8>;

pub trait IStorageSystem {
    fn open_read<'sys>(&'sys mut self, name: &str) -> Box<IReadOnlyStore<'sys> + 'sys>;
}

pub trait IReadOnlyStore<'sys> {
    fn get(&'sys self, key: &Bytes) -> Option<&'sys Bytes>;
}

type StoreData = BTreeMap<Bytes, Bytes>;

struct InMemoryStorageSystem {
    stores: BTreeMap<String, Arc<RwLock<StoreData>>>,
}

impl InMemoryStorageSystem {
    pub fn new() -> InMemoryStorageSystem {
        InMemoryStorageSystem {
            stores: BTreeMap::new(),
        }
    }
}

impl IStorageSystem for InMemoryStorageSystem {
    fn open_read<'sys>(&'sys mut self, name: &str) -> Box<IReadOnlyStore<'sys> + 'sys> {
        let store_data = self.stores.entry(name.into())
            .or_insert(Arc::new(RwLock::new(StoreData::new())));
        Box::new(ReadOnlyInMemoryStore::new(store_data))
    }
}


struct ReadOnlyInMemoryStore<'sys> {
    data: RwLockReadGuard<'sys, StoreData>,
}


impl<'sys> ReadOnlyInMemoryStore<'sys> {
    fn new(data: &'sys Arc<RwLock<StoreData>>) -> ReadOnlyInMemoryStore<'sys> {
        let locked_data = data.read().unwrap();

        ReadOnlyInMemoryStore {
            data: locked_data,
        }
    }
}


impl<'sys> IReadOnlyStore<'sys> for ReadOnlyInMemoryStore<'sys> {
    fn get(&'sys self, key: &Bytes) -> Option<&'sys Bytes> {
        self.data.get(key)
    }
}

fn main() {
    let mut storage = InMemoryStorageSystem::new();
    let store = storage.open_read("values");

    let key = String::from("dummy").into_bytes();
    let value = store.get(&key);
    match value {
        Some(ref val) => println!("Got {:?}", value),
        None => println!("Nothing found"),
    }
}

When I try to compile this code I get the following error:

error[E0597]: `*store` does not live long enough
  --> src/main.rs:69:1
   |
64 |    let value = store.get(&key);
   |                ----- borrow occurs here
...
69 | }
   | ^ `*store` dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created

How do I fix this? As far as I see, this should be working because all lifetimes are bound to the storage system which is created first and thus should be dropped last.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
andrekupka
  • 819
  • 2
  • 8
  • 6
  • 1
    You constrain lifetime in the method `IReadOnlyStore::get()` too much. [This works](https://play.rust-lang.org/?gist=7d1e143ed9c0683eff2a8bdedc4df4dc&version=stable). Take a look at [variance of structs](https://stackoverflow.com/a/45834055/2731452) too. – red75prime Aug 26 '17 at 19:43
  • Thank you very much, now its working and with the linked post I understood the problem. – andrekupka Aug 26 '17 at 19:51

0 Answers0