diff --git a/boards/hail/src/main.rs b/boards/hail/src/main.rs index b0415bdd9b..a318fc4ce1 100644 --- a/boards/hail/src/main.rs +++ b/boards/hail/src/main.rs @@ -23,6 +23,8 @@ use sam4l::usart; #[macro_use] pub mod io; +#[allow(dead_code)] +mod test_take_map_cell; static mut SPI_READ_BUF: [u8; 64] = [0; 64]; static mut SPI_WRITE_BUF: [u8; 64] = [0; 64]; @@ -275,7 +277,7 @@ pub unsafe fn reset_handler() { let syscall_spi_device = static_init!( VirtualSpiMasterDevice<'static, sam4l::spi::Spi>, VirtualSpiMasterDevice::new(mux_spi, 0), - 384/8); + 352/8); // Create the SPI systemc call capsule, passing the client let spi_syscalls = static_init!( @@ -343,6 +345,8 @@ pub unsafe fn reset_handler() { pin.set_client(gpio); } + + let hail = Hail { console: console, gpio: gpio, @@ -371,5 +375,8 @@ pub unsafe fn reset_handler() { let mut chip = sam4l::chip::Sam4l::new(); chip.mpu().enable_mpu(); + // Uncomment to measure overheads for TakeCell and MapCell: + // test_take_map_cell::test_take_map_cell(); + kernel::main(&hail, &mut chip, load_processes(), &hail.ipc); } diff --git a/boards/hail/src/test_take_map_cell.rs b/boards/hail/src/test_take_map_cell.rs new file mode 100644 index 0000000000..19d0df5f4b --- /dev/null +++ b/boards/hail/src/test_take_map_cell.rs @@ -0,0 +1,44 @@ +use kernel::common::take_cell::MapCell; + +pub unsafe fn test_take_map_cell() { + static FOO: u32 = 1234; + + static mut mc_ref: MapCell<&'static u32> = MapCell::new(&FOO); + test_map_cell(&mc_ref); + + static mut mc1: MapCell<[[u8; 256]; 1]> = MapCell::new([[125; 256]; 1]); + test_map_cell(&mc1); + + static mut mc2: MapCell<[[u8; 256]; 2]> = MapCell::new([[125; 256]; 2]); + test_map_cell(&mc2); + + static mut mc3: MapCell<[[u8; 256]; 3]> = MapCell::new([[125; 256]; 3]); + test_map_cell(&mc3); + + static mut mc4: MapCell<[[u8; 256]; 4]> = MapCell::new([[125; 256]; 4]); + test_map_cell(&mc4); + + static mut mc5: MapCell<[[u8; 256]; 5]> = MapCell::new([[125; 256]; 5]); + test_map_cell(&mc5); + + static mut mc6: MapCell<[[u8; 256]; 6]> = MapCell::new([[125; 256]; 6]); + test_map_cell(&mc6); + + static mut mc7: MapCell<[[u8; 256]; 7]> = MapCell::new([[125; 256]; 7]); + test_map_cell(&mc7); +} + +#[inline(never)] +#[allow(unused_unsafe)] +unsafe fn test_map_cell<'a, A>(tc: &MapCell) { + let dwt_ctl: *mut u32 = 0xE0001000 as *mut u32; + let dwt_cycles: *mut u32 = 0xE0001004 as *mut u32; + let demcr: *mut u32 = 0xE000EDFC as *mut u32; + + ::core::ptr::write_volatile(demcr, 0x01000000); + ::core::ptr::write_volatile(dwt_cycles, 0); + ::core::ptr::write_volatile(dwt_ctl, ::core::ptr::read_volatile(dwt_ctl) | 1); + tc.map(|_| ()); + let end = ::core::ptr::read_volatile(dwt_cycles); + println!("time: {}, size: {}", end, ::core::mem::size_of_val(tc)); +} diff --git a/boards/imix/src/main.rs b/boards/imix/src/main.rs index 6e0cc30c30..ce0d085d77 100644 --- a/boards/imix/src/main.rs +++ b/boards/imix/src/main.rs @@ -234,7 +234,9 @@ pub unsafe fn reset_handler() { let syscall_spi_device = static_init!( VirtualSpiMasterDevice<'static, sam4l::spi::Spi>, VirtualSpiMasterDevice::new(mux_spi, 3), - 48); + 352/8); + + // Create the SPI systemc call capsule, passing the client let spi_syscalls = static_init!( capsules::spi::Spi<'static, VirtualSpiMasterDevice<'static, sam4l::spi::Spi>>, capsules::spi::Spi::new(syscall_spi_device), @@ -264,7 +266,7 @@ pub unsafe fn reset_handler() { // Create a second virtualized SPI client, for the RF233 let rf233_spi = static_init!(VirtualSpiMasterDevice<'static, sam4l::spi::Spi>, VirtualSpiMasterDevice::new(mux_spi, 3), - 48); + 352/8); // Create the RF233 driver, passing its pins and SPI client let rf233: &RF233<'static, VirtualSpiMasterDevice<'static, sam4l::spi::Spi>> = static_init!(RF233<'static, VirtualSpiMasterDevice<'static, sam4l::spi::Spi>>, diff --git a/boards/storm/src/main.rs b/boards/storm/src/main.rs index 5caf187f29..09ac53a8a1 100644 --- a/boards/storm/src/main.rs +++ b/boards/storm/src/main.rs @@ -314,7 +314,7 @@ pub unsafe fn reset_handler() { let syscall_spi_device = static_init!( VirtualSpiMasterDevice<'static, sam4l::spi::Spi>, VirtualSpiMasterDevice::new(mux_spi, 3), - 384/8); + 352/8); // Create the SPI systemc call capsule, passing the client let spi_syscalls = static_init!( diff --git a/capsules/src/console.rs b/capsules/src/console.rs index 0d36964c25..e51b6c72ef 100644 --- a/capsules/src/console.rs +++ b/capsules/src/console.rs @@ -3,6 +3,7 @@ //! Console provides userspace with the ability to print text via a serial //! interface. +use core::cell::Cell; use kernel::{AppId, AppSlice, Container, Callback, Shared, Driver, ReturnCode}; use kernel::common::take_cell::TakeCell; use kernel::hil::uart::{self, UART, Client}; @@ -37,8 +38,8 @@ pub static mut WRITE_BUF: [u8; 64] = [0; 64]; pub struct Console<'a, U: UART + 'a> { uart: &'a U, apps: Container, - in_progress: TakeCell, - tx_buffer: TakeCell<&'static mut [u8]>, + in_progress: Cell>, + tx_buffer: TakeCell<'static, [u8]>, baud_rate: u32, } @@ -51,7 +52,7 @@ impl<'a, U: UART> Console<'a, U> { Console { uart: uart, apps: container, - in_progress: TakeCell::empty(), + in_progress: Cell::new(None), tx_buffer: TakeCell::new(tx_buffer), baud_rate: baud_rate, } @@ -99,8 +100,8 @@ impl<'a, U: UART> Console<'a, U> { /// Internal helper function for sending data for an existing transaction. /// Cannot fail. If can't send now, it will schedule for sending later. fn send(&self, app_id: AppId, app: &mut App, slice: AppSlice) { - if self.in_progress.is_none() { - self.in_progress.replace(app_id); + if self.in_progress.get().is_none() { + self.in_progress.set(Some(app_id)); self.tx_buffer.take().map(|buffer| { let mut transaction_len = app.write_remaining; for (i, c) in slice.as_ref()[slice.len() - app.write_remaining..slice.len()] @@ -204,7 +205,8 @@ impl<'a, U: UART> Client for Console<'a, U> { // Either print more from the AppSlice or send a callback to the // application. self.tx_buffer.replace(buffer); - self.in_progress.take().map(|appid| { + self.in_progress.get().map(|appid| { + self.in_progress.set(None); self.apps.enter(appid, |app, _| { match self.send_continue(appid, app) { Ok(more_to_send) => { @@ -229,7 +231,7 @@ impl<'a, U: UART> Client for Console<'a, U> { // If we are not printing more from the current AppSlice, // see if any other applications have pending messages. - if self.in_progress.is_none() { + if self.in_progress.get().is_none() { for cntr in self.apps.iter() { let started_tx = cntr.enter(|app, _| { if app.pending_write { diff --git a/capsules/src/fm25cl.rs b/capsules/src/fm25cl.rs index 5a0cdd1e9a..ad64797319 100644 --- a/capsules/src/fm25cl.rs +++ b/capsules/src/fm25cl.rs @@ -4,7 +4,7 @@ use core::cell::Cell; use core::cmp; use kernel::{AppId, AppSlice, Callback, Driver, ReturnCode, Shared}; -use kernel::common::take_cell::TakeCell; +use kernel::common::take_cell::{MapCell, TakeCell}; use kernel::hil; @@ -52,10 +52,10 @@ pub trait FM25CLClient { pub struct FM25CL<'a, S: hil::spi::SpiMasterDevice + 'a> { spi: &'a S, state: Cell, - txbuffer: TakeCell<&'static mut [u8]>, - rxbuffer: TakeCell<&'static mut [u8]>, - client: TakeCell<&'static FM25CLClient>, - client_buffer: TakeCell<&'static mut [u8]>, // Store buffer and state for passing back to client + txbuffer: TakeCell<'static, [u8]>, + rxbuffer: TakeCell<'static, [u8]>, + client: Cell>, + client_buffer: TakeCell<'static, [u8]>, // Store buffer and state for passing back to client client_write_address: Cell, client_write_len: Cell, } @@ -71,7 +71,7 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> FM25CL<'a, S> { state: Cell::new(State::Idle), txbuffer: TakeCell::new(txbuffer), rxbuffer: TakeCell::new(rxbuffer), - client: TakeCell::empty(), + client: Cell::new(None), client_buffer: TakeCell::empty(), client_write_address: Cell::new(0), client_write_len: Cell::new(0), @@ -79,7 +79,7 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> FM25CL<'a, S> { } pub fn set_client(&self, client: &'static C) { - self.client.replace(client); + self.client.set(Some(client)); } /// Setup SPI for this chip @@ -165,7 +165,7 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> hil::spi::SpiMasterClient for FM25CL // Also replace this buffer self.rxbuffer.replace(read_buffer); - self.client.map(|client| { client.status(status); }); + self.client.get().map(|client| { client.status(status); }); }); } State::WriteEnable => { @@ -195,9 +195,7 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> hil::spi::SpiMasterClient for FM25CL // Call done with the write() buffer self.client_buffer.take().map(move |buffer| { - self.client.map(move |client| { - client.done(buffer); - }); + self.client.get().map(move |client| { client.done(buffer); }); }); } State::ReadMemory => { @@ -216,7 +214,7 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> hil::spi::SpiMasterClient for FM25CL self.rxbuffer.replace(read_buffer); - self.client.map(move |client| { client.read(buffer, read_len); }); + self.client.get().map(move |client| { client.read(buffer, read_len); }); }); }); } @@ -227,18 +225,18 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> hil::spi::SpiMasterClient for FM25CL /// Holds buffers and whatnot that the application has passed us. struct AppState { - callback: Cell>, - read_buffer: TakeCell>, - write_buffer: TakeCell>, + callback: Option, + read_buffer: Option>, + write_buffer: Option>, } /// Default implementation of the FM25CL driver that provides a Driver /// interface for providing access to applications. pub struct FM25CLDriver<'a, S: hil::spi::SpiMasterDevice + 'a> { fm25cl: &'a FM25CL<'a, S>, - app_state: TakeCell, - kernel_read: TakeCell<&'static mut [u8]>, - kernel_write: TakeCell<&'static mut [u8]>, + app_state: MapCell, + kernel_read: TakeCell<'static, [u8]>, + kernel_write: TakeCell<'static, [u8]>, } impl<'a, S: hil::spi::SpiMasterDevice + 'a> FM25CLDriver<'a, S> { @@ -248,7 +246,7 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> FM25CLDriver<'a, S> { -> FM25CLDriver<'a, S> { FM25CLDriver { fm25cl: fm25, - app_state: TakeCell::empty(), + app_state: MapCell::empty(), kernel_read: TakeCell::new(read_buf), kernel_write: TakeCell::new(write_buf), } @@ -258,7 +256,7 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> FM25CLDriver<'a, S> { impl<'a, S: hil::spi::SpiMasterDevice + 'a> FM25CLClient for FM25CLDriver<'a, S> { fn status(&self, status: u8) { self.app_state.map(|app_state| { - app_state.callback.get().map(|mut cb| { cb.schedule(0, status as usize, 0); }); + app_state.callback.map(|mut cb| { cb.schedule(0, status as usize, 0); }); }); } @@ -266,7 +264,7 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> FM25CLClient for FM25CLDriver<'a, S> self.app_state.map(|app_state| { let mut read_len: usize = 0; - app_state.read_buffer.map(move |read_buffer| { + app_state.read_buffer.as_mut().map(move |read_buffer| { read_len = cmp::min(read_buffer.len(), len); let d = &mut read_buffer.as_mut()[0..(read_len as usize)]; @@ -277,7 +275,7 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> FM25CLClient for FM25CLDriver<'a, S> self.kernel_read.replace(data); }); - app_state.callback.get().map(|mut cb| { cb.schedule(1, read_len, 0); }); + app_state.callback.map(|mut cb| { cb.schedule(1, read_len, 0); }); }); } @@ -285,7 +283,7 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> FM25CLClient for FM25CLDriver<'a, S> self.kernel_write.replace(buffer); self.app_state - .map(|app_state| { app_state.callback.get().map(|mut cb| { cb.schedule(2, 0, 0); }); }); + .map(|app_state| { app_state.callback.map(|mut cb| { cb.schedule(2, 0, 0); }); }); } } @@ -297,13 +295,13 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> Driver for FM25CLDriver<'a, S> { let appst = match self.app_state.take() { None => { AppState { - callback: Cell::new(None), - read_buffer: TakeCell::new(slice), - write_buffer: TakeCell::empty(), + callback: None, + read_buffer: Some(slice), + write_buffer: None, } } - Some(appst) => { - appst.read_buffer.replace(slice); + Some(mut appst) => { + appst.read_buffer = Some(slice); appst } }; @@ -312,20 +310,15 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> Driver for FM25CLDriver<'a, S> { } // Pass write buffer in from application 1 => { - let appst = match self.app_state.take() { - None => { - AppState { - callback: Cell::new(None), - write_buffer: TakeCell::new(slice), - read_buffer: TakeCell::empty(), - } - } - Some(appst) => { - appst.write_buffer.replace(slice); - appst - } - }; - self.app_state.replace(appst); + if self.app_state.is_none() { + self.app_state.put(AppState { + callback: None, + write_buffer: Some(slice), + read_buffer: None, + }); + } else { + self.app_state.map(|appst| appst.write_buffer = Some(slice)); + } ReturnCode::SUCCESS } _ => ReturnCode::ENOSUPPORT, @@ -335,20 +328,15 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> Driver for FM25CLDriver<'a, S> { fn subscribe(&self, subscribe_num: usize, callback: Callback) -> ReturnCode { match subscribe_num { 0 => { - let appst = match self.app_state.take() { - None => { - AppState { - callback: Cell::new(Some(callback)), - write_buffer: TakeCell::empty(), - read_buffer: TakeCell::empty(), - } - } - Some(appst) => { - appst.callback.set(Some(callback)); - appst - } - }; - self.app_state.replace(appst); + if self.app_state.is_none() { + self.app_state.put(AppState { + callback: Some(callback), + write_buffer: None, + read_buffer: None, + }); + } else { + self.app_state.map(|appst| appst.callback = Some(callback)); + } ReturnCode::SUCCESS } @@ -385,7 +373,7 @@ impl<'a, S: hil::spi::SpiMasterDevice + 'a> Driver for FM25CLDriver<'a, S> { let len = ((data >> 16) & 0xFFFF) as usize; self.app_state.map(|app_state| { - app_state.write_buffer.map(|write_buffer| { + app_state.write_buffer.as_mut().map(|write_buffer| { self.kernel_write.take().map(|kernel_write| { // Check bounds for write length let buf_len = cmp::min(write_buffer.len(), kernel_write.len()); diff --git a/capsules/src/fxos8700_cq.rs b/capsules/src/fxos8700_cq.rs index b267fc9806..5f7ab42251 100644 --- a/capsules/src/fxos8700_cq.rs +++ b/capsules/src/fxos8700_cq.rs @@ -156,7 +156,7 @@ enum State { pub struct Fxos8700cq<'a> { i2c: &'a I2CDevice, state: Cell, - buffer: TakeCell<&'static mut [u8]>, + buffer: TakeCell<'static, [u8]>, callback: Cell>, } diff --git a/capsules/src/i2c_master_slave_driver.rs b/capsules/src/i2c_master_slave_driver.rs index ae75eab385..34981cb787 100644 --- a/capsules/src/i2c_master_slave_driver.rs +++ b/capsules/src/i2c_master_slave_driver.rs @@ -12,10 +12,11 @@ use core::cell::Cell; use core::cmp; -use kernel::{AppId, AppSlice, Callback, Driver, ReturnCode, Shared}; +use kernel::{AppId, AppSlice, Callback, Driver, Shared}; -use kernel::common::take_cell::TakeCell; +use kernel::common::take_cell::{TakeCell, MapCell}; use kernel::hil; +use kernel::returncode::ReturnCode; pub static mut BUFFER1: [u8; 256] = [0; 256]; pub static mut BUFFER2: [u8; 256] = [0; 256]; @@ -23,11 +24,11 @@ pub static mut BUFFER3: [u8; 256] = [0; 256]; pub struct AppState { - callback: TakeCell, - master_tx_buffer: TakeCell>, - master_rx_buffer: TakeCell>, - slave_tx_buffer: TakeCell>, - slave_rx_buffer: TakeCell>, + callback: Option, + master_tx_buffer: Option>, + master_rx_buffer: Option>, + slave_tx_buffer: Option>, + slave_rx_buffer: Option>, } #[derive(Clone,Copy,PartialEq)] @@ -41,10 +42,10 @@ pub struct I2CMasterSlaveDriver<'a> { i2c: &'a hil::i2c::I2CMasterSlave, listening: Cell, master_action: Cell, // Whether we issued a write or read as master - master_buffer: TakeCell<&'static mut [u8]>, - slave_buffer1: TakeCell<&'static mut [u8]>, - slave_buffer2: TakeCell<&'static mut [u8]>, - app_state: TakeCell, + master_buffer: TakeCell<'static, [u8]>, + slave_buffer1: TakeCell<'static, [u8]>, + slave_buffer2: TakeCell<'static, [u8]>, + app_state: MapCell, } impl<'a> I2CMasterSlaveDriver<'a> { @@ -54,11 +55,11 @@ impl<'a> I2CMasterSlaveDriver<'a> { slave_buffer2: &'static mut [u8]) -> I2CMasterSlaveDriver<'a> { let app_state = AppState { - callback: TakeCell::empty(), - master_tx_buffer: TakeCell::empty(), - master_rx_buffer: TakeCell::empty(), - slave_tx_buffer: TakeCell::empty(), - slave_rx_buffer: TakeCell::empty(), + callback: None, + master_tx_buffer: None, + master_rx_buffer: None, + slave_tx_buffer: None, + slave_rx_buffer: None, }; I2CMasterSlaveDriver { @@ -68,7 +69,7 @@ impl<'a> I2CMasterSlaveDriver<'a> { master_buffer: TakeCell::new(master_buffer), slave_buffer1: TakeCell::new(slave_buffer1), slave_buffer2: TakeCell::new(slave_buffer2), - app_state: TakeCell::new(app_state), + app_state: MapCell::new(app_state), } } } @@ -97,7 +98,7 @@ impl<'a> hil::i2c::I2CHwMasterClient for I2CMasterSlaveDriver<'a> { MasterAction::Read(read_len) => { self.app_state.map(|app_state| { - app_state.master_rx_buffer.map(move |app_buffer| { + app_state.master_rx_buffer.as_mut().map(move |app_buffer| { let len = cmp::min(app_buffer.len(), read_len as usize); let d = &mut app_buffer.as_mut()[0..(len as usize)]; @@ -137,7 +138,7 @@ impl<'a> hil::i2c::I2CHwSlaveClient for I2CMasterSlaveDriver<'a> { match transmission_type { hil::i2c::SlaveTransmissionType::Write => { self.app_state.map(|app_state| { - app_state.slave_rx_buffer.map(move |app_rx| { + app_state.slave_rx_buffer.as_mut().map(move |app_rx| { // Check bounds for write length let buf_len = cmp::min(app_rx.len(), buffer.len()); let read_len = cmp::min(buf_len, length as usize); @@ -196,22 +197,22 @@ impl<'a> Driver for I2CMasterSlaveDriver<'a> { // Pass in a buffer for transmitting a `write` to another // I2C device. 0 => { - self.app_state.map(|app_state| { app_state.master_tx_buffer.replace(slice); }); + self.app_state.map(|app_state| { app_state.master_tx_buffer = Some(slice); }); ReturnCode::SUCCESS } // Pass in a buffer for doing a read from another I2C device. 1 => { - self.app_state.map(|app_state| { app_state.master_rx_buffer.replace(slice); }); + self.app_state.map(|app_state| { app_state.master_rx_buffer = Some(slice); }); ReturnCode::SUCCESS } // Pass in a buffer for handling a read issued by another I2C master. 2 => { - self.app_state.map(|app_state| { app_state.slave_tx_buffer.replace(slice); }); + self.app_state.map(|app_state| { app_state.slave_tx_buffer = Some(slice); }); ReturnCode::SUCCESS } // Pass in a buffer for handling a write issued by another I2C master. 3 => { - self.app_state.map(|app_state| { app_state.slave_rx_buffer.replace(slice); }); + self.app_state.map(|app_state| { app_state.slave_rx_buffer = Some(slice); }); ReturnCode::SUCCESS } _ => ReturnCode::ENOSUPPORT, @@ -221,7 +222,7 @@ impl<'a> Driver for I2CMasterSlaveDriver<'a> { fn subscribe(&self, subscribe_num: usize, callback: Callback) -> ReturnCode { match subscribe_num { 0 => { - self.app_state.map(|app_state| { app_state.callback.replace(callback); }); + self.app_state.map(|app_state| { app_state.callback = Some(callback); }); ReturnCode::SUCCESS } @@ -239,7 +240,7 @@ impl<'a> Driver for I2CMasterSlaveDriver<'a> { let len = (data >> 16) & 0xFFFF; self.app_state.map(|app_state| { - app_state.master_tx_buffer.map(|app_tx| { + app_state.master_tx_buffer.as_mut().map(|app_tx| { self.master_buffer.take().map(|kernel_tx| { // Check bounds for write length let buf_len = cmp::min(app_tx.len(), kernel_tx.len()); @@ -270,7 +271,7 @@ impl<'a> Driver for I2CMasterSlaveDriver<'a> { let len = (data >> 16) & 0xFFFF; self.app_state.map(|app_state| { - app_state.master_rx_buffer.map(|app_rx| { + app_state.master_rx_buffer.as_mut().map(|app_rx| { self.master_buffer.take().map(|kernel_tx| { // Check bounds for write length let buf_len = cmp::min(app_rx.len(), kernel_tx.len()); @@ -314,7 +315,7 @@ impl<'a> Driver for I2CMasterSlaveDriver<'a> { // in the shared slice to the lower level I2C hardware driver. 4 => { self.app_state.map(|app_state| { - app_state.slave_tx_buffer.map(|app_tx| { + app_state.slave_tx_buffer.as_mut().map(|app_tx| { self.slave_buffer2.take().map(|kernel_tx| { // Check bounds for write length let len = data; diff --git a/capsules/src/isl29035.rs b/capsules/src/isl29035.rs index d41394e2ec..4380ef1036 100644 --- a/capsules/src/isl29035.rs +++ b/capsules/src/isl29035.rs @@ -21,7 +21,7 @@ pub struct Isl29035<'a, A: time::Alarm + 'a> { i2c: &'a I2CDevice, alarm: &'a A, state: Cell, - buffer: TakeCell<&'static mut [u8]>, + buffer: TakeCell<'static, [u8]>, callback: Cell>, } diff --git a/capsules/src/lps25hb.rs b/capsules/src/lps25hb.rs index 5e4a05523f..d900280c65 100644 --- a/capsules/src/lps25hb.rs +++ b/capsules/src/lps25hb.rs @@ -79,7 +79,7 @@ pub struct LPS25HB<'a> { interrupt_pin: &'a gpio::Pin, callback: Cell>, state: Cell, - buffer: TakeCell<&'static mut [u8]>, + buffer: TakeCell<'static, [u8]>, } impl<'a> LPS25HB<'a> { diff --git a/capsules/src/nrf51822_serialization.rs b/capsules/src/nrf51822_serialization.rs index d109d41956..ce11a6bd51 100644 --- a/capsules/src/nrf51822_serialization.rs +++ b/capsules/src/nrf51822_serialization.rs @@ -5,7 +5,7 @@ //! some nuances that keep the Nordic BLE serialization library happy. use kernel::{AppId, Callback, AppSlice, Driver, ReturnCode, Shared}; -use kernel::common::take_cell::TakeCell; +use kernel::common::take_cell::{MapCell, TakeCell}; use kernel::hil::uart::{self, UARTAdvanced, Client}; struct App { @@ -25,9 +25,9 @@ pub static mut READ_BUF: [u8; 600] = [0; 600]; // application. pub struct Nrf51822Serialization<'a, U: UARTAdvanced + 'a> { uart: &'a U, - app: TakeCell, - tx_buffer: TakeCell<&'static mut [u8]>, - rx_buffer: TakeCell<&'static mut [u8]>, + app: MapCell, + tx_buffer: TakeCell<'static, [u8]>, + rx_buffer: TakeCell<'static, [u8]>, } impl<'a, U: UARTAdvanced> Nrf51822Serialization<'a, U> { @@ -37,7 +37,7 @@ impl<'a, U: UARTAdvanced> Nrf51822Serialization<'a, U> { -> Nrf51822Serialization<'a, U> { Nrf51822Serialization { uart: uart, - app: TakeCell::empty(), + app: MapCell::empty(), tx_buffer: TakeCell::new(tx_buffer), rx_buffer: TakeCell::new(rx_buffer), } diff --git a/capsules/src/radio.rs b/capsules/src/radio.rs index d8dda34383..cc804e3884 100644 --- a/capsules/src/radio.rs +++ b/capsules/src/radio.rs @@ -9,7 +9,7 @@ use core::cell::Cell; use kernel::{AppId, Driver, Callback, AppSlice, Shared}; -use kernel::common::take_cell::TakeCell; +use kernel::common::take_cell::{MapCell, TakeCell}; use kernel::hil::radio; use kernel::returncode::ReturnCode; @@ -23,8 +23,8 @@ struct App { pub struct RadioDriver<'a, R: radio::Radio + 'a> { radio: &'a R, busy: Cell, - app: TakeCell, - kernel_tx: TakeCell<&'static mut [u8]>, + app: MapCell, + kernel_tx: TakeCell<'static, [u8]>, } impl<'a, R: radio::Radio> RadioDriver<'a, R> { @@ -32,7 +32,7 @@ impl<'a, R: radio::Radio> RadioDriver<'a, R> { RadioDriver { radio: radio, busy: Cell::new(false), - app: TakeCell::empty(), + app: MapCell::empty(), kernel_tx: TakeCell::empty(), } } diff --git a/capsules/src/rf233.rs b/capsules/src/rf233.rs index 4715d36b58..2315fed1aa 100644 --- a/capsules/src/rf233.rs +++ b/capsules/src/rf233.rs @@ -171,17 +171,17 @@ pub struct RF233<'a, S: spi::SpiMasterDevice + 'a> { irq_pin: &'a gpio::Pin, irq_ctl: &'a gpio::PinCtl, state: Cell, - tx_buf: TakeCell<&'static mut [u8]>, - rx_buf: TakeCell<&'static mut [u8]>, + tx_buf: TakeCell<'static, [u8]>, + rx_buf: TakeCell<'static, [u8]>, tx_len: Cell, tx_client: Cell>, rx_client: Cell>, addr: Cell, pan: Cell, seq: Cell, - spi_rx: TakeCell<&'static mut [u8]>, - spi_tx: TakeCell<&'static mut [u8]>, - spi_buf: TakeCell<&'static mut [u8]>, + spi_rx: TakeCell<'static, [u8]>, + spi_tx: TakeCell<'static, [u8]>, + spi_buf: TakeCell<'static, [u8]>, } fn interrupt_included(mask: u8, interrupt: u8) -> bool { diff --git a/capsules/src/si7021.rs b/capsules/src/si7021.rs index e60a0cef32..51c0a7abe6 100644 --- a/capsules/src/si7021.rs +++ b/capsules/src/si7021.rs @@ -56,7 +56,7 @@ pub struct SI7021<'a, A: time::Alarm + 'a> { alarm: &'a A, callback: Cell>, state: Cell, - buffer: TakeCell<&'static mut [u8]>, + buffer: TakeCell<'static, [u8]>, } impl<'a, A: time::Alarm + 'a> SI7021<'a, A> { diff --git a/capsules/src/spi.rs b/capsules/src/spi.rs index 5d5a61b715..5358b4f17c 100644 --- a/capsules/src/spi.rs +++ b/capsules/src/spi.rs @@ -4,7 +4,7 @@ use core::cell::Cell; use core::cmp; use kernel::{AppId, AppSlice, Callback, Driver, ReturnCode, Shared}; -use kernel::common::take_cell::TakeCell; +use kernel::common::take_cell::{MapCell, TakeCell}; use kernel::hil::spi::{SpiMasterDevice, SpiMasterClient}; use kernel::hil::spi::ClockPhase; use kernel::hil::spi::ClockPolarity; @@ -29,9 +29,9 @@ struct App { pub struct Spi<'a, S: SpiMasterDevice + 'a> { spi_master: &'a S, busy: Cell, - app: TakeCell, - kernel_read: TakeCell<&'static mut [u8]>, - kernel_write: TakeCell<&'static mut [u8]>, + app: MapCell, + kernel_read: TakeCell<'static, [u8]>, + kernel_write: TakeCell<'static, [u8]>, kernel_len: Cell, } @@ -40,7 +40,7 @@ impl<'a, S: SpiMasterDevice> Spi<'a, S> { Spi { spi_master: spi_master, busy: Cell::new(false), - app: TakeCell::empty(), + app: MapCell::empty(), kernel_len: Cell::new(0), kernel_read: TakeCell::empty(), kernel_write: TakeCell::empty(), diff --git a/capsules/src/tmp006.rs b/capsules/src/tmp006.rs index 5a4031fb17..e7971b593a 100644 --- a/capsules/src/tmp006.rs +++ b/capsules/src/tmp006.rs @@ -93,7 +93,7 @@ pub struct TMP006<'a> { repeated_mode: Cell, callback: Cell>, protocol_state: Cell, - buffer: TakeCell<&'static mut [u8]>, + buffer: TakeCell<'static, [u8]>, } impl<'a> TMP006<'a> { diff --git a/capsules/src/tsl2561.rs b/capsules/src/tsl2561.rs index 9dd93cfffe..6e4fcda5f4 100644 --- a/capsules/src/tsl2561.rs +++ b/capsules/src/tsl2561.rs @@ -195,7 +195,7 @@ pub struct TSL2561<'a> { interrupt_pin: &'a gpio::Pin, callback: Cell>, state: Cell, - buffer: TakeCell<&'static mut [u8]>, + buffer: TakeCell<'static, [u8]>, } impl<'a> TSL2561<'a> { diff --git a/capsules/src/virtual_i2c.rs b/capsules/src/virtual_i2c.rs index 48acf7719d..2193f6531c 100644 --- a/capsules/src/virtual_i2c.rs +++ b/capsules/src/virtual_i2c.rs @@ -13,12 +13,15 @@ pub struct MuxI2C<'a> { i2c: &'a i2c::I2CMaster, devices: List<'a, I2CDevice<'a>>, enabled: Cell, - inflight: TakeCell<&'a I2CDevice<'a>>, + inflight: Cell>>, } impl<'a> I2CHwMasterClient for MuxI2C<'a> { fn command_complete(&self, buffer: &'static mut [u8], error: Error) { - self.inflight.take().map(move |device| { device.command_complete(buffer, error); }); + self.inflight.get().map(move |device| { + self.inflight.set(None); + device.command_complete(buffer, error); + }); self.do_next_op(); } } @@ -29,7 +32,7 @@ impl<'a> MuxI2C<'a> { i2c: i2c, devices: List::new(), enabled: Cell::new(0), - inflight: TakeCell::empty(), + inflight: Cell::new(None), } } @@ -50,7 +53,7 @@ impl<'a> MuxI2C<'a> { } fn do_next_op(&self) { - if self.inflight.is_none() { + if self.inflight.get().is_none() { let mnode = self.devices.iter().find(|node| node.operation.get() != Op::Idle); mnode.map(|node| { node.buffer.take().map(|buf| { @@ -64,7 +67,7 @@ impl<'a> MuxI2C<'a> { } }); node.operation.set(Op::Idle); - self.inflight.replace(node); + self.inflight.set(Some(node)); }); } } @@ -82,7 +85,7 @@ pub struct I2CDevice<'a> { mux: &'a MuxI2C<'a>, addr: u8, enabled: Cell, - buffer: TakeCell<&'static mut [u8]>, + buffer: TakeCell<'static, [u8]>, operation: Cell, next: ListLink<'a, I2CDevice<'a>>, client: Cell>, diff --git a/capsules/src/virtual_spi.rs b/capsules/src/virtual_spi.rs index 20f5bef5d8..b03eb99eb1 100644 --- a/capsules/src/virtual_spi.rs +++ b/capsules/src/virtual_spi.rs @@ -10,7 +10,7 @@ use kernel::hil; pub struct MuxSpiMaster<'a, Spi: hil::spi::SpiMaster + 'a> { spi: &'a Spi, devices: List<'a, VirtualSpiMasterDevice<'a, Spi>>, - inflight: TakeCell<&'a VirtualSpiMasterDevice<'a, Spi>>, + inflight: Cell>>, } impl<'a, Spi: hil::spi::SpiMaster> hil::spi::SpiMasterClient for MuxSpiMaster<'a, Spi> { @@ -18,7 +18,8 @@ impl<'a, Spi: hil::spi::SpiMaster> hil::spi::SpiMasterClient for MuxSpiMaster<'a write_buffer: &'static mut [u8], read_buffer: Option<&'static mut [u8]>, len: usize) { - self.inflight.take().map(move |device| { + self.inflight.get().map(move |device| { + self.inflight.set(None); self.do_next_op(); device.read_write_done(write_buffer, read_buffer, len); }); @@ -30,12 +31,12 @@ impl<'a, Spi: hil::spi::SpiMaster> MuxSpiMaster<'a, Spi> { MuxSpiMaster { spi: spi, devices: List::new(), - inflight: TakeCell::empty(), + inflight: Cell::new(None), } } fn do_next_op(&self) { - if self.inflight.is_none() { + if self.inflight.get().is_none() { let mnode = self.devices.iter().find(|node| node.operation.get() != Op::Idle); mnode.map(|node| { self.spi.specify_chip_select(node.chip_select.get()); @@ -54,11 +55,10 @@ impl<'a, Spi: hil::spi::SpiMaster> MuxSpiMaster<'a, Spi> { Op::ReadWriteBytes(len) => { // Only async operations want to block by setting // the devices as inflight. - self.inflight.replace(node); + self.inflight.set(Some(node)); node.txbuffer.take().map(|txbuffer| { - node.rxbuffer.take().map(move |rxbuffer| { - self.spi.read_write_bytes(txbuffer, rxbuffer, len); - }); + let rxbuffer = node.rxbuffer.take(); + self.spi.read_write_bytes(txbuffer, rxbuffer, len); }); } Op::SetPolarity(pol) => { @@ -90,8 +90,8 @@ enum Op { pub struct VirtualSpiMasterDevice<'a, Spi: hil::spi::SpiMaster + 'a> { mux: &'a MuxSpiMaster<'a, Spi>, chip_select: Cell, - txbuffer: TakeCell<&'static mut [u8]>, - rxbuffer: TakeCell>, + txbuffer: TakeCell<'static, [u8]>, + rxbuffer: TakeCell<'static, [u8]>, operation: Cell, next: ListLink<'a, VirtualSpiMasterDevice<'a, Spi>>, client: Cell>, @@ -149,7 +149,7 @@ impl<'a, Spi: hil::spi::SpiMaster> hil::spi::SpiMasterDevice for VirtualSpiMaste len: usize) -> bool { self.txbuffer.replace(write_buffer); - self.rxbuffer.replace(read_buffer); + self.rxbuffer.put(read_buffer); self.operation.set(Op::ReadWriteBytes(len)); self.mux.do_next_op(); true diff --git a/chips/nrf51/src/clock.rs b/chips/nrf51/src/clock.rs index a83a395423..fb52bda618 100644 --- a/chips/nrf51/src/clock.rs +++ b/chips/nrf51/src/clock.rs @@ -7,9 +7,9 @@ //! Author: Philip Levis //! Date: August 18, 2016 +use core::cell::Cell; use core::mem; use kernel::common::VolatileCell; -use kernel::common::take_cell::TakeCell; struct Registers { pub tasks_hfclkstart: VolatileCell, @@ -79,7 +79,7 @@ pub enum XtalFreq { } pub struct Clock { - client: TakeCell<&'static ClockClient>, + client: Cell>, } pub trait ClockClient { @@ -90,7 +90,7 @@ pub trait ClockClient { fn event(&self); } -pub static mut CLOCK: Clock = Clock { client: TakeCell::empty() }; +pub static mut CLOCK: Clock = Clock { client: Cell::new(None) }; #[allow(non_snake_case)] fn CLK() -> &'static Registers { @@ -99,7 +99,7 @@ fn CLK() -> &'static Registers { impl Clock { pub fn set_client(&self, client: &'static ClockClient) { - self.client.replace(client); + self.client.set(Some(client)); } pub fn interrupt_enable(&self, interrupt: InterruptField) { diff --git a/chips/nrf51/src/gpio.rs b/chips/nrf51/src/gpio.rs index d7d0e829bf..37d699dbb7 100644 --- a/chips/nrf51/src/gpio.rs +++ b/chips/nrf51/src/gpio.rs @@ -8,7 +8,6 @@ use core::cell::Cell; use core::mem; use core::ops::{Index, IndexMut}; use kernel::common::VolatileCell; -use kernel::common::take_cell::TakeCell; use kernel::hil; use nvic; use peripheral_interrupts::NvicIdx; @@ -91,7 +90,7 @@ fn find_channel(pin: u8) -> i8 { pub struct GPIOPin { pin: u8, client_data: Cell, - client: TakeCell<&'static hil::gpio::Client>, + client: Cell>, } impl GPIOPin { @@ -99,12 +98,12 @@ impl GPIOPin { GPIOPin { pin: pin, client_data: Cell::new(0), - client: TakeCell::empty(), + client: Cell::new(None), } } pub fn set_client(&self, client: &'static C) { - self.client.replace(client); + self.client.set(Some(client)); } } @@ -189,7 +188,7 @@ impl hil::gpio::Pin for GPIOPin { impl GPIOPin { pub fn handle_interrupt(&self) { - self.client.map(|client| { client.fired(self.client_data.get()); }); + self.client.get().map(|client| { client.fired(self.client_data.get()); }); } } diff --git a/chips/nrf51/src/timer.rs b/chips/nrf51/src/timer.rs index fc4fd55d1c..9d33020ae7 100644 --- a/chips/nrf51/src/timer.rs +++ b/chips/nrf51/src/timer.rs @@ -19,9 +19,9 @@ //! Date: August 18, 2016 use chip; +use core::cell::Cell; use core::mem; use kernel::common::VolatileCell; -use kernel::common::take_cell::TakeCell; use kernel::hil; use nvic; use peripheral_interrupts::NvicIdx; @@ -64,19 +64,19 @@ pub enum Location { pub static mut TIMER0: Timer = Timer { which: Location::TIMER0, nvic: NvicIdx::TIMER0, - client: TakeCell::empty(), + client: Cell::new(None), }; pub static mut ALARM1: TimerAlarm = TimerAlarm { which: Location::TIMER1, nvic: NvicIdx::TIMER1, - client: TakeCell::empty(), + client: Cell::new(None), }; pub static mut TIMER2: Timer = Timer { which: Location::TIMER2, nvic: NvicIdx::TIMER2, - client: TakeCell::empty(), + client: Cell::new(None), }; #[allow(non_snake_case)] @@ -93,7 +93,7 @@ pub trait CompareClient { pub struct Timer { which: Location, nvic: NvicIdx, - client: TakeCell<&'static CompareClient>, + client: Cell>, } impl Timer { @@ -105,12 +105,12 @@ impl Timer { Timer { which: location, nvic: nvic, - client: TakeCell::empty(), + client: Cell::new(None), } } pub fn set_client(&self, client: &'static CompareClient) { - self.client.replace(client); + self.client.set(Some(client)); } pub fn start(&self) { @@ -223,7 +223,7 @@ impl Timer { /// events that is passed to the client. pub fn handle_interrupt(&self) { nvic::clear_pending(self.nvic); - self.client.map(|client| { + self.client.get().map(|client| { let mut val = 0; // For each of 4 possible compare events, if it's happened, // clear it and store its bit in val to pass in callback. @@ -242,7 +242,7 @@ impl Timer { pub struct TimerAlarm { which: Location, nvic: NvicIdx, - client: TakeCell<&'static hil::time::Client>, + client: Cell>, } // CC0 is used for capture @@ -260,7 +260,7 @@ impl TimerAlarm { TimerAlarm { which: location, nvic: nvic, - client: TakeCell::empty(), + client: Cell::new(None), } } @@ -276,7 +276,7 @@ impl TimerAlarm { } pub fn set_client(&self, client: &'static hil::time::Client) { - self.client.replace(client); + self.client.set(Some(client)); } pub fn start(&self) { @@ -294,7 +294,7 @@ impl TimerAlarm { #[inline(never)] pub fn handle_interrupt(&self) { self.clear_alarm(); - self.client.map(|client| { client.fired(); }); + self.client.get().map(|client| { client.fired(); }); } // Enable and disable interrupts use the bottom 4 bits diff --git a/chips/nrf51/src/uart.rs b/chips/nrf51/src/uart.rs index 4401af9c1a..b81a9d04a1 100644 --- a/chips/nrf51/src/uart.rs +++ b/chips/nrf51/src/uart.rs @@ -54,8 +54,8 @@ const UART_BASE: u32 = 0x40002000; pub struct UART { regs: *mut Registers, - client: TakeCell<&'static uart::Client>, - buffer: TakeCell<&'static mut [u8]>, + client: Cell>, + buffer: TakeCell<'static, [u8]>, len: Cell, index: Cell, } @@ -76,7 +76,7 @@ impl UART { pub const fn new() -> UART { UART { regs: UART_BASE as *mut Registers, - client: TakeCell::empty(), + client: Cell::new(None), buffer: TakeCell::empty(), len: Cell::new(0), index: Cell::new(0), @@ -165,7 +165,7 @@ impl UART { regs.task_stoptx.set(1 as u32); // Signal client write done - self.client.map(|client| { + self.client.get().map(|client| { self.buffer.take().map(|buffer| { client.transmit_complete(buffer, uart::Error::CommandComplete); }); @@ -209,7 +209,7 @@ impl UART { impl uart::UART for UART { fn set_client(&self, client: &'static uart::Client) { - self.client.replace(client); + self.client.set(Some(client)); } fn init(&self, params: uart::UARTParams) { diff --git a/chips/sam4l/src/dma.rs b/chips/sam4l/src/dma.rs index 0cfb7fbf96..7ebc22f588 100644 --- a/chips/sam4l/src/dma.rs +++ b/chips/sam4l/src/dma.rs @@ -132,7 +132,7 @@ pub struct DMAChannel { nvic: nvic::NvicIdx, pub client: Option<&'static mut DMAClient>, enabled: Cell, - buffer: TakeCell<&'static mut [u8]>, + buffer: TakeCell<'static, [u8]>, } pub trait DMAClient { diff --git a/chips/sam4l/src/flashcalw.rs b/chips/sam4l/src/flashcalw.rs index 1e148a5d92..ad0df495e1 100644 --- a/chips/sam4l/src/flashcalw.rs +++ b/chips/sam4l/src/flashcalw.rs @@ -26,7 +26,7 @@ use core::cell::Cell; use core::mem; use kernel::common::VolatileCell; -use kernel::common::take_cell::TakeCell; +use kernel::common::take_cell::MapCell; use nvic; use pm; @@ -159,10 +159,10 @@ pub struct FLASHCALW { pb_clock: pm::Clock, error_status: Cell, ready: Cell, - client: TakeCell<&'static Client>, + client: Cell>, current_state: Cell, current_command: Cell, - page_buffer: TakeCell<[u8; PAGE_SIZE as usize]>, + page_buffer: MapCell<[u8; PAGE_SIZE as usize]>, } // static instance for the board. Only one FLASHCALW on chip. @@ -215,10 +215,10 @@ impl FLASHCALW { pb_clock: pm::Clock::PBB(pb_clk), error_status: Cell::new(0), ready: Cell::new(true), - client: TakeCell::empty(), + client: Cell::new(None), current_state: Cell::new(FlashState::Unconfigured), current_command: Cell::new(Command::None), - page_buffer: TakeCell::new([0; PAGE_SIZE as usize]), + page_buffer: MapCell::new([0; PAGE_SIZE as usize]), } } @@ -280,20 +280,21 @@ impl FLASHCALW { self.current_command.set(Command::None); self.current_state.set(FlashState::Ready); - // call command complete with error - match error_status { - 4 => { - self.client.map(|value| { value.command_complete(Error::LockE); }); - } - 8 => { - self.client.map(|value| { value.command_complete(Error::ProgE); }); - } - 12 => { - self.client.map(|value| { value.command_complete(Error::LockProgE); }); + self.client.get().map(|client| { + // call command complete with error + match error_status { + 4 => { + client.command_complete(Error::LockE); + } + 8 => { + client.command_complete(Error::ProgE); + } + 12 => { + client.command_complete(Error::LockProgE); + } + _ => {} } - _ => {} - } - return; + }); } // Part of a command succeeded -- continue onto next steps. @@ -360,7 +361,7 @@ impl FLASHCALW { // If the command is finished call the complete CB. if self.current_command.get() == Command::None && self.current_state.get() == FlashState::Ready { - self.client.map(|value| { value.command_complete(Error::CommandComplete); }); + self.client.get().map(|value| { value.command_complete(Error::CommandComplete); }); } } @@ -739,7 +740,7 @@ impl FLASHCALW { } } // replace the page buffer in the take cell - self.page_buffer.put(Some(buffer)); + self.page_buffer.put(buffer); } // returns the error_status (useful for debugging). @@ -751,7 +752,7 @@ impl FLASHCALW { // Implementation of high level calls using the low-lv functions. impl FLASHCALW { pub fn set_client(&self, client: &'static Client) { - self.client.put(Some(client)); + self.client.set(Some(client)); } pub fn configure(&mut self) { diff --git a/chips/sam4l/src/gpio.rs b/chips/sam4l/src/gpio.rs index f493d53607..0ccac85d9e 100644 --- a/chips/sam4l/src/gpio.rs +++ b/chips/sam4l/src/gpio.rs @@ -4,7 +4,6 @@ use self::Pin::*; use core::cell::Cell; use core::mem; use core::ops::{Index, IndexMut}; -use kernel::common::take_cell::TakeCell; use kernel::common::volatile_cell::VolatileCell; use kernel::hil; use nvic; @@ -281,7 +280,7 @@ pub struct GPIOPin { nvic: nvic::NvicIdx, pin_mask: u32, client_data: Cell, - client: TakeCell<&'static hil::gpio::Client>, + client: Cell>, } impl GPIOPin { @@ -291,12 +290,12 @@ impl GPIOPin { nvic: nvic, pin_mask: 1 << ((pin as u32) % 32), client_data: Cell::new(0), - client: TakeCell::empty(), + client: Cell::new(None), } } pub fn set_client(&self, client: &'static C) { - self.client.replace(client); + self.client.set(Some(client)); } pub fn select_peripheral(&self, function: PeripheralFunction) { @@ -411,7 +410,7 @@ impl GPIOPin { } pub fn handle_interrupt(&self) { - self.client.map(|client| { client.fired(self.client_data.get()); }); + self.client.get().map(|client| { client.fired(self.client_data.get()); }); } pub fn disable_schmidtt_trigger(&self) { diff --git a/chips/sam4l/src/i2c.rs b/chips/sam4l/src/i2c.rs index 117d9f17d5..b95246014e 100644 --- a/chips/sam4l/src/i2c.rs +++ b/chips/sam4l/src/i2c.rs @@ -104,20 +104,20 @@ pub struct I2CHw { slave_registers: Option<*mut TWISRegisters>, // Pointer to the I2C TWIS registers in memory master_clock: pm::Clock, slave_clock: Option, - dma: TakeCell<&'static DMAChannel>, + dma: Cell>, dma_pids: (DMAPeripheral, DMAPeripheral), nvic: nvic::NvicIdx, slave_nvic: Option, - master_client: TakeCell<&'static hil::i2c::I2CHwMasterClient>, - slave_client: TakeCell<&'static hil::i2c::I2CHwSlaveClient>, - on_deck: TakeCell<(DMAPeripheral, usize)>, + master_client: Cell>, + slave_client: Cell>, + on_deck: Cell>, slave_enabled: Cell, my_slave_address: Cell, - slave_read_buffer: TakeCell<&'static mut [u8]>, + slave_read_buffer: TakeCell<'static, [u8]>, slave_read_buffer_len: Cell, slave_read_buffer_index: Cell, - slave_write_buffer: TakeCell<&'static mut [u8]>, + slave_write_buffer: TakeCell<'static, [u8]>, slave_write_buffer_len: Cell, slave_write_buffer_index: Cell, } @@ -176,13 +176,13 @@ impl I2CHw { slave_registers: slave_base_addr, master_clock: master_clock, slave_clock: slave_clock, - dma: TakeCell::empty(), + dma: Cell::new(None), dma_pids: (dma_rx, dma_tx), nvic: nvic, slave_nvic: slave_nvic, - master_client: TakeCell::empty(), - slave_client: TakeCell::empty(), - on_deck: TakeCell::empty(), + master_client: Cell::new(None), + slave_client: Cell::new(None), + on_deck: Cell::new(None), slave_enabled: Cell::new(false), my_slave_address: Cell::new(0), @@ -225,15 +225,15 @@ impl I2CHw { } pub fn set_dma(&self, dma: &'static DMAChannel) { - self.dma.replace(dma); + self.dma.set(Some(dma)); } pub fn set_master_client(&self, client: &'static hil::i2c::I2CHwMasterClient) { - self.master_client.replace(client); + self.master_client.set(Some(client)); } pub fn set_slave_client(&self, client: &'static hil::i2c::I2CHwSlaveClient) { - self.slave_client.replace(client); + self.slave_client.set(Some(client)); } pub fn handle_interrupt(&self) { @@ -252,7 +252,9 @@ impl I2CHw { _ => None }; - match self.on_deck.take() { + let on_deck = self.on_deck.get(); + self.on_deck.set(None); + match on_deck { None => { write_volatile(&mut regs.command, 0); write_volatile(&mut regs.next_command, 0); @@ -263,11 +265,11 @@ impl I2CHw { write_volatile(&mut regs.control, 0x1 << 7); write_volatile(&mut regs.control, 0x1 << 1); - self.master_client.map(|client| { - let buf = match self.dma.take() { + self.master_client.get().map(|client| { + let buf = match self.dma.get() { Some(dma) => { let b = dma.abort_xfer(); - self.dma.replace(dma); + self.dma.set(Some(dma)); b } None => None, @@ -283,7 +285,7 @@ impl I2CHw { | (1 << 8) // ANAK - Address not ACKd | (1 << 9) // DNAK - Data not ACKd | (1 << 10)); // ARBLST - Abitration lost - self.dma.map(|dma| { + self.dma.get().map(|dma| { let buf = dma.abort_xfer().unwrap(); dma.prepare_xfer(dma_periph, buf, len); dma.start_xfer(); @@ -344,7 +346,7 @@ impl I2CHw { } pub fn write(&self, chip: u8, flags: usize, data: &'static mut [u8], len: u8) { - self.dma.map(move |dma| { + self.dma.get().map(move |dma| { dma.enable(); dma.prepare_xfer(self.dma_pids.1, data, len as usize); self.setup_xfer(chip, flags, false, len); @@ -354,7 +356,7 @@ impl I2CHw { } pub fn read(&self, chip: u8, flags: usize, data: &'static mut [u8], len: u8) { - self.dma.map(move |dma| { + self.dma.get().map(move |dma| { dma.enable(); dma.prepare_xfer(self.dma_pids.0, data, len as usize); self.setup_xfer(chip, flags, true, len); @@ -364,12 +366,12 @@ impl I2CHw { } pub fn write_read(&self, chip: u8, data: &'static mut [u8], split: u8, read_len: u8) { - self.dma.map(move |dma| { + self.dma.get().map(move |dma| { dma.enable(); dma.prepare_xfer(self.dma_pids.1, data, split as usize); self.setup_xfer(chip, START, false, split); self.setup_nextfer(chip, START | STOP, true, read_len); - self.on_deck.replace((self.dma_pids.0, read_len as usize)); + self.on_deck.set(Some((self.dma_pids.0, read_len as usize))); dma.start_xfer(); }); } @@ -451,7 +453,7 @@ impl I2CHw { } else { // Call to upper layers asking for a buffer to send - self.slave_client.map(|client| { client.read_expected(); }); + self.slave_client.get().map(|client| { client.read_expected(); }); } } else { @@ -470,7 +472,7 @@ impl I2CHw { } else { // Call to upper layers asking for a buffer to // read into. - self.slave_client.map(|client| { client.write_expected(); }); + self.slave_client.get().map(|client| { client.write_expected(); }); } } @@ -488,7 +490,7 @@ impl I2CHw { if status & (1 << 5) > 0 { // read - self.slave_client.map(|client| { + self.slave_client.get().map(|client| { self.slave_read_buffer.take().map(|buffer| { client.command_complete(buffer, nbytes as u8, @@ -512,7 +514,7 @@ impl I2CHw { regs.receive_holding.get(); } - self.slave_client.map(|client| { + self.slave_client.get().map(|client| { self.slave_write_buffer.take().map(|buffer| { client.command_complete(buffer, nbytes as u8, diff --git a/chips/sam4l/src/spi.rs b/chips/sam4l/src/spi.rs index 910edf97d6..ea42200bc5 100644 --- a/chips/sam4l/src/spi.rs +++ b/chips/sam4l/src/spi.rs @@ -6,7 +6,6 @@ use dma::DMAChannel; use dma::DMAClient; use dma::DMAPeripheral; -use kernel::common::take_cell::TakeCell; use kernel::common::volatile_cell::VolatileCell; use kernel::hil::spi; @@ -61,9 +60,9 @@ pub enum Peripheral { /// The SAM4L supports four peripherals. pub struct Spi { registers: *mut SpiRegisters, - client: TakeCell<&'static SpiMasterClient>, - dma_read: TakeCell<&'static mut DMAChannel>, - dma_write: TakeCell<&'static mut DMAChannel>, + client: Cell>, + dma_read: Cell>, + dma_write: Cell>, // keep track of which how many DMA transfers are pending to correctly // issue completion event only after both complete. transfers_in_progress: Cell, @@ -77,9 +76,9 @@ impl Spi { pub const fn new() -> Spi { Spi { registers: SPI_BASE as *mut SpiRegisters, - client: TakeCell::empty(), - dma_read: TakeCell::empty(), - dma_write: TakeCell::empty(), + client: Cell::new(None), + dma_read: Cell::new(None), + dma_write: Cell::new(None), transfers_in_progress: Cell::new(0), dma_length: Cell::new(0), } @@ -97,8 +96,8 @@ impl Spi { pub fn disable(&self) { let regs: &mut SpiRegisters = unsafe { mem::transmute(self.registers) }; - self.dma_read.map(|read| read.disable()); - self.dma_write.map(|write| write.disable()); + self.dma_read.get().map(|read| read.disable()); + self.dma_write.get().map(|write| write.disable()); regs.cr.set(0b10); } @@ -207,9 +206,9 @@ impl Spi { } /// Set the DMA channels used for reading and writing. - pub fn set_dma(&mut self, read: &'static mut DMAChannel, write: &'static mut DMAChannel) { - self.dma_read.replace(read); - self.dma_write.replace(write); + pub fn set_dma(&mut self, read: &'static DMAChannel, write: &'static DMAChannel) { + self.dma_read.set(Some(read)); + self.dma_write.set(Some(write)); } fn enable_clock(&self) { @@ -223,7 +222,7 @@ impl spi::SpiMaster for Spi { type ChipSelect = u8; fn set_client(&self, client: &'static SpiMasterClient) { - self.client.replace(client); + self.client.set(Some(client)); } /// By default, initialize SPI to operate at 40KHz, clock is @@ -319,7 +318,7 @@ impl spi::SpiMaster for Spi { // The ordering of these operations matters. // For transfers 4 bytes or longer, this will work as expected. // For shorter transfers, the first byte will be missing. - self.dma_write.map(move |write| { + self.dma_write.get().map(move |write| { write.enable(); write.do_xfer(DMAPeripheral::SPI_TX, write_buffer, count); }); @@ -328,7 +327,7 @@ impl spi::SpiMaster for Spi { // of the option. `map()` checks this for us. read_buffer.map(|rbuf| { self.transfers_in_progress.set(2); - self.dma_read.map(move |read| { + self.dma_read.get().map(move |read| { read.enable(); read.do_xfer(DMAPeripheral::SPI_RX, rbuf, count); }); @@ -416,13 +415,13 @@ impl DMAClient for Spi { self.transfers_in_progress.set(self.transfers_in_progress.get() - 1); if self.transfers_in_progress.get() == 0 { - let txbuf = self.dma_write.map_or(None, |dma| { + let txbuf = self.dma_write.get().map_or(None, |dma| { let buf = dma.abort_xfer(); dma.disable(); buf }); - let rxbuf = self.dma_read.map_or(None, |dma| { + let rxbuf = self.dma_read.get().map_or(None, |dma| { let buf = dma.abort_xfer(); dma.disable(); buf @@ -431,6 +430,7 @@ impl DMAClient for Spi { let len = self.dma_length.get(); self.dma_length.set(0); self.client + .get() .map(|cb| { txbuf.map(|txbuf| { cb.read_write_done(txbuf, rxbuf, len); }); }); } } diff --git a/chips/sam4l/src/usart.rs b/chips/sam4l/src/usart.rs index 28964823f3..57a243e599 100644 --- a/chips/sam4l/src/usart.rs +++ b/chips/sam4l/src/usart.rs @@ -2,7 +2,6 @@ use core::cell::Cell; use core::cmp; use core::mem; use dma; -use kernel::common::take_cell::TakeCell; use kernel::common::volatile_cell::VolatileCell; // other modules use kernel::hil; @@ -67,6 +66,7 @@ enum UsartMode { Unused, } +#[derive(Copy,Clone)] enum UsartClient<'a> { Uart(&'a hil::uart::Client), SpiMaster(&'a hil::spi::SpiMasterClient), @@ -82,14 +82,14 @@ pub struct USART { usart_tx_state: Cell, usart_rx_state: Cell, - rx_dma: TakeCell<&'static dma::DMAChannel>, + rx_dma: Cell>, rx_dma_peripheral: dma::DMAPeripheral, rx_len: Cell, - tx_dma: TakeCell<&'static dma::DMAChannel>, + tx_dma: Cell>, tx_dma_peripheral: dma::DMAPeripheral, tx_len: Cell, - client: TakeCell>, + client: Cell>>, spi_chip_select: Cell>, } @@ -134,15 +134,15 @@ impl USART { usart_tx_state: Cell::new(USARTStateTX::Idle), // these get defined later by `chip.rs` - rx_dma: TakeCell::empty(), + rx_dma: Cell::new(None), rx_dma_peripheral: rx_dma_peripheral, rx_len: Cell::new(0), - tx_dma: TakeCell::empty(), + tx_dma: Cell::new(None), tx_dma_peripheral: tx_dma_peripheral, tx_len: Cell::new(0), // this gets defined later by `main.rs` - client: TakeCell::empty(), + client: Cell::new(None), // This is only used if the USART is in SPI mode. spi_chip_select: Cell::new(None), @@ -150,8 +150,8 @@ impl USART { } pub fn set_dma(&self, rx_dma: &'static dma::DMAChannel, tx_dma: &'static dma::DMAChannel) { - self.rx_dma.replace(rx_dma); - self.tx_dma.replace(tx_dma); + self.rx_dma.set(Some(rx_dma)); + self.tx_dma.set(Some(tx_dma)); } pub fn enable_rx(&self) { @@ -190,7 +190,7 @@ impl USART { // get buffer let mut length = 0; - let buffer = self.rx_dma.map_or(None, |rx_dma| { + let buffer = self.rx_dma.get().map_or(None, |rx_dma| { length = self.rx_len.get() - rx_dma.transfer_counter(); let buf = rx_dma.abort_xfer(); rx_dma.disable(); @@ -199,12 +199,12 @@ impl USART { self.rx_len.set(0); // alert client - self.client.map(|usartclient| { + self.client.get().map(|usartclient| { buffer.map(|buf| match usartclient { - &mut UsartClient::Uart(client) => { + UsartClient::Uart(client) => { client.receive_complete(buf, length, error); } - &mut UsartClient::SpiMaster(_) => {} + UsartClient::SpiMaster(_) => {} }); }); } @@ -218,7 +218,7 @@ impl USART { // get buffer let mut length = 0; - let buffer = self.tx_dma.map_or(None, |tx_dma| { + let buffer = self.tx_dma.get().map_or(None, |tx_dma| { length = self.tx_len.get() - tx_dma.transfer_counter(); let buf = tx_dma.abort_xfer(); tx_dma.disable(); @@ -227,12 +227,12 @@ impl USART { self.tx_len.set(0); // alert client - self.client.map(|usartclient| { + self.client.get().map(|usartclient| { buffer.map(|buf| match usartclient { - &mut UsartClient::Uart(client) => { + UsartClient::Uart(client) => { client.receive_complete(buf, length, error); } - &mut UsartClient::SpiMaster(_) => {} + UsartClient::SpiMaster(_) => {} }); }); } @@ -434,23 +434,23 @@ impl dma::DMAClient for USART { self.usart_rx_state.set(USARTStateRX::Idle); // get buffer - let buffer = self.rx_dma.map_or(None, |rx_dma| { + let buffer = self.rx_dma.get().map_or(None, |rx_dma| { let buf = rx_dma.abort_xfer(); rx_dma.disable(); buf }); // alert client - self.client.map(|usartclient| { + self.client.get().map(|usartclient| { buffer.map(|buf| { let length = self.rx_len.get(); match usartclient { - &mut UsartClient::Uart(client) => { + UsartClient::Uart(client) => { client.receive_complete(buf, length, hil::uart::Error::CommandComplete); } - &mut UsartClient::SpiMaster(_) => {} + UsartClient::SpiMaster(_) => {} } }); }); @@ -463,19 +463,19 @@ impl dma::DMAClient for USART { self.usart_tx_state.set(USARTStateTX::Transfer_Completing); // get buffer - let buffer = self.tx_dma.map_or(None, |tx_dma| { + let buffer = self.tx_dma.get().map_or(None, |tx_dma| { let buf = tx_dma.abort_xfer(); tx_dma.disable(); buf }); // alert client - self.client.map(|usartclient| { + self.client.get().map(|usartclient| { buffer.map(|buf| match usartclient { - &mut UsartClient::Uart(client) => { + UsartClient::Uart(client) => { client.transmit_complete(buf, hil::uart::Error::CommandComplete); } - &mut UsartClient::SpiMaster(_) => {} + UsartClient::SpiMaster(_) => {} }); }); self.tx_len.set(0); @@ -497,13 +497,13 @@ impl dma::DMAClient for USART { self.usart_tx_state.set(USARTStateTX::Transfer_Completing); // get buffer - let txbuf = self.tx_dma.map_or(None, |dma| { + let txbuf = self.tx_dma.get().map_or(None, |dma| { let buf = dma.abort_xfer(); dma.disable(); buf }); - let rxbuf = self.rx_dma.map_or(None, |dma| { + let rxbuf = self.rx_dma.get().map_or(None, |dma| { let buf = dma.abort_xfer(); dma.disable(); buf @@ -512,10 +512,10 @@ impl dma::DMAClient for USART { let len = self.tx_len.get(); // alert client - self.client.map(|usartclient| { + self.client.get().map(|usartclient| { txbuf.map(|tbuf| match usartclient { - &mut UsartClient::Uart(_) => {} - &mut UsartClient::SpiMaster(client) => { + UsartClient::Uart(_) => {} + UsartClient::SpiMaster(client) => { client.read_write_done(tbuf, rxbuf, len); } }); @@ -533,7 +533,7 @@ impl dma::DMAClient for USART { impl hil::uart::UART for USART { fn set_client(&self, client: &'static hil::uart::Client) { let c = UsartClient::Uart(client); - self.client.replace(c); + self.client.set(Some(c)); } fn init(&self, params: hil::uart::UARTParams) { @@ -587,7 +587,7 @@ impl hil::uart::UART for USART { self.usart_tx_state.set(USARTStateTX::DMA_Transmitting); // set up dma transfer and start transmission - self.tx_dma.map(move |dma| { + self.tx_dma.get().map(move |dma| { dma.enable(); dma.do_xfer(self.tx_dma_peripheral, tx_data, tx_len); self.tx_len.set(tx_len); @@ -610,7 +610,7 @@ impl hil::uart::UART for USART { self.usart_rx_state.set(USARTStateRX::DMA_Receiving); // set up dma transfer and start reception - self.rx_dma.map(move |dma| { + self.rx_dma.get().map(move |dma| { dma.enable(); dma.do_xfer(self.rx_dma_peripheral, rx_buffer, length); self.rx_len.set(rx_len); @@ -632,7 +632,7 @@ impl hil::uart::UARTAdvanced for USART { self.usart_rx_state.set(USARTStateRX::DMA_Receiving); // set up dma transfer and start reception - self.rx_dma.map(move |dma| { + self.rx_dma.get().map(move |dma| { dma.enable(); let length = rx_buffer.len(); dma.do_xfer(self.rx_dma_peripheral, rx_buffer, length); @@ -653,7 +653,7 @@ impl hil::uart::UARTAdvanced for USART { self.usart_rx_state.set(USARTStateRX::DMA_Receiving); // set up dma transfer and start reception - self.rx_dma.map(move |dma| { + self.rx_dma.get().map(move |dma| { dma.enable(); let length = rx_buffer.len(); dma.do_xfer(self.rx_dma_peripheral, rx_buffer, length); @@ -691,7 +691,7 @@ impl hil::spi::SpiMaster for USART { fn set_client(&self, client: &'static hil::spi::SpiMasterClient) { let c = UsartClient::SpiMaster(client); - self.client.replace(c); + self.client.set(Some(c)); } fn is_busy(&self) -> bool { @@ -724,13 +724,13 @@ impl hil::spi::SpiMaster for USART { }); // Set up dma transfer and start transmission - self.tx_dma.map(move |dma| { + self.tx_dma.get().map(move |dma| { dma.enable(); dma.do_xfer(self.tx_dma_peripheral, write_buffer, count); }); read_buffer.map(|rbuf| { - self.rx_dma.map(move |read| { + self.rx_dma.get().map(move |read| { read.enable(); read.do_xfer(self.rx_dma_peripheral, rbuf, count); }); diff --git a/kernel/src/common/take_cell.rs b/kernel/src/common/take_cell.rs index 4e40e76ae8..61f4da4a86 100644 --- a/kernel/src/common/take_cell.rs +++ b/kernel/src/common/take_cell.rs @@ -1,25 +1,26 @@ -use core::cell::UnsafeCell; -use core::ptr; +use core::{mem, ptr}; +use core::cell::{Cell, UnsafeCell}; -/// A mutable memory location that enforces borrow rules at runtime without -/// possible panics. +/// A shared reference to a mutable reference. /// -/// A `TakeCell` is a potential reference to mutable memory. Borrow rules are -/// enforced by forcing clients to either move the memory out of the cell or -/// operate on a borrow within a closure. You can think of a `TakeCell` as a -/// between an `Option` wrapped in a `RefCell` --- attempts to take the value -/// from inside a `TakeCell` may fail by returning `None`. -pub struct TakeCell { - val: UnsafeCell>, +/// A `TakeCell` wraps potential reference to mutable memory that may be +/// available at a given point. Rather than enforcing borrow rules at +/// compile-time, `TakeCell` enables multiple clients to hold references to it, +/// but ensures that only one referrer has access to the underlying mutable +/// reference at a time. Clients either move the memory out of the `TakeCell` or +/// operate on a borrow within a closure. Attempts to take the value from inside +/// a `TakeCell` may fail by returning `None`. +pub struct TakeCell<'a, T: 'a + ?Sized> { + val: UnsafeCell>, } -impl TakeCell { - pub const fn empty() -> TakeCell { +impl<'a, T: ?Sized> TakeCell<'a, T> { + pub const fn empty() -> TakeCell<'a, T> { TakeCell { val: UnsafeCell::new(None) } } /// Creates a new `TakeCell` containing `value` - pub const fn new(value: T) -> TakeCell { + pub fn new(value: &'a mut T) -> TakeCell<'a, T> { TakeCell { val: UnsafeCell::new(Some(value)) } } @@ -31,9 +32,9 @@ impl TakeCell { unsafe { (&*self.val.get()).is_some() } } - /// Takes the value out of the `TakeCell` leaving a `None` in it's place. If - /// the value has already been taken elsewhere (and not `replace`ed), the - /// returned `Option` will be empty. + /// Takes the mutable reference out of the `TakeCell` leaving a `None` in + /// it's place. If the value has already been taken elsewhere (and not + /// `replace`ed), the returned `Option` will be empty. /// /// # Examples /// @@ -45,14 +46,15 @@ impl TakeCell { /// x.take(); /// assert_eq!(y.take(), None); /// ``` - pub fn take(&self) -> Option { + pub fn take(&self) -> Option<&'a mut T> { unsafe { let inner = &mut *self.val.get(); inner.take() } } - pub fn put(&self, val: Option) { + /// Stores `val` in the `TakeCell` + pub fn put(&self, val: Option<&'a mut T>) { let _ = self.take(); let ptr = self.val.get(); unsafe { @@ -62,7 +64,7 @@ impl TakeCell { /// Replaces the contents of the `TakeCell` with `val`. If the cell was not /// empty, the previous value is returned, otherwise `None` is returned. - pub fn replace(&self, val: T) -> Option { + pub fn replace(&self, val: &'a mut T) -> Option<&'a mut T> { let prev = self.take(); let ptr = self.val.get(); unsafe { @@ -102,6 +104,7 @@ impl TakeCell { }) } + /// Performs a `map` or returns a default value if the `TakeCell` is empty pub fn map_or(&self, default: R, closure: F) -> R where F: FnOnce(&mut T) -> R { @@ -113,9 +116,12 @@ impl TakeCell { }) } + /// Uses the first closure (`modify`) to modify the value in the `TakeCell` + /// if it is present, otherwise, fills the `TakeCell` with the result of + /// `mkval`. pub fn modify_or_replace(&self, modify: F, mkval: G) where F: FnOnce(&mut T), - G: FnOnce() -> T + G: FnOnce() -> &'a mut T { let val = match self.take() { Some(mut val) => { @@ -127,3 +133,131 @@ impl TakeCell { self.replace(val); } } + +/// A mutable memory location that enforces borrow rules at runtime without +/// possible panics. +/// +/// A `MapCell` is a potential reference to mutable memory. Borrow rules are +/// enforced by forcing clients to either move the memory out of the cell or +/// operate on a borrow within a closure. You can think of a `MapCell` as an +/// `Option` wrapped in a `RefCell` --- attempts to take the value from inside a +/// `MapCell` may fail by returning `None`. +pub struct MapCell { + val: UnsafeCell, + occupied: Cell, +} + +impl MapCell { + pub fn empty() -> MapCell { + MapCell { + val: unsafe { mem::uninitialized() }, + occupied: Cell::new(false), + } + } + + /// Creates a new `MapCell` containing `value` + pub const fn new(value: T) -> MapCell { + MapCell { + val: UnsafeCell::new(value), + occupied: Cell::new(true), + } + } + + pub fn is_none(&self) -> bool { + !self.is_some() + } + + pub fn is_some(&self) -> bool { + self.occupied.get() + } + + /// Takes the value out of the `MapCell` leaving it empty. If + /// the value has already been taken elsewhere (and not `replace`ed), the + /// returned `Option` will be `None`. + /// + /// # Examples + /// + /// ``` + /// let cell = MapCell::new(1234); + /// let x = &cell; + /// let y = &cell; + /// + /// assert_eq!(x.take(), Some(1234)); + /// assert_eq!(y.take(), None); + /// ``` + pub fn take(&self) -> Option { + if self.is_none() { + return None; + } else { + self.occupied.set(false); + unsafe { Some(ptr::replace(self.val.get(), mem::uninitialized())) } + } + } + + pub fn put(&self, val: T) { + self.occupied.set(true); + unsafe { + ptr::write(self.val.get(), val); + } + } + + /// Replaces the contents of the `MapCell` with `val`. If the cell was not + /// empty, the previous value is returned, otherwise `None` is returned. + pub fn replace(&self, val: T) -> Option { + if self.is_some() { + unsafe { Some(ptr::replace(self.val.get(), val)) } + } else { + self.put(val); + None + } + } + + /// Allows `closure` to borrow the contents of the `MapCell` if-and-only-if + /// it is not `take`n already. The state of the `MapCell` is unchanged + /// after the closure completes. + /// + /// # Examples + /// + /// ``` + /// let cell = MapCell::new(1234); + /// let x = &cell; + /// let y = &cell; + /// + /// x.map(|value| { + /// // We have mutable access to the value while in the closure + /// value += 1; + /// }); + /// + /// // After the closure completes, the mutable memory is still in the cell, + /// // but potentially changed. + /// assert_eq!(y.take(), Some(1235)); + /// ``` + pub fn map(&self, closure: F) -> Option + where F: FnOnce(&mut T) -> R + { + if self.is_some() { + self.occupied.set(false); + let valref = unsafe { &mut *self.val.get() }; + let res = closure(valref); + self.occupied.set(true); + Some(res) + } else { + None + } + } + + pub fn map_or(&self, default: R, closure: F) -> R + where F: FnOnce(&mut T) -> R + { + self.map(closure).unwrap_or(default) + } + + pub fn modify_or_replace(&self, modify: F, mkval: G) + where F: FnOnce(&mut T), + G: FnOnce() -> T + { + if self.map(modify).is_none() { + self.put(mkval()); + } + } +}