rust/src/bootstrap/cache.rs

93 lines
3.0 KiB
Rust
Raw Normal View History

2017-07-05 10:20:20 -06:00
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use serde_json;
use serde::{Serialize, Deserialize};
2017-07-13 11:12:57 -06:00
use std::any::TypeId;
use builder::Step;
2017-07-05 10:20:20 -06:00
use std::fmt;
use std::mem;
use std::collections::HashMap;
use std::cell::RefCell;
/// This is essentially a HashMap which allows storing any type in its input and
/// any type in its output. It is a write-once cache; values are never evicted,
/// which means that references to the value can safely be returned from the
/// get() method.
//
// FIXME: This type does not permit retrieving &Path from a PathBuf, primarily
// due to a lack of any obvious way to ensure that this is safe, but also not
// penalize other cases (e.g., deserializing u32 -> &u32, which is non-optimal).
#[derive(Debug)]
pub struct Cache(RefCell<HashMap<Key, Box<str>>>);
fn to_json<T: Serialize>(element: &T) -> String {
2017-07-13 11:12:57 -06:00
t!(serde_json::to_string(element))
2017-07-05 10:20:20 -06:00
}
fn from_json<'a, O: Deserialize<'a>>(data: &'a str) -> O {
2017-07-13 11:12:57 -06:00
t!(serde_json::from_str(data))
2017-07-05 10:20:20 -06:00
}
#[derive(Clone, PartialEq, Eq, Hash)]
2017-07-13 11:12:57 -06:00
pub struct Key(TypeId, String);
2017-07-05 10:20:20 -06:00
impl fmt::Debug for Key {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2017-07-13 11:12:57 -06:00
fmt.write_str(&format!("{:?}; ", self.0))?;
fmt.write_str(&self.1)
2017-07-05 10:20:20 -06:00
}
}
impl Cache {
pub fn new() -> Cache {
Cache(RefCell::new(HashMap::new()))
}
2017-07-13 11:12:57 -06:00
pub fn to_key<'a, K: Step<'a>>(key: &K) -> Key {
Key(TypeId::of::<K::Id>(), to_json(key))
2017-07-05 10:20:20 -06:00
}
/// Puts a value into the cache. Will panic if called more than once with
/// the same key.
///
/// Returns the internal key utilized, as an opaque structure, useful only
/// for debugging.
pub fn put<V>(&self, key: Key, value: &V)
where
V: Serialize,
{
let mut cache = self.0.borrow_mut();
let value = to_json(value);
assert!(!cache.contains_key(&key), "processing {:?} a second time", key);
// Store a boxed str so that it's location in memory never changes and
// it's safe for us to return references to it (so long as they live as
// long as us).
cache.insert(key, value.into_boxed_str());
}
pub fn get<'a, V>(&'a self, key: &Key) -> Option<V>
where
V: Deserialize<'a> + 'a,
{
let cache = self.0.borrow();
cache.get(key).map(|v| {
// Change the lifetime. This borrow is valid for as long as self lives;
// the data we're accessing will live as long as us and will be in a
// stable location, since we use Box<str>.
let v = unsafe {
mem::transmute::<&str, &'a str>(v)
};
from_json(v)
})
}
}