diff --git a/src/lib.rs b/src/lib.rs index 35caa9c..aa98ab7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,8 @@ extern crate std; pub use stack::Stack; pub use stack::GuardedStack; +pub use stack::SliceStack; + pub use generator::Generator; #[cfg(unix)] diff --git a/src/stack.rs b/src/stack.rs index a861ddd..f95c02d 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -1,7 +1,6 @@ // This file is part of libfringe, a low-level green threading library. // Copyright (c) edef // See the LICENSE file included in this distribution. -//! Traits for stacks. /// A trait for objects that hold ownership of a stack. pub trait Stack { @@ -20,3 +19,22 @@ pub trait Stack { /// A guarded stack must guarantee that any access of data at addresses `limit()` to /// `limit().offset(4096)` will abnormally terminate the program. pub unsafe trait GuardedStack {} + +/// SliceStack holds a non-guarded stack allocated elsewhere and provided as a mutable +/// slice. +pub struct SliceStack<'a>(pub &'a mut [u8]); + +impl<'a> Stack for SliceStack<'a> { + #[inline(always)] + fn base(&self) -> *mut u8 { + // The slice cannot wrap around the address space, so the conversion from usize + // to isize will not wrap either. + let len: isize = self.0.len() as isize; + unsafe { self.limit().offset(len) } + } + + #[inline(always)] + fn limit(&self) -> *mut u8 { + self.0.as_ptr() as *mut u8 + } +} diff --git a/tests/generator.rs b/tests/generator.rs index 5945519..650fe88 100644 --- a/tests/generator.rs +++ b/tests/generator.rs @@ -3,7 +3,7 @@ // See the LICENSE file included in this distribution. extern crate fringe; -use fringe::OsStack; +use fringe::{OsStack, SliceStack}; use fringe::generator::Generator; fn new_add_one() -> Generator { @@ -59,3 +59,19 @@ fn panic_safety() { let mut wrapper = Wrapper { gen: gen }; wrapper.gen.resume(()); } + +#[test] +fn with_slice_stack() { + let mut memory = [0; 1024]; + let stack = SliceStack(&mut memory); + let mut add_one = unsafe { + Generator::unsafe_new(stack, move |yielder, mut input| { + loop { + if input == 0 { break } + input = yielder.generate(input + 1) + } + }) + }; + assert_eq!(add_one.resume(1), Some(2)); + assert_eq!(add_one.resume(2), Some(3)); +} diff --git a/tests/stack.rs b/tests/stack.rs index e2dd5d0..6d6755b 100644 --- a/tests/stack.rs +++ b/tests/stack.rs @@ -3,17 +3,24 @@ // See the LICENSE file included in this distribution. extern crate fringe; -use fringe::{Stack, OsStack}; +use fringe::{Stack, SliceStack, OsStack}; #[test] -fn default_stack() { +fn slice_stack() { + let mut memory = [0; 1024]; + let stack = SliceStack(&mut memory); + assert_eq!(stack.base() as isize - stack.limit() as isize, 1024); +} + +#[test] +fn default_os_stack() { let stack = OsStack::new(0).unwrap(); // Make sure the topmost page of the stack, at least, is accessible. unsafe { *(stack.base().offset(-1)) = 0; } } #[test] -fn one_page_stack() { +fn one_page_os_stack() { let stack = OsStack::new(4096).unwrap(); // Make sure the topmost page of the stack, at least, is accessible. unsafe { *(stack.base().offset(-1)) = 0; }