diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-04-28 20:36:08 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-05-07 23:43:39 -0700 |
| commit | ab92ea526d455b402efbccc7160c8aec0237c88f (patch) | |
| tree | 92e748f3e3496a48ac68dd290a0a08aa342740a1 | |
| parent | ef6daf9935da103f1b915a5c9904794da79b0b60 (diff) | |
| download | rust-ab92ea526d455b402efbccc7160c8aec0237c88f.tar.gz rust-ab92ea526d455b402efbccc7160c8aec0237c88f.zip | |
std: Modernize the local_data api
This commit brings the local_data api up to modern rust standards with a few key improvements: * The `pop` and `set` methods have been combined into one method, `replace` * The `get_mut` method has been removed. All interior mutability should be done through `RefCell`. * All functionality is now exposed as a method on the keys themselves. Instead of importing std::local_data, you now use "key.replace()" and "key.get()". * All closures have been removed in favor of RAII functionality. This means that get() and get_mut() no long require closures, but rather return Option<SmartPointer> where the smart pointer takes care of relinquishing the borrow and also implements the necessary Deref traits * The modify() function was removed to cut the local_data interface down to its bare essentials (similarly to how RefCell removed set/get). [breaking-change]
| -rw-r--r-- | src/libcollections/hashmap.rs | 70 | ||||
| -rw-r--r-- | src/liblog/lib.rs | 9 | ||||
| -rw-r--r-- | src/librand/lib.rs | 18 | ||||
| -rw-r--r-- | src/librustc/middle/trans/base.rs | 35 | ||||
| -rw-r--r-- | src/librustc/util/common.rs | 8 | ||||
| -rw-r--r-- | src/librustdoc/clean.rs | 15 | ||||
| -rw-r--r-- | src/librustdoc/core.rs | 3 | ||||
| -rw-r--r-- | src/librustdoc/html/format.rs | 129 | ||||
| -rw-r--r-- | src/librustdoc/html/markdown.rs | 23 | ||||
| -rw-r--r-- | src/librustdoc/html/render.rs | 154 | ||||
| -rw-r--r-- | src/librustdoc/lib.rs | 3 | ||||
| -rw-r--r-- | src/librustdoc/passes.rs | 9 | ||||
| -rw-r--r-- | src/librustdoc/test.rs | 3 | ||||
| -rw-r--r-- | src/libstd/local_data.rs | 537 | ||||
| -rw-r--r-- | src/libstd/macros.rs | 6 | ||||
| -rw-r--r-- | src/libstd/rt/task.rs | 9 | ||||
| -rw-r--r-- | src/libstd/slice.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/ext/mtwt.rs | 39 | ||||
| -rw-r--r-- | src/libsyntax/parse/token.rs | 7 | ||||
| -rw-r--r-- | src/test/auxiliary/macro_crate_outlive_expansion_phase.rs | 3 | ||||
| -rw-r--r-- | src/test/compile-fail/core-tls-store-pointer.rs | 2 | ||||
| -rw-r--r-- | src/test/compile-fail/macro-local-data-key-priv.rs | 4 | ||||
| -rw-r--r-- | src/test/run-pass/macro-local-data-key.rs | 14 |
23 files changed, 442 insertions, 659 deletions
diff --git a/src/libcollections/hashmap.rs b/src/libcollections/hashmap.rs index ce8e1474ee5..2d1de87fe06 100644 --- a/src/libcollections/hashmap.rs +++ b/src/libcollections/hashmap.rs @@ -1617,8 +1617,7 @@ mod test_map { use std::cmp::Equiv; use std::hash::Hash; use std::iter::{Iterator,range_inclusive,range_step_inclusive}; - use std::local_data; - use std::vec; + use std::cell::RefCell; struct KindaIntLike(int); @@ -1657,7 +1656,7 @@ mod test_map { assert_eq!(*m.find(&2).unwrap(), 4); } - local_data_key!(drop_vector: vec::Vec<int>) + local_data_key!(drop_vector: RefCell<Vec<int>>) #[deriving(Hash, Eq, TotalEq)] struct Dropable { @@ -1667,8 +1666,8 @@ mod test_map { impl Dropable { fn new(k: uint) -> Dropable { - local_data::get_mut(drop_vector, - |v| { v.unwrap().as_mut_slice()[k] += 1; }); + let v = drop_vector.get().unwrap(); + v.borrow_mut().as_mut_slice()[k] += 1; Dropable { k: k } } @@ -1676,23 +1675,23 @@ mod test_map { impl Drop for Dropable { fn drop(&mut self) { - local_data::get_mut(drop_vector, |v| - { v.unwrap().as_mut_slice()[self.k] -= 1; }); + let v = drop_vector.get().unwrap(); + v.borrow_mut().as_mut_slice()[self.k] -= 1; } } #[test] fn test_drops() { - local_data::set(drop_vector, vec::Vec::from_elem(200, 0)); + drop_vector.replace(Some(RefCell::new(Vec::from_elem(200, 0)))); { let mut m = HashMap::new(); - local_data::get(drop_vector, |v| { - for i in range(0u, 200) { - assert_eq!(v.unwrap().as_slice()[i], 0); - } - }); + let v = drop_vector.get().unwrap(); + for i in range(0u, 200) { + assert_eq!(v.borrow().as_slice()[i], 0); + } + drop(v); for i in range(0u, 100) { let d1 = Dropable::new(i); @@ -1700,11 +1699,11 @@ mod test_map { m.insert(d1, d2); } - local_data::get(drop_vector, |v| { - for i in range(0u, 200) { - assert_eq!(v.unwrap().as_slice()[i], 1); - } - }); + let v = drop_vector.get().unwrap(); + for i in range(0u, 200) { + assert_eq!(v.borrow().as_slice()[i], 1); + } + drop(v); for i in range(0u, 50) { let k = Dropable::new(i); @@ -1712,30 +1711,27 @@ mod test_map { assert!(v.is_some()); - local_data::get(drop_vector, |v| { - assert_eq!(v.unwrap().as_slice()[i], 1); - assert_eq!(v.unwrap().as_slice()[i+100], 1); - }); + let v = drop_vector.get().unwrap(); + assert_eq!(v.borrow().as_slice()[i], 1); + assert_eq!(v.borrow().as_slice()[i+100], 1); } - local_data::get(drop_vector, |v| { - for i in range(0u, 50) { - assert_eq!(v.unwrap().as_slice()[i], 0); - assert_eq!(v.unwrap().as_slice()[i+100], 0); - } + let v = drop_vector.get().unwrap(); + for i in range(0u, 50) { + assert_eq!(v.borrow().as_slice()[i], 0); + assert_eq!(v.borrow().as_slice()[i+100], 0); + } - for i in range(50u, 100) { - assert_eq!(v.unwrap().as_slice()[i], 1); - assert_eq!(v.unwrap().as_slice()[i+100], 1); - } - }); + for i in range(50u, 100) { + assert_eq!(v.borrow().as_slice()[i], 1); + assert_eq!(v.borrow().as_slice()[i+100], 1); + } } - local_data::get(drop_vector, |v| { - for i in range(0u, 200) { - assert_eq!(v.unwrap().as_slice()[i], 0); - } - }); + let v = drop_vector.get().unwrap(); + for i in range(0u, 200) { + assert_eq!(v.borrow().as_slice()[i], 0); + } } #[test] diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 035a81f4143..09e9cd83f3d 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -122,7 +122,6 @@ use std::cast; use std::fmt; use std::io::LineBufferedWriter; use std::io; -use std::local_data; use std::os; use std::rt; use std::slice; @@ -228,7 +227,7 @@ pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) { // Completely remove the local logger from TLS in case anyone attempts to // frob the slot while we're doing the logging. This will destroy any logger // set during logging. - let mut logger = local_data::pop(local_logger).unwrap_or_else(|| { + let mut logger = local_logger.replace(None).unwrap_or_else(|| { box DefaultLogger { handle: io::stderr() } as Box<Logger:Send> }); logger.log(&LogRecord { @@ -238,7 +237,7 @@ pub fn log(level: u32, loc: &'static LogLocation, args: &fmt::Arguments) { module_path: loc.module_path, line: loc.line, }); - local_data::set(local_logger, logger); + local_logger.replace(Some(logger)); } /// Getter for the global log level. This is a function so that it can be called @@ -250,9 +249,7 @@ pub fn log_level() -> u32 { unsafe { LOG_LEVEL } } /// Replaces the task-local logger with the specified logger, returning the old /// logger. pub fn set_logger(logger: Box<Logger:Send>) -> Option<Box<Logger:Send>> { - let prev = local_data::pop(local_logger); - local_data::set(local_logger, logger); - return prev; + local_logger.replace(Some(logger)) } /// A LogRecord is created by the logging macros, and passed as the only diff --git a/src/librand/lib.rs b/src/librand/lib.rs index d5a2c163a90..cb27f2f0ff8 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -79,7 +79,6 @@ println!("{:?}", tuple_ptr) use std::cast; use std::io::IoResult; use std::kinds::marker; -use std::local_data; use std::strbuf::StrBuf; pub use isaac::{IsaacRng, Isaac64Rng}; @@ -581,9 +580,6 @@ pub struct TaskRng { marker: marker::NoSend, } -// used to make space in TLS for a random number generator -local_data_key!(TASK_RNG_KEY: Box<TaskRngInner>) - /// Retrieve the lazily-initialized task-local random number /// generator, seeded by the system. Intended to be used in method /// chaining style, e.g. `task_rng().gen::<int>()`. @@ -596,7 +592,10 @@ local_data_key!(TASK_RNG_KEY: Box<TaskRngInner>) /// the same sequence always. If absolute consistency is required, /// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. pub fn task_rng() -> TaskRng { - local_data::get_mut(TASK_RNG_KEY, |rng| match rng { + // used to make space in TLS for a random number generator + local_data_key!(TASK_RNG_KEY: Box<TaskRngInner>) + + match TASK_RNG_KEY.get() { None => { let r = match StdRng::new() { Ok(r) => r, @@ -607,12 +606,15 @@ pub fn task_rng() -> TaskRng { TaskRngReseeder); let ptr = &mut *rng as *mut TaskRngInner; - local_data::set(TASK_RNG_KEY, rng); + TASK_RNG_KEY.replace(Some(rng)); TaskRng { rng: ptr, marker: marker::NoSend } } - Some(rng) => TaskRng { rng: &mut **rng, marker: marker::NoSend } - }) + Some(rng) => TaskRng { + rng: &**rng as *_ as *mut TaskRngInner, + marker: marker::NoSend + } + } } impl Rng for TaskRng { diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index c002c47d35d..7b342b7cb95 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -74,7 +74,6 @@ use arena::TypedArena; use libc::c_uint; use std::c_str::ToCStr; use std::cell::{Cell, RefCell}; -use std::local_data; use std::rc::Rc; use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic}; use syntax::ast_util::{local_def, is_local}; @@ -88,19 +87,17 @@ use syntax::{ast, ast_util, ast_map}; use time; -local_data_key!(task_local_insn_key: Vec<&'static str> ) +local_data_key!(task_local_insn_key: RefCell<Vec<&'static str>>) pub fn with_insn_ctxt(blk: |&[&'static str]|) { - local_data::get(task_local_insn_key, |c| { - match c { - Some(ctx) => blk(ctx.as_slice()), - None => () - } - }) + match task_local_insn_key.get() { + Some(ctx) => blk(ctx.borrow().as_slice()), + None => () + } } pub fn init_insn_ctxt() { - local_data::set(task_local_insn_key, Vec::new()); + task_local_insn_key.replace(Some(RefCell::new(Vec::new()))); } pub struct _InsnCtxt { _x: () } @@ -108,23 +105,19 @@ pub struct _InsnCtxt { _x: () } #[unsafe_destructor] impl Drop for _InsnCtxt { fn drop(&mut self) { - local_data::modify(task_local_insn_key, |c| { - c.map(|mut ctx| { - ctx.pop(); - ctx - }) - }) + match task_local_insn_key.get() { + Some(ctx) => { ctx.borrow_mut().pop(); } + None => {} + } } } pub fn push_ctxt(s: &'static str) -> _InsnCtxt { debug!("new InsnCtxt: {}", s); - local_data::modify(task_local_insn_key, |c| { - c.map(|mut ctx| { - ctx.push(s); - ctx - }) - }); + match task_local_insn_key.get() { + Some(ctx) => ctx.borrow_mut().push(s), + None => {} + } _InsnCtxt { _x: () } } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 0d14c036ba7..5ddae0c1bfe 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -14,23 +14,21 @@ use syntax::ast; use syntax::visit; use syntax::visit::Visitor; -use std::local_data; - use time; pub fn time<T, U>(do_it: bool, what: &str, u: U, f: |U| -> T) -> T { local_data_key!(depth: uint); if !do_it { return f(u); } - let old = local_data::get(depth, |d| d.map(|a| *a).unwrap_or(0)); - local_data::set(depth, old + 1); + let old = depth.get().map(|d| *d).unwrap_or(0); + depth.replace(Some(old + 1)); let start = time::precise_time_s(); let rv = f(u); let end = time::precise_time_s(); println!("{}time: {:3.3f} s\t{}", " ".repeat(old), end - start, what); - local_data::set(depth, old); + depth.replace(Some(old)); rv } diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 79fc0fbeada..be0fd85525d 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -26,7 +26,6 @@ use rustc::metadata::cstore; use rustc::metadata::csearch; use rustc::metadata::decoder; -use std::local_data; use std::strbuf::StrBuf; use core; @@ -77,7 +76,7 @@ pub struct Crate { impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> { fn clean(&self) -> Crate { - let cx = local_data::get(super::ctxtkey, |x| *x.unwrap()); + let cx = super::ctxtkey.get().unwrap(); let mut externs = Vec::new(); cx.sess().cstore.iter_crate_data(|n, meta| { @@ -251,7 +250,7 @@ impl Clean<Item> for doctree::Module { // determine if we should display the inner contents or // the outer `mod` item for the source code. let where = { - let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap()); + let ctxt = super::ctxtkey.get().unwrap(); let cm = ctxt.sess().codemap(); let outer = cm.lookup_char_pos(self.where_outer.lo); let inner = cm.lookup_char_pos(self.where_inner.lo); @@ -726,7 +725,7 @@ impl Clean<Type> for ast::Ty { fn clean(&self) -> Type { use syntax::ast::*; debug!("cleaning type `{:?}`", self); - let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap()); + let ctxt = super::ctxtkey.get().unwrap(); let codemap = ctxt.sess().codemap(); debug!("span corresponds to `{}`", codemap.span_to_str(self.span)); match self.node { @@ -909,7 +908,7 @@ pub struct Span { impl Clean<Span> for syntax::codemap::Span { fn clean(&self) -> Span { - let ctxt = local_data::get(super::ctxtkey, |x| *x.unwrap()); + let ctxt = super::ctxtkey.get().unwrap(); let cm = ctxt.sess().codemap(); let filename = cm.span_to_filename(*self); let lo = cm.lookup_char_pos(self.lo); @@ -1237,7 +1236,7 @@ trait ToSource { impl ToSource for syntax::codemap::Span { fn to_src(&self) -> ~str { debug!("converting span {:?} to snippet", self.clean()); - let ctxt = local_data::get(super::ctxtkey, |x| x.unwrap().clone()); + let ctxt = super::ctxtkey.get().unwrap(); let cm = ctxt.sess().codemap().clone(); let sn = match cm.span_to_snippet(*self) { Some(x) => x, @@ -1292,7 +1291,7 @@ fn name_from_pat(p: &ast::Pat) -> ~str { /// Given a Type, resolve it using the def_map fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound> >, id: ast::NodeId) -> Type { - let cx = local_data::get(super::ctxtkey, |x| *x.unwrap()); + let cx = super::ctxtkey.get().unwrap(); let tycx = match cx.maybe_typed { core::Typed(ref tycx) => tycx, // If we're extracting tests, this return value doesn't matter. @@ -1351,7 +1350,7 @@ fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource { } fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> { - let cx = local_data::get(super::ctxtkey, |x| *x.unwrap()); + let cx = super::ctxtkey.get().unwrap(); match cx.maybe_typed { core::Typed(ref tcx) => { tcx.def_map.borrow().find(&id).map(|&d| ast_util::def_id_of_def(d)) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 9f89da563cc..1916e053e98 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -20,7 +20,6 @@ use syntax; use std::cell::RefCell; use std::os; -use std::local_data; use collections::HashSet; use visit_ast::RustdocVisitor; @@ -109,7 +108,7 @@ pub fn run_core(libs: HashSet<Path>, cfgs: Vec<~str>, path: &Path) -> (clean::Crate, CrateAnalysis) { let (ctxt, analysis) = get_ast_and_resolve(path, libs, cfgs); let ctxt = @ctxt; - local_data::set(super::ctxtkey, ctxt); + super::ctxtkey.replace(Some(ctxt)); let krate = { let mut v = RustdocVisitor::new(ctxt, Some(&analysis)); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 1e2f89659cd..223f9341b73 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -17,7 +17,6 @@ use std::fmt; use std::io; -use std::local_data; use std::strbuf::StrBuf; use syntax::ast; @@ -206,78 +205,72 @@ fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool, generics.push_str(">"); } - // Did someone say rightward-drift? - local_data::get(current_location_key, |loc| { - let loc = loc.unwrap(); - - local_data::get(cache_key, |cache| { - let cache = cache.unwrap(); - let abs_root = root(&**cache, loc.as_slice()); - let rel_root = match path.segments.get(0).name.as_slice() { - "self" => Some("./".to_owned()), - _ => None, - }; - - if print_all { - let amt = path.segments.len() - 1; - match rel_root { - Some(root) => { - let mut root = StrBuf::from_str(root); - for seg in path.segments.slice_to(amt).iter() { - if "super" == seg.name || "self" == seg.name { - try!(write!(w, "{}::", seg.name)); - } else { - root.push_str(seg.name); - root.push_str("/"); - try!(write!(w, "<a class='mod' - href='{}index.html'>{}</a>::", - root.as_slice(), - seg.name)); - } - } - } - None => { - for seg in path.segments.slice_to(amt).iter() { - try!(write!(w, "{}::", seg.name)); - } + let loc = current_location_key.get().unwrap(); + let cache = cache_key.get().unwrap(); + let abs_root = root(&**cache, loc.as_slice()); + let rel_root = match path.segments.get(0).name.as_slice() { + "self" => Some("./".to_owned()), + _ => None, + }; + + if print_all { + let amt = path.segments.len() - 1; + match rel_root { + Some(root) => { + let mut root = StrBuf::from_str(root); + for seg in path.segments.slice_to(amt).iter() { + if "super" == seg.name || "self" == seg.name { + try!(write!(w, "{}::", seg.name)); + } else { + root.push_str(seg.name); + root.push_str("/"); + try!(write!(w, "<a class='mod' + href='{}index.html'>{}</a>::", + root.as_slice(), + seg.name)); } } } - - match info(&**cache) { - // This is a documented path, link to it! - Some((ref fqp, shortty)) if abs_root.is_some() => { - let mut url = StrBuf::from_str(abs_root.unwrap()); - let to_link = fqp.slice_to(fqp.len() - 1); - for component in to_link.iter() { - url.push_str(*component); - url.push_str("/"); - } - match shortty { - item_type::Module => { - url.push_str(*fqp.last().unwrap()); - url.push_str("/index.html"); - } - _ => { - url.push_str(shortty.to_static_str()); - url.push_str("."); - url.push_str(*fqp.last().unwrap()); - url.push_str(".html"); - } - } - - try!(write!(w, "<a class='{}' href='{}' title='{}'>{}</a>", - shortty, url, fqp.connect("::"), last.name)); + None => { + for seg in path.segments.slice_to(amt).iter() { + try!(write!(w, "{}::", seg.name)); } + } + } + } + match info(&**cache) { + // This is a documented path, link to it! + Some((ref fqp, shortty)) if abs_root.is_some() => { + let mut url = StrBuf::from_str(abs_root.unwrap()); + let to_link = fqp.slice_to(fqp.len() - 1); + for component in to_link.iter() { + url.push_str(*component); + url.push_str("/"); + } + match shortty { + item_type::Module => { + url.push_str(*fqp.last().unwrap()); + url.push_str("/index.html"); + } _ => { - try!(write!(w, "{}", last.name)); + url.push_str(shortty.to_static_str()); + url.push_str("."); + url.push_str(*fqp.last().unwrap()); + url.push_str(".html"); } } - try!(write!(w, "{}", generics.as_slice())); - Ok(()) - }) - }) + + try!(write!(w, "<a class='{}' href='{}' title='{}'>{}</a>", + shortty, url, fqp.connect("::"), last.name)); + } + + _ => { + try!(write!(w, "{}", last.name)); + } + } + try!(write!(w, "{}", generics.as_slice())); + Ok(()) } /// Helper to render type parameters @@ -302,10 +295,8 @@ impl fmt::Show for clean::Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { clean::TyParamBinder(id) | clean::Generic(id) => { - local_data::get(cache_key, |cache| { - let m = cache.unwrap(); - f.buf.write(m.typarams.get(&id).as_bytes()) - }) + let m = cache_key.get().unwrap(); + f.buf.write(m.typarams.get(&id).as_bytes()) } clean::ResolvedPath{id, typarams: ref tp, path: ref path} => { try!(resolved_path(f.buf, id, path, false)); diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 9d6b0ec5517..0141df34a6c 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -27,11 +27,11 @@ #![allow(non_camel_case_types)] use libc; +use std::cell::RefCell; use std::fmt; use std::io; -use std::local_data; -use std::str; use std::slice; +use std::str; use collections::HashMap; use html::toc::TocBuilder; @@ -139,7 +139,7 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> { } } -local_data_key!(used_header_map: HashMap<~str, uint>) +local_data_key!(used_header_map: RefCell<HashMap<~str, uint>>) pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result { extern fn block(ob: *mut hoedown_buffer, text: *hoedown_buffer, @@ -216,15 +216,12 @@ pub fn render(w: &mut io::Writer, s: &str, print_toc: bool) -> fmt::Result { let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) }; // Make sure our hyphenated ID is unique for this page - let id = local_data::get_mut(used_header_map, |map| { - let map = map.unwrap(); - match map.find_mut(&id) { - None => {} - Some(a) => { *a += 1; return format!("{}-{}", id, *a - 1) } - } - map.insert(id.clone(), 1); - id.clone() - }); + let map = used_header_map.get().unwrap(); + let id = match map.borrow_mut().find_mut(&id) { + None => id, + Some(a) => { *a += 1; format!("{}-{}", id, *a - 1) } + }; + map.borrow_mut().insert(id.clone(), 1); let sec = match opaque.toc_builder { Some(ref mut builder) => { @@ -348,7 +345,7 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) { /// used at the beginning of rendering an entire HTML page to reset from the /// previous state (if any). pub fn reset_headers() { - local_data::set(used_header_map, HashMap::new()) + used_header_map.replace(Some(RefCell::new(HashMap::new()))); } impl<'a> fmt::Show for Markdown<'a> { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index a0d21bbf149..fe80d26d109 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -37,7 +37,6 @@ use collections::{HashMap, HashSet}; use std::fmt; use std::io::{fs, File, BufferedWriter, MemWriter, BufferedReader}; use std::io; -use std::local_data; use std::str; use std::strbuf::StrBuf; @@ -243,24 +242,22 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { } // Crawl the crate to build various caches used for the output - let mut cache = local_data::get(::analysiskey, |analysis| { - let public_items = analysis.map(|a| a.public_items.clone()); - let public_items = public_items.unwrap_or(NodeSet::new()); - Cache { - impls: HashMap::new(), - typarams: HashMap::new(), - paths: HashMap::new(), - traits: HashMap::new(), - implementors: HashMap::new(), - stack: Vec::new(), - parent_stack: Vec::new(), - search_index: Vec::new(), - extern_locations: HashMap::new(), - privmod: false, - public_items: public_items, - orphan_methods: Vec::new(), - } - }); + let public_items = ::analysiskey.get().map(|a| a.public_items.clone()); + let public_items = public_items.unwrap_or(NodeSet::new()); + let mut cache = Cache { + impls: HashMap::new(), + typarams: HashMap::new(), + paths: HashMap::new(), + traits: HashMap::new(), + implementors: HashMap::new(), + stack: Vec::new(), + parent_stack: Vec::new(), + search_index: Vec::new(), + extern_locations: HashMap::new(), + privmod: false, + public_items: public_items, + orphan_methods: Vec::new(), + }; cache.stack.push(krate.name.clone()); krate = cache.fold_crate(krate); @@ -833,7 +830,7 @@ impl Context { item.name = Some(krate.name); // using a rwarc makes this parallelizable in the future - local_data::set(cache_key, Arc::new(cache)); + cache_key.replace(Some(Arc::new(cache))); let mut work = vec!((self, item)); loop { @@ -859,7 +856,7 @@ impl Context { info!("Rendering an item to {}", w.path().display()); // A little unfortunate that this is done like this, but it sure // does make formatting *a lot* nicer. - local_data::set(current_location_key, cx.current.clone()); + current_location_key.replace(Some(cx.current.clone())); let mut title = StrBuf::from_str(cx.current.connect("::")); if pushname { @@ -1299,31 +1296,28 @@ fn item_trait(w: &mut Writer, it: &clean::Item, try!(write!(w, "</div>")); } - local_data::get(cache_key, |cache| { - let cache = cache.unwrap(); - match cache.implementors.find(&it.id) { - Some(implementors) => { - try!(write!(w, " - <h2 id='implementors'>Implementors</h2> - <ul class='item-list'> - ")); - for i in implementors.iter() { - match *i { - PathType(ref ty) => { - try!(write!(w, "<li><code>{}</code></li>", *ty)); - } - OtherType(ref generics, ref trait_, ref for_) => { - try!(write!(w, "<li><code>impl{} {} for {}</code></li>", - *generics, *trait_, *for_)); - } + match cache_key.get().unwrap().implementors.find(&it.id) { + Some(implementors) => { + try!(write!(w, " + <h2 id='implementors'>Implementors</h2> + <ul class='item-list'> + ")); + for i in implementors.iter() { + match *i { + PathType(ref ty) => { + try!(write!(w, "<li><code>{}</code></li>", *ty)); + } + OtherType(ref generics, ref trait_, ref for_) => { + try!(write!(w, "<li><code>impl{} {} for {}</code></li>", + *generics, *trait_, *for_)); } } - try!(write!(w, "</ul>")); } - None => {} + try!(write!(w, "</ul>")); } - Ok(()) - }) + None => {} + } + Ok(()) } fn render_method(w: &mut Writer, meth: &clean::Item) -> fmt::Result { @@ -1550,51 +1544,48 @@ fn render_struct(w: &mut Writer, it: &clean::Item, } fn render_methods(w: &mut Writer, it: &clean::Item) -> fmt::Result { - local_data::get(cache_key, |cache| { - let c = cache.unwrap(); - match c.impls.find(&it.id) { - Some(v) => { - let mut non_trait = v.iter().filter(|p| { - p.ref0().trait_.is_none() - }); - let non_trait = non_trait.collect::<Vec<&(clean::Impl, Option<~str>)>>(); - let mut traits = v.iter().filter(|p| { - p.ref0().trait_.is_some() - }); - let traits = traits.collect::<Vec<&(clean::Impl, Option<~str>)>>(); - - if non_trait.len() > 0 { - try!(write!(w, "<h2 id='methods'>Methods</h2>")); - for &(ref i, ref dox) in non_trait.move_iter() { + match cache_key.get().unwrap().impls.find(&it.id) { + Some(v) => { + let mut non_trait = v.iter().filter(|p| { + p.ref0().trait_.is_none() + }); + let non_trait = non_trait.collect::<Vec<&(clean::Impl, Option<~str>)>>(); + let mut traits = v.iter().filter(|p| { + p.ref0().trait_.is_some() + }); + let traits = traits.collect::<Vec<&(clean::Impl, Option<~str>)>>(); + + if non_trait.len() > 0 { + try!(write!(w, "<h2 id='methods'>Methods</h2>")); + for &(ref i, ref dox) in non_trait.move_iter() { + try!(render_impl(w, i, dox)); + } + } + if traits.len() > 0 { + try!(write!(w, "<h2 id='implementations'>Trait \ + Implementations</h2>")); + let mut any_derived = false; + for & &(ref i, ref dox) in traits.iter() { + if !i.derived { try!(render_impl(w, i, dox)); + } else { + any_derived = true; } } - if traits.len() > 0 { - try!(write!(w, "<h2 id='implementations'>Trait \ - Implementations</h2>")); - let mut any_derived = false; - for & &(ref i, ref dox) in traits.iter() { - if !i.derived { + if any_derived { + try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \ + </h3>")); + for &(ref i, ref dox) in traits.move_iter() { + if i.derived { try!(render_impl(w, i, dox)); - } else { - any_derived = true; - } - } - if any_derived { - try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \ - </h3>")); - for &(ref i, ref dox) in traits.move_iter() { - if i.derived { - try!(render_impl(w, i, dox)); - } } } } } - None => {} } - Ok(()) - }) + None => {} + } + Ok(()) } fn render_impl(w: &mut Writer, i: &clean::Impl, @@ -1644,9 +1635,8 @@ fn render_impl(w: &mut Writer, i: &clean::Impl, match trait_id { None => {} Some(id) => { - try!(local_data::get(cache_key, |cache| { - let cache = cache.unwrap(); - match cache.traits.find(&id) { + try!({ + match cache_key.get().unwrap().traits.find(&id) { Some(t) => { for method in t.methods.iter() { let n = method.item().name.clone(); @@ -1661,7 +1651,7 @@ fn render_impl(w: &mut Writer, i: &clean::Impl, None => {} } Ok(()) - })) + }) } } try!(write!(w, "</div>")); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 24b3e1128ea..a79c8b30bba 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -28,7 +28,6 @@ extern crate time; extern crate log; extern crate libc; -use std::local_data; use std::io; use std::io::{File, MemWriter}; use std::str; @@ -276,7 +275,7 @@ fn rust_input(cratefile: &str, matches: &getopts::Matches) -> Output { &cr) }).unwrap(); info!("finished with rustc"); - local_data::set(analysiskey, analysis); + analysiskey.replace(Some(analysis)); // Process all of the crate attributes, extracting plugin metadata along // with the passes which we are supposed to run. diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index f8a2382c028..38d1b2a14e1 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -11,7 +11,6 @@ use collections::HashSet; use rustc::util::nodemap::NodeSet; use std::cmp; -use std::local_data; use std::strbuf::StrBuf; use std::uint; use syntax::ast; @@ -86,13 +85,11 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult { /// Strip private items from the point of view of a crate or externally from a /// crate, specified by the `xcrate` flag. -pub fn strip_private(krate: clean::Crate) -> plugins::PluginResult { +pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult { // This stripper collects all *retained* nodes. let mut retained = HashSet::new(); - let exported_items = local_data::get(super::analysiskey, |analysis| { - analysis.unwrap().exported_items.clone() - }); - let mut krate = krate; + let analysis = super::analysiskey.get().unwrap(); + let exported_items = analysis.exported_items.clone(); // strip all private items { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 0b8434d7d17..898f5856694 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -12,7 +12,6 @@ use std::cell::RefCell; use std::char; use std::io; use std::io::{Process, TempDir}; -use std::local_data; use std::os; use std::str; use std::strbuf::StrBuf; @@ -75,7 +74,7 @@ pub fn run(input: &str, maybe_typed: core::NotTyped(sess), src: input_path, }; - local_data::set(super::ctxtkey, ctx); + super::ctxtkey.replace(Some(ctx)); let mut v = RustdocVisitor::new(ctx, None); v.visit(&ctx.krate); diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index 9a029de8d6c..c3c04c5470f 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -23,16 +23,14 @@ named and annotated. This name is then passed to the functions in this module to modify/read the slot specified by the key. ```rust -use std::local_data; - local_data_key!(key_int: int) local_data_key!(key_vector: ~[int]) -local_data::set(key_int, 3); -local_data::get(key_int, |opt| assert_eq!(opt.map(|x| *x), Some(3))); +key_int.replace(Some(3)); +assert_eq!(*key_int.get().unwrap(), 3); -local_data::set(key_vector, ~[4]); -local_data::get(key_vector, |opt| assert_eq!(*opt.unwrap(), ~[4])); +key_vector.replace(Some(~[4])); +assert_eq!(*key_vector.get().unwrap(), ~[4]); ``` */ @@ -43,9 +41,12 @@ local_data::get(key_vector, |opt| assert_eq!(*opt.unwrap(), ~[4])); use cast; use iter::{Iterator}; use kinds::Send; +use kinds::marker; use mem::replace; +use ops::{Drop, Deref}; use option::{None, Option, Some}; use owned::Box; +use raw; use rt::task::{Task, LocalStorage}; use slice::{ImmutableVector, MutableVector}; use vec::Vec; @@ -66,7 +67,7 @@ pub type Key<T> = &'static KeyValue<T>; #[allow(missing_doc)] pub enum KeyValue<T> { Key } -#[allow(missing_doc)] +#[doc(hidden)] trait LocalData {} impl<T: 'static> LocalData for T {} @@ -91,7 +92,7 @@ impl<T: 'static> LocalData for T {} // n.b. If TLS is used heavily in future, this could be made more efficient with // a proper map. #[doc(hidden)] -pub type Map = Vec<Option<(*u8, TLSValue, LoanState)>>; +pub type Map = Vec<Option<(*u8, TLSValue, uint)>>; type TLSValue = Box<LocalData:Send>; // Gets the map from the runtime. Lazily initialises if not done so already. @@ -111,243 +112,156 @@ unsafe fn get_local_map() -> &mut Map { *slot = Some(vec!()); match *slot { Some(ref mut map_ptr) => { return map_ptr } - None => abort() + None => unreachable!(), } } } } -#[deriving(Eq)] -enum LoanState { - NoLoan, ImmLoan, MutLoan -} - -impl LoanState { - fn describe(&self) -> &'static str { - match *self { - NoLoan => "no loan", - ImmLoan => "immutable", - MutLoan => "mutable" - } - } -} - fn key_to_key_value<T: 'static>(key: Key<T>) -> *u8 { - unsafe { cast::transmute(key) } + key as *KeyValue<T> as *u8 } -/// Removes a task-local value from task-local storage. This will return -/// Some(value) if the key was present in TLS, otherwise it will return None. +/// An RAII immutable reference to a task-local value. /// -/// A runtime assertion will be triggered it removal of TLS value is attempted -/// while the value is still loaned out via `get` or `get_mut`. -pub fn pop<T: 'static>(key: Key<T>) -> Option<T> { - let map = unsafe { get_local_map() }; - let key_value = key_to_key_value(key); - - for entry in map.mut_iter() { - match *entry { - Some((k, _, loan)) if k == key_value => { - if loan != NoLoan { - fail!("TLS value cannot be removed because it is currently \ - borrowed as {}", loan.describe()); - } - // Move the data out of the `entry` slot via prelude::replace. - // This is guaranteed to succeed because we already matched - // on `Some` above. - let data = match replace(entry, None) { - Some((_, data, _)) => data, - None => abort() - }; - - // Move `data` into transmute to get out the memory that it - // owns, we must free it manually later. - let (_vtable, alloc): (uint, Box<T>) = unsafe { - cast::transmute(data) - }; - - // Now that we own `alloc`, we can just move out of it as we - // would with any other data. - return Some(*alloc); - } - _ => {} - } - } - return None; +/// The task-local data can be accessed through this value, and when this +/// structure is dropped it will return the borrow on the data. +pub struct Ref<T> { + ptr: &'static T, + key: Key<T>, + index: uint, + nosend: marker::NoSend, } -/// Retrieves a value from TLS. The closure provided is yielded `Some` of a -/// reference to the value located in TLS if one exists, or `None` if the key -/// provided is not present in TLS currently. -/// -/// It is considered a runtime error to attempt to get a value which is already -/// on loan via the `get_mut` method provided. -pub fn get<T: 'static, U>(key: Key<T>, f: |Option<&T>| -> U) -> U { - get_with(key, ImmLoan, f) -} - -/// Retrieves a mutable value from TLS. The closure provided is yielded `Some` -/// of a reference to the mutable value located in TLS if one exists, or `None` -/// if the key provided is not present in TLS currently. -/// -/// It is considered a runtime error to attempt to get a value which is already -/// on loan via this or the `get` methods. -pub fn get_mut<T: 'static, U>(key: Key<T>, f: |Option<&mut T>| -> U) -> U { - get_with(key, MutLoan, |x| { - match x { - None => f(None), - // We're violating a lot of compiler guarantees with this - // invocation of `transmute`, but we're doing runtime checks to - // ensure that it's always valid (only one at a time). - // - // there is no need to be upset! - Some(x) => { f(Some(unsafe { cast::transmute::<&_, &mut _>(x) })) } - } - }) -} +impl<T: 'static> KeyValue<T> { + /// Replaces a value in task local storage. + /// + /// If this key is already present in TLS, then the previous value is + /// replaced with the provided data, and then returned. + /// + /// # Failure + /// + /// This function will fail if this key is present in TLS and currently on + /// loan with the `get` method. + /// + /// # Example + /// + /// ``` + /// local_data_key!(foo: int) + /// + /// assert_eq!(foo.replace(Some(10)), None); + /// assert_eq!(foo.replace(Some(4)), Some(10)); + /// assert_eq!(foo.replace(None), Some(4)); + /// ``` + pub fn replace(&'static self, data: Option<T>) -> Option<T> { + let map = unsafe { get_local_map() }; + let keyval = key_to_key_value(self); + + // When the task-local map is destroyed, all the data needs to be + // cleaned up. For this reason we can't do some clever tricks to store + // '~T' as a '*c_void' or something like that. To solve the problem, we + // cast everything to a trait (LocalData) which is then stored inside + // the map. Upon destruction of the map, all the objects will be + // destroyed and the traits have enough information about them to + // destroy themselves. + // + // Additionally, the type of the local data map must ascribe to Send, so + // we do the transmute here to add the Send bound back on. This doesn't + // actually matter because TLS will always own the data (until its moved + // out) and we're not actually sending it to other schedulers or + // anything. + let newval = data.map(|d| { + let d = box d as Box<LocalData>; + let d: Box<LocalData:Send> = unsafe { cast::transmute(d) }; + (keyval, d, 0) + }); -fn get_with<T:'static, - U>( - key: Key<T>, - state: LoanState, - f: |Option<&T>| -> U) - -> U { - // This function must be extremely careful. Because TLS can store owned - // values, and we must have some form of `get` function other than `pop`, - // this function has to give a `&` reference back to the caller. - // - // One option is to return the reference, but this cannot be sound because - // the actual lifetime of the object is not known. The slot in TLS could not - // be modified until the object goes out of scope, but the TLS code cannot - // know when this happens. - // - // For this reason, the reference is yielded to a specified closure. This - // way the TLS code knows exactly what the lifetime of the yielded pointer - // is, allowing callers to acquire references to owned data. This is also - // sound so long as measures are taken to ensure that while a TLS slot is - // loaned out to a caller, it's not modified recursively. - let map = unsafe { get_local_map() }; - let key_value = key_to_key_value(key); - - let pos = map.iter().position(|entry| { - match *entry { - Some((k, _, _)) if k == key_value => true, _ => false - } - }); - match pos { - None => { return f(None); } - Some(i) => { - let ret; - let mut return_loan = false; - match *map.get_mut(i) { - Some((_, ref data, ref mut loan)) => { - match (state, *loan) { - (_, NoLoan) => { - *loan = state; - return_loan = true; - } - (ImmLoan, ImmLoan) => {} - (want, cur) => { - fail!("TLS slot cannot be borrowed as {} because \ - it is already borrowed as {}", - want.describe(), cur.describe()); - } - } - // data was created with `box T as Box<LocalData>`, so we - // extract pointer part of the trait, (as Box<T>), and - // then use compiler coercions to achieve a '&' pointer. - unsafe { - match *cast::transmute::<&TLSValue, - &(uint, Box<T>)>(data){ - (_vtable, ref alloc) => { - let value: &T = *alloc; - ret = f(Some(value)); - } - } - } - } - _ => abort() + let pos = match self.find(map) { + Some((i, _, &0)) => Some(i), + Some((_, _, _)) => fail!("TLS value cannot be replaced because it \ + is already borrowed"), + None => map.iter().position(|entry| entry.is_none()), + }; + + match pos { + Some(i) => { + replace(map.get_mut(i), newval).map(|(_, data, _)| { + // Move `data` into transmute to get out the memory that it + // owns, we must free it manually later. + let t: raw::TraitObject = unsafe { cast::transmute(data) }; + let alloc: Box<T> = unsafe { cast::transmute(t.data) }; + + // Now that we own `alloc`, we can just move out of it as we + // would with any other data. + *alloc + }) } - - // n.b. 'data' and 'loans' are both invalid pointers at the point - // 'f' returned because `f` could have appended more TLS items which - // in turn relocated the vector. Hence we do another lookup here to - // fixup the loans. - if return_loan { - match *map.get_mut(i) { - Some((_, _, ref mut loan)) => { *loan = NoLoan; } - None => abort() - } + None => { + map.push(newval); + None } - return ret; } } -} -fn abort() -> ! { - use intrinsics; - unsafe { intrinsics::abort() } -} + /// Borrows a value from TLS. + /// + /// If `None` is returned, then this key is not present in TLS. If `Some` is + /// returned, then the returned data is a smart pointer representing a new + /// loan on this TLS key. While on loan, this key cannot be altered via the + /// `replace` method. + /// + /// # Example + /// + /// ``` + /// local_data_key!(key: int) + /// + /// assert!(key.get().is_none()); + /// + /// key.replace(Some(3)); + /// assert_eq!(*key.get().unwrap(), 3); + /// ``` + pub fn get(&'static self) -> Option<Ref<T>> { + let map = unsafe { get_local_map() }; + + self.find(map).map(|(pos, data, loan)| { + *loan += 1; + + // data was created with `~T as ~LocalData`, so we extract + // pointer part of the trait, (as ~T), and then use + // compiler coercions to achieve a '&' pointer. + let ptr = unsafe { + let data = data as *Box<LocalData:Send> as *raw::TraitObject; + &mut *((*data).data as *mut T) + }; + Ref { ptr: ptr, index: pos, nosend: marker::NoSend, key: self } + }) + } -/// Inserts a value into task local storage. If the key is already present in -/// TLS, then the previous value is removed and replaced with the provided data. -/// -/// It is considered a runtime error to attempt to set a key which is currently -/// on loan via the `get` or `get_mut` methods. -pub fn set<T: 'static>(key: Key<T>, data: T) { - let map = unsafe { get_local_map() }; - let keyval = key_to_key_value(key); - - // When the task-local map is destroyed, all the data needs to be cleaned - // up. For this reason we can't do some clever tricks to store 'Box<T>' as - // a '*c_void' or something like that. To solve the problem, we cast - // everything to a trait (LocalData) which is then stored inside the map. - // Upon destruction of the map, all the objects will be destroyed and the - // traits have enough information about them to destroy themselves. - let data = box data as Box<LocalData:>; - - fn insertion_position(map: &mut Map, - key: *u8) -> Option<uint> { - // First see if the map contains this key already - let curspot = map.iter().position(|entry| { + fn find<'a>(&'static self, + map: &'a mut Map) -> Option<(uint, &'a TLSValue, &'a mut uint)>{ + let key_value = key_to_key_value(self); + map.mut_iter().enumerate().filter_map(|(i, entry)| { match *entry { - Some((ekey, _, loan)) if key == ekey => { - if loan != NoLoan { - fail!("TLS value cannot be overwritten because it is - already borrowed as {}", loan.describe()) - } - true + Some((k, ref data, ref mut loan)) if k == key_value => { + Some((i, data, loan)) } - _ => false, + _ => None } - }); - // If it doesn't contain the key, just find a slot that's None - match curspot { - Some(i) => Some(i), - None => map.iter().position(|entry| entry.is_none()) - } + }).next() } +} - // The type of the local data map must ascribe to Send, so we do the - // transmute here to add the Send bound back on. This doesn't actually - // matter because TLS will always own the data (until its moved out) and - // we're not actually sending it to other schedulers or anything. - let data: Box<LocalData:Send> = unsafe { cast::transmute(data) }; - match insertion_position(map, keyval) { - Some(i) => { *map.get_mut(i) = Some((keyval, data, NoLoan)); } - None => { map.push(Some((keyval, data, NoLoan))); } - } +impl<T: 'static> Deref<T> for Ref<T> { + fn deref<'a>(&'a self) -> &'a T { self.ptr } } -/// Modifies a task-local value by temporarily removing it from task-local -/// storage and then re-inserting if `Some` is returned from the closure. -/// -/// This function will have the same runtime errors as generated from `pop` and -/// `set` (the key must not currently be on loan -pub fn modify<T: 'static>(key: Key<T>, f: |Option<T>| -> Option<T>) { - match f(pop(key)) { - Some(next) => { set(key, next); } - None => {} +#[unsafe_destructor] +impl<T: 'static> Drop for Ref<T> { + fn drop(&mut self) { + let map = unsafe { get_local_map() }; + + let (_, _, ref mut loan) = *map.get_mut(self.index).get_mut_ref(); + *loan -= 1; } } @@ -362,55 +276,36 @@ mod tests { #[test] fn test_tls_multitask() { static my_key: Key<~str> = &Key; - set(my_key, "parent data".to_owned()); + my_key.replace(Some("parent data".to_owned())); task::spawn(proc() { // TLS shouldn't carry over. - assert!(get(my_key, |k| k.map(|k| (*k).clone())).is_none()); - set(my_key, "child data".to_owned()); - assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == - "child data".to_owned()); + assert!(my_key.get().is_none()); + my_key.replace(Some("child data".to_owned())); + assert!(my_key.get().get_ref().as_slice() == "child data"); // should be cleaned up for us }); + // Must work multiple times - assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "parent data".to_owned()); - assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "parent data".to_owned()); - assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "parent data".to_owned()); + assert!(my_key.get().unwrap().as_slice() == "parent data"); + assert!(my_key.get().unwrap().as_slice() == "parent data"); + assert!(my_key.get().unwrap().as_slice() == "parent data"); } #[test] fn test_tls_overwrite() { static my_key: Key<~str> = &Key; - set(my_key, "first data".to_owned()); - set(my_key, "next data".to_owned()); // Shouldn't leak. - assert!(get(my_key, |k| k.map(|k| (*k).clone())).unwrap() == "next data".to_owned()); + my_key.replace(Some("first data".to_owned())); + my_key.replace(Some("next data".to_owned())); // Shouldn't leak. + assert!(my_key.get().unwrap().as_slice() == "next data"); } #[test] fn test_tls_pop() { static my_key: Key<~str> = &Key; - set(my_key, "weasel".to_owned()); - assert!(pop(my_key).unwrap() == "weasel".to_owned()); + my_key.replace(Some("weasel".to_owned())); + assert!(my_key.replace(None).unwrap() == "weasel".to_owned()); // Pop must remove the data from the map. - assert!(pop(my_key).is_none()); - } - - #[test] - fn test_tls_modify() { - static my_key: Key<~str> = &Key; - modify(my_key, |data| { - match data { - Some(ref val) => fail!("unwelcome value: {}", *val), - None => Some("first data".to_owned()) - } - }); - modify(my_key, |data| { - match data.as_ref().map(|s| s.as_slice()) { - Some("first data") => Some("next data".to_owned()), - Some(ref val) => fail!("wrong value: {}", *val), - None => fail!("missing value") - } - }); - assert!(pop(my_key).unwrap() == "next data".to_owned()); + assert!(my_key.replace(None).is_none()); } #[test] @@ -423,7 +318,7 @@ mod tests { // a stack smaller than 1 MB. static my_key: Key<~str> = &Key; task::spawn(proc() { - set(my_key, "hax".to_owned()); + my_key.replace(Some("hax".to_owned())); }); } @@ -433,28 +328,27 @@ mod tests { static box_key: Key<@()> = &Key; static int_key: Key<int> = &Key; task::spawn(proc() { - set(str_key, "string data".to_owned()); - set(box_key, @()); - set(int_key, 42); + str_key.replace(Some("string data".to_owned())); + box_key.replace(Some(@())); + int_key.replace(Some(42)); }); } #[test] - #[allow(dead_code)] fn test_tls_overwrite_multiple_types() { static str_key: Key<~str> = &Key; static box_key: Key<@()> = &Key; static int_key: Key<int> = &Key; task::spawn(proc() { - set(str_key, "string data".to_owned()); - set(str_key, "string data 2".to_owned()); - set(box_key, @()); - set(box_key, @()); - set(int_key, 42); + str_key.replace(Some("string data".to_owned())); + str_key.replace(Some("string data 2".to_owned())); + box_key.replace(Some(@())); + box_key.replace(Some(@())); + int_key.replace(Some(42)); // This could cause a segfault if overwriting-destruction is done // with the crazy polymorphic transmute rather than the provided // finaliser. - set(int_key, 31337); + int_key.replace(Some(31337)); }); } @@ -464,17 +358,16 @@ mod tests { static str_key: Key<~str> = &Key; static box_key: Key<@()> = &Key; static int_key: Key<int> = &Key; - set(str_key, "parent data".to_owned()); - set(box_key, @()); + str_key.replace(Some("parent data".to_owned())); + box_key.replace(Some(@())); task::spawn(proc() { - // spawn_linked - set(str_key, "string data".to_owned()); - set(box_key, @()); - set(int_key, 42); + str_key.replace(Some("string data".to_owned())); + box_key.replace(Some(@())); + int_key.replace(Some(42)); fail!(); }); // Not quite nondeterministic. - set(int_key, 31337); + int_key.replace(Some(31337)); fail!(); } @@ -482,42 +375,24 @@ mod tests { fn test_static_pointer() { static key: Key<&'static int> = &Key; static VALUE: int = 0; - let v: &'static int = &VALUE; - set(key, v); + key.replace(Some(&VALUE)); } #[test] fn test_owned() { static key: Key<Box<int>> = &Key; - set(key, box 1); - - get(key, |v| { - get(key, |v| { - get(key, |v| { - assert_eq!(**v.unwrap(), 1); - }); - assert_eq!(**v.unwrap(), 1); - }); - assert_eq!(**v.unwrap(), 1); - }); - set(key, box 2); - get(key, |v| { - assert_eq!(**v.unwrap(), 2); - }) - } - - #[test] - fn test_get_mut() { - static key: Key<int> = &Key; - set(key, 1); - - get_mut(key, |v| { - *v.unwrap() = 2; - }); - - get(key, |v| { - assert_eq!(*v.unwrap(), 2); - }) + key.replace(Some(box 1)); + + { + let k1 = key.get().unwrap(); + let k2 = key.get().unwrap(); + let k3 = key.get().unwrap(); + assert_eq!(**k1, 1); + assert_eq!(**k2, 1); + assert_eq!(**k3, 1); + } + key.replace(Some(box 2)); + assert_eq!(**key.get().unwrap(), 2); } #[test] @@ -527,56 +402,26 @@ mod tests { static key3: Key<int> = &Key; static key4: Key<int> = &Key; static key5: Key<int> = &Key; - set(key1, 1); - set(key2, 2); - set(key3, 3); - set(key4, 4); - set(key5, 5); - - get(key1, |x| assert_eq!(*x.unwrap(), 1)); - get(key2, |x| assert_eq!(*x.unwrap(), 2)); - get(key3, |x| assert_eq!(*x.unwrap(), 3)); - get(key4, |x| assert_eq!(*x.unwrap(), 4)); - get(key5, |x| assert_eq!(*x.unwrap(), 5)); + key1.replace(Some(1)); + key2.replace(Some(2)); + key3.replace(Some(3)); + key4.replace(Some(4)); + key5.replace(Some(5)); + + assert_eq!(*key1.get().unwrap(), 1); + assert_eq!(*key2.get().unwrap(), 2); + assert_eq!(*key3.get().unwrap(), 3); + assert_eq!(*key4.get().unwrap(), 4); + assert_eq!(*key5.get().unwrap(), 5); } #[test] #[should_fail] fn test_nested_get_set1() { static key: Key<int> = &Key; - set(key, 4); - get(key, |_| { - set(key, 4); - }) - } - - #[test] - #[should_fail] - fn test_nested_get_mut2() { - static key: Key<int> = &Key; - set(key, 4); - get(key, |_| { - get_mut(key, |_| {}) - }) - } - - #[test] - #[should_fail] - fn test_nested_get_mut3() { - static key: Key<int> = &Key; - set(key, 4); - get_mut(key, |_| { - get(key, |_| {}) - }) - } + key.replace(Some(4)); - #[test] - #[should_fail] - fn test_nested_get_mut4() { - static key: Key<int> = &Key; - set(key, 4); - get_mut(key, |_| { - get_mut(key, |_| {}) - }) + let _k = key.get(); + key.replace(Some(4)); } } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 4ae3d453f03..1efe56756ed 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -289,12 +289,10 @@ macro_rules! println( /// # Example /// /// ``` -/// use std::local_data; -/// /// local_data_key!(my_integer: int) /// -/// local_data::set(my_integer, 2); -/// local_data::get(my_integer, |val| println!("{}", val.map(|i| *i))); +/// my_integer.replace(Some(2)); +/// println!("{}", my_integer.get().map(|a| *a)); /// ``` #[macro_export] macro_rules! local_data_key( diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 5b29de5a8c1..68d8c446cf9 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -414,13 +414,12 @@ mod test { #[test] fn tls() { - use local_data; local_data_key!(key: @~str) - local_data::set(key, @"data".to_owned()); - assert!(*local_data::get(key, |k| k.map(|k| *k)).unwrap() == "data".to_owned()); + key.replace(Some(@"data".to_owned())); + assert_eq!(key.get().unwrap().as_slice(), "data"); local_data_key!(key2: @~str) - local_data::set(key2, @"data".to_owned()); - assert!(*local_data::get(key2, |k| k.map(|k| *k)).unwrap() == "data".to_owned()); + key2.replace(Some(@"data".to_owned())); + assert_eq!(key2.get().unwrap().as_slice(), "data"); } #[test] diff --git a/src/libstd/slice.rs b/src/libstd/slice.rs index 6c8a329446d..35800048d28 100644 --- a/src/libstd/slice.rs +++ b/src/libstd/slice.rs @@ -3112,7 +3112,6 @@ mod tests { #[test] #[should_fail] fn test_from_elem_fail() { - use cast; use cell::Cell; use rc::Rc; diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs index 4ae9d436972..6ac3becf0b6 100644 --- a/src/libsyntax/ext/mtwt.rs +++ b/src/libsyntax/ext/mtwt.rs @@ -18,7 +18,6 @@ use ast::{Ident, Mrk, Name, SyntaxContext}; use std::cell::RefCell; -use std::local_data; use std::rc::Rc; use collections::HashMap; @@ -91,17 +90,14 @@ fn new_rename_internal(id: Ident, pub fn with_sctable<T>(op: |&SCTable| -> T) -> T { local_data_key!(sctable_key: Rc<SCTable>) - local_data::get(sctable_key, |opt_ts| { - let table = match opt_ts { - None => { - let ts = Rc::new(new_sctable_internal()); - local_data::set(sctable_key, ts.clone()); - ts - } - Some(ts) => ts.clone() - }; - op(&*table) - }) + match sctable_key.get() { + Some(ts) => op(&**ts), + None => { + let ts = Rc::new(new_sctable_internal()); + sctable_key.replace(Some(ts.clone())); + op(&*ts) + } + } } // Make a fresh syntax context table with EmptyCtxt in slot zero @@ -154,17 +150,14 @@ type ResolveTable = HashMap<(Name,SyntaxContext),Name>; fn with_resolve_table_mut<T>(op: |&mut ResolveTable| -> T) -> T { local_data_key!(resolve_table_key: Rc<RefCell<ResolveTable>>) - local_data::get(resolve_table_key, |opt_ts| { - let table = match opt_ts { - None => { - let ts = Rc::new(RefCell::new(HashMap::new())); - local_data::set(resolve_table_key, ts.clone()); - ts - } - Some(ts) => ts.clone() - }; - op(&mut *table.borrow_mut()) - }) + match resolve_table_key.get() { + Some(ts) => op(&mut *ts.borrow_mut()), + None => { + let ts = Rc::new(RefCell::new(HashMap::new())); + resolve_table_key.replace(Some(ts.clone())); + op(&mut *ts.borrow_mut()) + } + } } // Resolve a syntax object to a name, per MTWT. diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index e4e71baad44..131e744d83d 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -19,7 +19,6 @@ use util::interner; use serialize::{Decodable, Decoder, Encodable, Encoder}; use std::cast; use std::fmt; -use std::local_data; use std::path::BytesContainer; use std::rc::Rc; use std::strbuf::StrBuf; @@ -529,11 +528,11 @@ pub type IdentInterner = StrInterner; // FIXME(eddyb) #8726 This should probably use a task-local reference. pub fn get_ident_interner() -> Rc<IdentInterner> { local_data_key!(key: Rc<::parse::token::IdentInterner>) - match local_data::get(key, |k| k.map(|k| k.clone())) { - Some(interner) => interner, + match key.get() { + Some(interner) => interner.clone(), None => { let interner = Rc::new(mk_fresh_ident_interner()); - local_data::set(key, interner.clone()); + key.replace(Some(interner.clone())); interner } } diff --git a/src/test/auxiliary/macro_crate_outlive_expansion_phase.rs b/src/test/auxiliary/macro_crate_outlive_expansion_phase.rs index a2c7e3533d8..670673fe047 100644 --- a/src/test/auxiliary/macro_crate_outlive_expansion_phase.rs +++ b/src/test/auxiliary/macro_crate_outlive_expansion_phase.rs @@ -15,7 +15,6 @@ extern crate syntax; use std::any::Any; -use std::local_data; use syntax::ast::Name; use syntax::ext::base::SyntaxExtension; @@ -30,6 +29,6 @@ impl Drop for Foo { #[macro_registrar] pub fn registrar(_: |Name, SyntaxExtension|) { local_data_key!(foo: Box<Any:Send>); - local_data::set(foo, box Foo { foo: 10 } as Box<Any:Send>); + foo.replace(Some(box Foo { foo: 10 } as Box<Any:Send>)); } diff --git a/src/test/compile-fail/core-tls-store-pointer.rs b/src/test/compile-fail/core-tls-store-pointer.rs index d1541f23c70..2344bd0f090 100644 --- a/src/test/compile-fail/core-tls-store-pointer.rs +++ b/src/test/compile-fail/core-tls-store-pointer.rs @@ -10,8 +10,6 @@ // Testing that we can't store a reference it task-local storage -use std::local_data; - local_data_key!(key: @&int) //~^ ERROR missing lifetime specifier diff --git a/src/test/compile-fail/macro-local-data-key-priv.rs b/src/test/compile-fail/macro-local-data-key-priv.rs index e87d57aaa56..ec0e656cc29 100644 --- a/src/test/compile-fail/macro-local-data-key-priv.rs +++ b/src/test/compile-fail/macro-local-data-key-priv.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::local_data; - // check that the local data keys are private by default. mod bar { @@ -17,6 +15,6 @@ mod bar { } fn main() { - local_data::set(bar::baz, -10.0); + bar::baz.replace(Some(-10.0)); //~^ ERROR static `baz` is private } diff --git a/src/test/run-pass/macro-local-data-key.rs b/src/test/run-pass/macro-local-data-key.rs index e03256bfe49..730b0b08d45 100644 --- a/src/test/run-pass/macro-local-data-key.rs +++ b/src/test/run-pass/macro-local-data-key.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::local_data; - local_data_key!(foo: int) mod bar { @@ -17,12 +15,12 @@ mod bar { } pub fn main() { - local_data::get(foo, |x| assert!(x.is_none())); - local_data::get(bar::baz, |y| assert!(y.is_none())); + assert!(foo.get().is_none()); + assert!(bar::baz.get().is_none()); - local_data::set(foo, 3); - local_data::set(bar::baz, -10.0); + foo.replace(Some(3)); + bar::baz.replace(Some(-10.0)); - local_data::get(foo, |x| assert_eq!(*x.unwrap(), 3)); - local_data::get(bar::baz, |y| assert_eq!(*y.unwrap(), -10.0)); + assert_eq!(*foo.get().unwrap(), 3); + assert_eq!(*bar::baz.get().unwrap(), -10.0); } |
