diff --git a/substrate/environmental/Cargo.toml b/substrate/environmental/Cargo.toml index 52c3337f8a130..971dd38b676b5 100644 --- a/substrate/environmental/Cargo.toml +++ b/substrate/environmental/Cargo.toml @@ -2,3 +2,7 @@ name = "environmental" version = "0.1.0" authors = ["Parity Technologies "] + +[features] +default = ["std"] +std = [] diff --git a/substrate/environmental/src/lib.rs b/substrate/environmental/src/lib.rs index 1b9587a5a5390..8c415fe63af65 100644 --- a/substrate/environmental/src/lib.rs +++ b/substrate/environmental/src/lib.rs @@ -40,12 +40,18 @@ //! } //! ``` -use std::cell::RefCell; -use std::thread::LocalKey; +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(not(feature = "std"), feature(const_fn))] + +#[cfg(feature = "std")] +include!("../with_std.rs"); + +#[cfg(not(feature = "std"))] +include!("../without_std.rs"); #[doc(hidden)] pub fn using R>( - global: &'static LocalKey>>, + global: &'static imp::LocalKey>>, protected: &mut T, f: F ) -> R { @@ -59,13 +65,13 @@ pub fn using R>( global.with(|r| { let original = { let mut global = r.borrow_mut(); - ::std::mem::replace(&mut *global, Some(protected as _)) + imp::replace(&mut *global, Some(protected as _)) }; // even if `f` panics the original will be replaced. struct ReplaceOriginal<'a, T: 'a + ?Sized> { original: Option<*mut T>, - global: &'a RefCell>, + global: &'a imp::RefCell>, } impl<'a, T: 'a + ?Sized> Drop for ReplaceOriginal<'a, T> { @@ -85,7 +91,7 @@ pub fn using R>( #[doc(hidden)] pub fn with R>( - global: &'static LocalKey>>, + global: &'static imp::LocalKey>>, mutator: F, ) -> Option { global.with(|r| unsafe { @@ -104,6 +110,7 @@ pub fn with R>( /// Declare a new global reference module whose underlying value does not contain references. /// /// Will create a module of a given name that contains two functions: +/// /// * `pub fn using R>(protected: &mut $t, f: F) -> R` /// This executes `f`, returning its value. During the call, the module's reference is set to /// be equal to `protected`. @@ -163,7 +170,7 @@ macro_rules! environmental { #[allow(non_camel_case_types)] struct $name { __private_field: () } - thread_local!(static GLOBAL: ::std::cell::RefCell> + thread_local_impl!(static GLOBAL: ::std::cell::RefCell> = ::std::cell::RefCell::new(None)); impl $name { @@ -187,8 +194,8 @@ macro_rules! environmental { #[allow(non_camel_case_types)] struct $name { __private_field: () } - thread_local!(static GLOBAL: ::std::cell::RefCell> - = ::std::cell::RefCell::new(None)); + thread_local_impl!(static GLOBAL: $crate::imp::RefCell> + = $crate::imp::RefCell::new(None)); impl $name { #[allow(unused_imports)] @@ -198,7 +205,7 @@ macro_rules! environmental { f: F ) -> R { let lifetime_extended = unsafe { - ::std::mem::transmute::<&mut $t, &mut ($t + 'static)>(protected) + $crate::imp::transmute::<&mut $t, &mut ($t + 'static)>(protected) }; $crate::using(&GLOBAL, lifetime_extended, f) } diff --git a/substrate/environmental/with_std.rs b/substrate/environmental/with_std.rs new file mode 100644 index 0000000000000..df940cd6d6bb8 --- /dev/null +++ b/substrate/environmental/with_std.rs @@ -0,0 +1,31 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +#[doc(hidden)] +pub mod imp { + pub use std::cell::RefCell; + pub use std::thread::LocalKey; + pub use std::mem::transmute; + pub use std::mem::replace; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! thread_local_impl { + ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr) => ( + thread_local!($(#[$attr])* static $name: $t = $init); + ); +} diff --git a/substrate/environmental/without_std.rs b/substrate/environmental/without_std.rs new file mode 100644 index 0000000000000..6178dc7d1d883 --- /dev/null +++ b/substrate/environmental/without_std.rs @@ -0,0 +1,69 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +#[doc(hidden)] +pub mod imp { + pub use core::cell::RefCell; + pub use core::mem::transmute; + pub use core::mem::replace; + + // This code is a simplified version of [`LocalKey`] and it's wasm32 specialization: [`statik::Key`]. + // [`LocalKey`]: https://github.com/alexcrichton/rust/blob/98931165a23a1c2860d99759385f45d6807c8982/src/libstd/thread/local.rs#L89 + // [`statik::Key`]: https://github.com/alexcrichton/rust/blob/98931165a23a1c2860d99759385f45d6807c8982/src/libstd/thread/local.rs#L310-L312 + + pub struct LocalKey { + pub init: fn() -> T, + pub inner: RefCell>, + } + + // This is safe as long there is no threads in wasm32. + unsafe impl ::core::marker::Sync for LocalKey { } + + impl LocalKey { + pub const fn new(init: fn() -> T) -> LocalKey { + LocalKey { + init, + inner: RefCell::new(None), + } + } + + pub fn with(&'static self, f: F) -> R + where F: FnOnce(&T) -> R + { + if self.inner.borrow().is_none() { + let v = (self.init)(); + *self.inner.borrow_mut() = Some(v); + } + // This code can't panic because: + // 1. `inner` can be borrowed mutably only once at the initialization time. + // 2. After the initialization `inner` is always `Some`. + f(&*self.inner.borrow().as_ref().unwrap()) + } + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! thread_local_impl { + ($(#[$attr:meta])* static $name:ident: $t:ty = $init:expr) => ( + $(#[$attr])* + static $name: $crate::imp::LocalKey<$t> = { + fn __init() -> $t { $init } + + $crate::imp::LocalKey::new(__init) + }; + ); +}