<commit_before>use std::fmt;
use super::atom::Atom;
use super::parser;
use super::token::{Token, Tokenizer, CurlyAroundTokenizer};

#[derive(Debug, PartialEq)]
pub enum Expr {
    Atom(Atom),

    // ( ... )
    Tuple(Vec<Expr>),

    // [ ... ]
    Array(Vec<Expr>),

    // { key val ... }
    Map(Vec<(Expr, Expr)>),
}

impl Expr {
    pub fn parse_iter<'a, I>(mut iter: I) -> Result<Expr, ()>
        where I: Iterator<Item = Token<'a>>
    {
        if let Ok(expr) = parser::parse_expr(&mut iter) {
            if parser::at_end(&mut iter) {
                return Ok(expr);
            }
        }
        Err(())
    }

    pub fn parse(s: &str) -> Result<Expr, ()> {
        Expr::parse_iter(Tokenizer::new(s, true))
    }

    pub fn parse_toplevel(s: &str) -> Result<Expr, ()> {
        Expr::parse_iter(CurlyAroundTokenizer::new(Tokenizer::new(s, true)))
    }
}

impl<T> From<T> for Expr where T: Into<Atom>
{
    fn from(t: T) -> Expr {
        Expr::Atom(t.into())
    }
}

impl From<()> for Expr {
    fn from(_e: ()) -> Expr {
        Expr::Tuple(vec![])
    }
}

impl<A> From<(A,)> for Expr where A: Into<Expr>
{
    fn from(e: (A,)) -> Expr {
        Expr::Tuple(vec![e.0.into()])
    }
}

impl<A, B> From<(A, B)> for Expr
    where A: Into<Expr>,
          B: Into<Expr>
{
    fn from(e: (A, B)) -> Expr {
        Expr::Tuple(vec![e.0.into(), e.1.into()])
    }
}

impl<A, B, C> From<(A, B, C)> for Expr
    where A: Into<Expr>,
          B: Into<Expr>,
          C: Into<Expr>
{
    fn from(e: (A, B, C)) -> Expr {
        Expr::Tuple(vec![e.0.into(), e.1.into(), e.2.into()])
    }
}

impl<A, B, C, D> From<(A, B, C, D)> for Expr
    where A: Into<Expr>,
          B: Into<Expr>,
          C: Into<Expr>,
          D: Into<Expr>
{
    fn from(e: (A, B, C, D)) -> Expr {
        Expr::Tuple(vec![e.0.into(), e.1.into(), e.2.into(), e.3.into()])
    }
}

impl<A> From<Vec<A>> for Expr where A: Into<Expr>
{
    fn from(arr: Vec<A>) -> Expr {
        Expr::Array(arr.into_iter().map(|e| e.into()).collect())
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Expr::Atom(ref a) => write!(f, "{}", a),
            Expr::Tuple(ref t) => {
                try!(write!(f, "("));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, ")")
            }
            Expr::Array(ref t) => {
                try!(write!(f, "["));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, "]")
            }
            Expr::Map(ref t) => {
                try!(write!(f, "{}", "{"));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{} {}", space, expr.0, expr.1));
                }
                write!(f, "{}", "}")
            }

        }
    }
}

#[test]
fn test_display() {
    assert_eq!("12345", &format!("{}", Expr::Atom(Atom::UInt(12345))));
    assert_eq!("1.0", &format!("{}", Expr::Atom(Atom::Float(1.0))));

    assert_eq!("(12345)",
               &format!("{}", Expr::Tuple(vec![Expr::Atom(Atom::UInt(12345))])));
    assert_eq!("(12345 abc)",
               &format!("{}",
                        Expr::Tuple(vec![Expr::Atom(Atom::UInt(12345)),
                                         Expr::Atom(Atom::Str("abc".to_string()))])));
    assert_eq!("(12345 (abc))",
               &format!("{}",
                        Expr::Tuple(vec![Expr::Atom(Atom::UInt(12345)),
                                         Expr::Tuple(vec![
                                         Expr::Atom(Atom::Str("abc".to_string()))
                                         ])])));

}

#[test]
fn test_from() {
    assert_eq!(Expr::Atom(Atom::UInt(123)), Expr::from(123u64));
    assert_eq!(Expr::Atom(Atom::SInt(123)), Expr::from(123i64));
    assert_eq!(Expr::Atom(Atom::Str("test".to_string())),
               Expr::from("test"));
    assert_eq!(Expr::Atom(Atom::Float(123.45)), Expr::from(123.45));
    assert_eq!(Expr::Tuple(vec![Expr::Atom(Atom::Float(123.45))]),
               Expr::from((123.45,)));
    assert_eq!(Expr::Array(vec![Expr::Atom(Atom::Float(123.45))]),
               Expr::from(vec![123.45]));

}

#[test]
fn test_parse() {
    assert_eq!(Ok(Expr::from(("abc", 123u64, ("-", 123.43, 11.0)))),
               Expr::parse("(abc 123 (- 123.43 11.0))"));
}

#[test]
fn test_parse_toplevel() {
    assert_eq!(Expr::parse("{a 1 b 2}"), Expr::parse_toplevel("a 1 b 2"));
}
<commit_msg>Implement Expr::into_map<commit_after>use std::fmt;
use super::atom::Atom;
use super::parser;
use super::token::{Token, Tokenizer, CurlyAroundTokenizer};
use std::collections::BTreeMap;

#[derive(Debug, PartialEq)]
pub enum Expr {
    Atom(Atom),

    // ( ... )
    Tuple(Vec<Expr>),

    // [ ... ]
    Array(Vec<Expr>),

    // { key val ... }
    Map(Vec<(Expr, Expr)>),
}

impl Expr {
    /// Converts a Expr::Map into a BTreeMap<String, Expr> if possible.
    pub fn into_map(self) -> Result<BTreeMap<String, Expr>, &'static str> {
        match self {
            Expr::Map(pairs) => {
                let mut map = BTreeMap::new();
                for (key, val) in pairs {
                    match key {
                        Expr::Atom(Atom::Str(s)) => {
                            if map.insert(s, val).is_some() {
                                return Err("duplicate key");
                            }
                        }
                        _ => return Err("key has to be a string"),
                    }
                }
                return Ok(map);
            }
            _ => Err("expr is not a Expr::Map"),
        }
    }

    pub fn parse_iter<'a, I>(mut iter: I) -> Result<Expr, ()>
        where I: Iterator<Item = Token<'a>>
    {
        if let Ok(expr) = parser::parse_expr(&mut iter) {
            if parser::at_end(&mut iter) {
                return Ok(expr);
            }
        }
        Err(())
    }

    pub fn parse(s: &str) -> Result<Expr, ()> {
        Expr::parse_iter(Tokenizer::new(s, true))
    }

    pub fn parse_toplevel(s: &str) -> Result<Expr, ()> {
        Expr::parse_iter(CurlyAroundTokenizer::new(Tokenizer::new(s, true)))
    }
}

impl<T> From<T> for Expr where T: Into<Atom>
{
    fn from(t: T) -> Expr {
        Expr::Atom(t.into())
    }
}

impl From<()> for Expr {
    fn from(_e: ()) -> Expr {
        Expr::Tuple(vec![])
    }
}

impl<A> From<(A,)> for Expr where A: Into<Expr>
{
    fn from(e: (A,)) -> Expr {
        Expr::Tuple(vec![e.0.into()])
    }
}

impl<A, B> From<(A, B)> for Expr
    where A: Into<Expr>,
          B: Into<Expr>
{
    fn from(e: (A, B)) -> Expr {
        Expr::Tuple(vec![e.0.into(), e.1.into()])
    }
}

impl<A, B, C> From<(A, B, C)> for Expr
    where A: Into<Expr>,
          B: Into<Expr>,
          C: Into<Expr>
{
    fn from(e: (A, B, C)) -> Expr {
        Expr::Tuple(vec![e.0.into(), e.1.into(), e.2.into()])
    }
}

impl<A, B, C, D> From<(A, B, C, D)> for Expr
    where A: Into<Expr>,
          B: Into<Expr>,
          C: Into<Expr>,
          D: Into<Expr>
{
    fn from(e: (A, B, C, D)) -> Expr {
        Expr::Tuple(vec![e.0.into(), e.1.into(), e.2.into(), e.3.into()])
    }
}

impl<A> From<Vec<A>> for Expr where A: Into<Expr>
{
    fn from(arr: Vec<A>) -> Expr {
        Expr::Array(arr.into_iter().map(|e| e.into()).collect())
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Expr::Atom(ref a) => write!(f, "{}", a),
            Expr::Tuple(ref t) => {
                try!(write!(f, "("));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, ")")
            }
            Expr::Array(ref t) => {
                try!(write!(f, "["));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, "]")
            }
            Expr::Map(ref t) => {
                try!(write!(f, "{}", "{"));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{} {}", space, expr.0, expr.1));
                }
                write!(f, "{}", "}")
            }

        }
    }
}

#[test]
fn test_display() {
    assert_eq!("12345", &format!("{}", Expr::Atom(Atom::UInt(12345))));
    assert_eq!("1.0", &format!("{}", Expr::Atom(Atom::Float(1.0))));

    assert_eq!("(12345)",
               &format!("{}", Expr::Tuple(vec![Expr::Atom(Atom::UInt(12345))])));
    assert_eq!("(12345 abc)",
               &format!("{}",
                        Expr::Tuple(vec![Expr::Atom(Atom::UInt(12345)),
                                         Expr::Atom(Atom::Str("abc".to_string()))])));
    assert_eq!("(12345 (abc))",
               &format!("{}",
                        Expr::Tuple(vec![Expr::Atom(Atom::UInt(12345)),
                                         Expr::Tuple(vec![
                                         Expr::Atom(Atom::Str("abc".to_string()))
                                         ])])));

}

#[test]
fn test_from() {
    assert_eq!(Expr::Atom(Atom::UInt(123)), Expr::from(123u64));
    assert_eq!(Expr::Atom(Atom::SInt(123)), Expr::from(123i64));
    assert_eq!(Expr::Atom(Atom::Str("test".to_string())),
               Expr::from("test"));
    assert_eq!(Expr::Atom(Atom::Float(123.45)), Expr::from(123.45));
    assert_eq!(Expr::Tuple(vec![Expr::Atom(Atom::Float(123.45))]),
               Expr::from((123.45,)));
    assert_eq!(Expr::Array(vec![Expr::Atom(Atom::Float(123.45))]),
               Expr::from(vec![123.45]));

}

#[test]
fn test_parse() {
    assert_eq!(Ok(Expr::from(("abc", 123u64, ("-", 123.43, 11.0)))),
               Expr::parse("(abc 123 (- 123.43 11.0))"));
}

#[test]
fn test_parse_toplevel() {
    assert_eq!(Expr::parse("{a 1 b 2}"), Expr::parse_toplevel("a 1 b 2"));
}

#[test]
fn test_map() {
    let map = Expr::parse("{a 1 b 2}").unwrap().into_map().unwrap();
    assert_eq!(true, map.contains_key("a"));
    assert_eq!(true, map.contains_key("b"));
    assert_eq!(false, map.contains_key("c"));

    assert_eq!(Err("duplicate key"),
               Expr::parse("{a 1 b 2 a 1}").unwrap().into_map());
    assert_eq!(Err("key has to be a string"),
               Expr::parse("{1 1 b 2 a 1}").unwrap().into_map());

}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::vec::Vec;
use capability::ClientHook;
use common::*;
use message;

pub use self::FirstSegment::{NumWords, ZeroedWords};

pub type SegmentId = u32;

#[derive(Copy)]
pub struct SegmentReader {
    pub arena : ArenaPtr,
    pub ptr : *const Word,
    pub size : WordCount32
}

unsafe impl Send for SegmentReader {}

impl SegmentReader {

    #[inline]
    pub unsafe fn get_start_ptr(&self) -> *const Word {
        self.ptr.offset(0)
    }

    #[inline]
    pub fn contains_interval(&self, from : *const Word, to : *const Word) -> bool {
        let this_begin : usize = self.ptr as usize;
        let this_end : usize = unsafe { self.ptr.offset(self.size as isize) as usize };
        return from as usize >= this_begin && to as usize <= this_end && from as usize <= to as usize;
        // TODO readLimiter
    }
}

#[derive(Copy)]
pub struct SegmentBuilder {
    pub reader : SegmentReader,
    pub id : SegmentId,
    pos : *mut Word,
}

unsafe impl Send for SegmentBuilder {}

impl SegmentBuilder {

    pub fn new(arena : *mut BuilderArena,
               id : SegmentId,
               ptr : *mut Word,
               size : WordCount32) -> SegmentBuilder {
        SegmentBuilder {
            reader : SegmentReader {
                arena : ArenaPtr::Builder(arena),
                ptr : unsafe {::std::mem::transmute(ptr)},
                size : size
            },
            id : id,
            pos : ptr,
        }
    }

    pub fn get_word_offset_to(&mut self, ptr : *mut Word) -> WordCount32 {
        let this_addr : usize = self.reader.ptr as usize;
        let ptr_addr : usize = ptr as usize;
        assert!(ptr_addr >= this_addr);
        let result = (ptr_addr - this_addr) / BYTES_PER_WORD;
        return result as u32;
    }

    #[inline]
    pub fn current_size(&self) -> WordCount32 {
        ptr_sub(self.pos, self.reader.ptr) as u32
    }

    #[inline]
    pub fn allocate(&mut self, amount : WordCount32) -> Option<*mut Word> {
        if amount > self.reader.size - self.current_size() {
            return None;
        } else {
            let result = self.pos;
            self.pos = unsafe { self.pos.offset(amount as isize) };
            return Some(result);
        }
    }

    #[inline]
    pub fn get_ptr_unchecked(&self, offset : WordCount32) -> *mut Word {
        unsafe {
            ::std::mem::transmute(self.reader.ptr.offset(offset as isize))
        }
    }

    #[inline]
    pub fn get_segment_id(&self) -> SegmentId { self.id }

    #[inline]
    pub fn get_arena(&self) -> *mut BuilderArena {
        match self.reader.arena {
            ArenaPtr::Builder(b) => b,
            _ => unreachable!()
        }
    }
}

pub struct ReaderArena {
    //    message : *message::MessageReader<'a>,
    pub segment0 : SegmentReader,

    pub more_segments : Vec<SegmentReader>,
    //XXX should this be a map as in capnproto-c++?

    pub cap_table : Vec<Option<Box<ClientHook+Send>>>,

    pub fail_fast : bool,
}

impl ReaderArena {
    pub fn new(segments : &[&[Word]], options : message::ReaderOptions) -> Box<ReaderArena> {
        assert!(segments.len() > 0);
        let mut arena = Box::new(ReaderArena {
            segment0 : SegmentReader {
                arena : ArenaPtr::Null,
                ptr : unsafe { segments[0].get_unchecked(0) },
                size : segments[0].len() as u32
            },
            more_segments : Vec::new(),
            cap_table : Vec::new(),
            fail_fast : options.fail_fast,
        });

        let arena_ptr = ArenaPtr::Reader (&*arena);

        arena.segment0.arena = arena_ptr;

        if segments.len() > 1 {
            let mut more_segment_readers = Vec::new();
            for segment in segments[1 ..].iter() {
                let segment_reader = SegmentReader {
                    arena : arena_ptr,
                    ptr : unsafe { segment.get_unchecked(0) },
                    size : segment.len() as u32
                };
                more_segment_readers.push(segment_reader);
            }
            arena.more_segments = more_segment_readers;
        }

        arena
    }

    pub fn try_get_segment(&self, id : SegmentId) -> *const SegmentReader {
        if id == 0 {
            return &self.segment0 as *const SegmentReader;
        } else {
            unsafe { self.more_segments.get_unchecked(id as usize - 1) as *const SegmentReader }
        }
    }

    #[inline]
    pub fn init_cap_table(&mut self, cap_table : Vec<Option<Box<ClientHook+Send>>>) {
        self.cap_table = cap_table;
    }

}

pub struct BuilderArena {
    pub segment0 : SegmentBuilder,
    pub more_segments : Vec<Box<SegmentBuilder>>,
    pub allocation_strategy : message::AllocationStrategy,
    pub owned_memory : Vec<*mut Word>,
    pub next_size : u32,
    pub cap_table : Vec<Option<Box<ClientHook+Send>>>,
    pub fail_fast : bool,
}

impl Drop for BuilderArena {
    fn drop(&mut self) {
        unsafe {
            ::std::rt::heap::deallocate(::std::mem::transmute(self.segment0.reader.ptr),
                                        BYTES_PER_WORD * self.segment0.reader.size as usize,
                                        BYTES_PER_WORD);
        }
        for ref segment_builder in self.more_segments.iter() {
            unsafe {
                ::std::rt::heap::deallocate(::std::mem::transmute(segment_builder.reader.ptr),
                                            BYTES_PER_WORD * segment_builder.reader.size as usize,
                                            BYTES_PER_WORD);
            }
        }
    }
}

pub enum FirstSegment<'a> {
    NumWords(u32),
    ZeroedWords(&'a mut [Word])
}

impl BuilderArena {

    pub fn new(allocation_strategy : message::AllocationStrategy,
               first_segment : FirstSegment,
               fail_fast : bool) -> Box<BuilderArena> {
        let (first_segment, num_words, owned_memory) : (*mut Word, u32, Vec<*mut Word>) = unsafe {
            match first_segment {
                NumWords(n) => {
                    let ptr : *mut Word = ::std::mem::transmute(
                        ::std::rt::heap::allocate(BYTES_PER_WORD * n as usize,
                                                  ::std::mem::min_align_of::<Word>()));
                    ::std::ptr::zero_memory(ptr, n as usize);
                    if ptr.is_null() {panic!("could not allocate segment")}
                    (ptr, n, vec!(ptr))
                }
                ZeroedWords(w) => (w.as_mut_ptr(), w.len() as u32, Vec::new())
            }};

        let mut result = Box::new(BuilderArena {
            segment0 : SegmentBuilder {
                reader : SegmentReader {
                    ptr : first_segment as *const Word,
                    size : num_words,
                    arena : ArenaPtr::Null },
                id : 0,
                pos : first_segment,
            },
            more_segments : Vec::new(),
            allocation_strategy : allocation_strategy,
            owned_memory : owned_memory,
            next_size : num_words,
            cap_table : Vec::new(),
            fail_fast : fail_fast,
        });

        let arena_ptr = { let ref mut ptr = *result; ptr as *mut BuilderArena};
        result.segment0.reader.arena = ArenaPtr::Builder(arena_ptr);

        result
    }

    pub fn allocate_owned_memory(&mut self, minimum_size : WordCount32) -> (*mut Word, WordCount32) {
        let size = ::std::cmp::max(minimum_size, self.next_size);
        let new_words : *mut Word = unsafe {
            ::std::mem::transmute(::std::rt::heap::allocate(BYTES_PER_WORD * size as usize,
                                                            ::std::mem::min_align_of::<Word>())) };
        unsafe { ::std::ptr::zero_memory(new_words, size as usize) };

        if new_words.is_null() { panic!("could not allocate a new segment.") }

        self.owned_memory.push(new_words);

        match self.allocation_strategy {
            message::AllocationStrategy::GrowHeuristically => { self.next_size += size; }
            _ => { }
        }
        (new_words, size)
    }

    #[inline]
    pub fn allocate(&mut self, amount : WordCount32) -> (*mut SegmentBuilder, *mut Word) {
        unsafe {
            match self.segment0.allocate(amount) {
                Some(result) => { return ((&mut self.segment0) as *mut SegmentBuilder, result) }
                None => {}
            }

            //# Need to fall back to additional segments.

            let id = {
                let len = self.more_segments.len();
                if len == 0 { 1 }
                else {
                    let result_ptr = &mut *self.more_segments.as_mut_slice()[len-1] as *mut SegmentBuilder;
                    match self.more_segments.as_mut_slice()[len - 1].allocate(amount) {
                        Some(result) => { return (result_ptr, result) }
                        None => { len + 1 }
                    }
                }};

            let (words, size) = self.allocate_owned_memory(amount);
            let mut new_builder = Box::new(SegmentBuilder::new(self, id as u32, words, size));
            let builder_ptr = &mut *new_builder as *mut SegmentBuilder;

            self.more_segments.push(new_builder);

            (builder_ptr, (*builder_ptr).allocate(amount).unwrap() )
        }
    }

    pub fn get_segment(&mut self, id : SegmentId) -> *mut SegmentBuilder {
        if id == 0 {
            &mut self.segment0 as *mut SegmentBuilder
        } else {
            &mut *self.more_segments.as_mut_slice()[(id - 1) as usize] as *mut SegmentBuilder
        }
    }

    pub fn get_segments_for_output<T, U : FnMut(&[&[Word]]) -> T>(&self, mut cont : U) -> T {
        unsafe {
            if self.more_segments.len() == 0 {
                let v = ::std::slice::from_raw_parts::<Word>(
                    self.segment0.reader.ptr,
                    self.segment0.current_size() as usize);
                cont(&[v])
            } else {
                let mut result = Vec::new();
                result.push(::std::slice::from_raw_parts(self.segment0.reader.ptr,
                                                         self.segment0.current_size() as usize));
                for seg in self.more_segments.iter() {
                    result.push(::std::slice::from_raw_parts(seg.reader.ptr,
                                                             seg.current_size() as usize))
                }
                cont(result.as_slice())
            }
        }
    }

    pub fn get_cap_table<'a>(&'a self) -> &'a [Option<Box<ClientHook+Send>>] {
        self.cap_table.as_slice()
    }

    pub fn inject_cap(&mut self, cap : Box<ClientHook+Send>) -> u32 {
        self.cap_table.push(Some(cap));
        self.cap_table.len() as u32 - 1
    }
}

#[derive(Copy)]
pub enum ArenaPtr {
    Reader(*const ReaderArena),
    Builder(*mut BuilderArena),
    Null
}

impl ArenaPtr {
    pub fn try_get_segment(&self, id : SegmentId) -> *const SegmentReader {
        unsafe {
            match self {
                &ArenaPtr::Reader(reader) => {
                    (&*reader).try_get_segment(id)
                }
                &ArenaPtr::Builder(builder) => {
                    if id == 0 {
                        &(*builder).segment0.reader as *const SegmentReader
                    } else {
                        &(*builder).more_segments.as_slice()[id as usize - 1].reader as *const SegmentReader
                    }
                }
                &ArenaPtr::Null => {
                    panic!()
                }
            }
        }
    }

    pub fn extract_cap(&self, index : usize) -> Option<Box<ClientHook+Send>> {
        unsafe {
            match self {
                &ArenaPtr::Reader(reader) => {
                    if index < (*reader).cap_table.len() {
                        match (*reader).cap_table.as_slice()[index] {
                            Some( ref hook ) => { Some(hook.copy()) }
                            None => {
                                None
                            }
                        }
                    } else {
                        None
                    }
                }
                &ArenaPtr::Builder(builder) => {
                    if index < (*builder).cap_table.len() {
                        match (*builder).cap_table.as_slice()[index] {
                            Some( ref hook ) => { Some(hook.copy()) }
                            None => {
                                None
                            }
                        }
                    } else {
                        None
                    }
                }
                &ArenaPtr::Null => {
                    panic!();
                }
            }
        }
    }

    pub fn fail_fast(&self) -> bool {
        unsafe {
            match self {
                &ArenaPtr::Reader(reader) => {
                    (*reader).fail_fast
                }
                &ArenaPtr::Builder(builder) => {
                    (*builder).fail_fast
                }
                &ArenaPtr::Null => {
                    panic!()
                }
            }
        }
    }

}
<commit_msg>check for null before zeroing<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::vec::Vec;
use capability::ClientHook;
use common::*;
use message;

pub use self::FirstSegment::{NumWords, ZeroedWords};

pub type SegmentId = u32;

#[derive(Copy)]
pub struct SegmentReader {
    pub arena : ArenaPtr,
    pub ptr : *const Word,
    pub size : WordCount32
}

unsafe impl Send for SegmentReader {}

impl SegmentReader {

    #[inline]
    pub unsafe fn get_start_ptr(&self) -> *const Word {
        self.ptr.offset(0)
    }

    #[inline]
    pub fn contains_interval(&self, from : *const Word, to : *const Word) -> bool {
        let this_begin : usize = self.ptr as usize;
        let this_end : usize = unsafe { self.ptr.offset(self.size as isize) as usize };
        return from as usize >= this_begin && to as usize <= this_end && from as usize <= to as usize;
        // TODO readLimiter
    }
}

#[derive(Copy)]
pub struct SegmentBuilder {
    pub reader : SegmentReader,
    pub id : SegmentId,
    pos : *mut Word,
}

unsafe impl Send for SegmentBuilder {}

impl SegmentBuilder {

    pub fn new(arena : *mut BuilderArena,
               id : SegmentId,
               ptr : *mut Word,
               size : WordCount32) -> SegmentBuilder {
        SegmentBuilder {
            reader : SegmentReader {
                arena : ArenaPtr::Builder(arena),
                ptr : unsafe {::std::mem::transmute(ptr)},
                size : size
            },
            id : id,
            pos : ptr,
        }
    }

    pub fn get_word_offset_to(&mut self, ptr : *mut Word) -> WordCount32 {
        let this_addr : usize = self.reader.ptr as usize;
        let ptr_addr : usize = ptr as usize;
        assert!(ptr_addr >= this_addr);
        let result = (ptr_addr - this_addr) / BYTES_PER_WORD;
        return result as u32;
    }

    #[inline]
    pub fn current_size(&self) -> WordCount32 {
        ptr_sub(self.pos, self.reader.ptr) as u32
    }

    #[inline]
    pub fn allocate(&mut self, amount : WordCount32) -> Option<*mut Word> {
        if amount > self.reader.size - self.current_size() {
            return None;
        } else {
            let result = self.pos;
            self.pos = unsafe { self.pos.offset(amount as isize) };
            return Some(result);
        }
    }

    #[inline]
    pub fn get_ptr_unchecked(&self, offset : WordCount32) -> *mut Word {
        unsafe {
            ::std::mem::transmute(self.reader.ptr.offset(offset as isize))
        }
    }

    #[inline]
    pub fn get_segment_id(&self) -> SegmentId { self.id }

    #[inline]
    pub fn get_arena(&self) -> *mut BuilderArena {
        match self.reader.arena {
            ArenaPtr::Builder(b) => b,
            _ => unreachable!()
        }
    }
}

pub struct ReaderArena {
    //    message : *message::MessageReader<'a>,
    pub segment0 : SegmentReader,

    pub more_segments : Vec<SegmentReader>,
    //XXX should this be a map as in capnproto-c++?

    pub cap_table : Vec<Option<Box<ClientHook+Send>>>,

    pub fail_fast : bool,
}

impl ReaderArena {
    pub fn new(segments : &[&[Word]], options : message::ReaderOptions) -> Box<ReaderArena> {
        assert!(segments.len() > 0);
        let mut arena = Box::new(ReaderArena {
            segment0 : SegmentReader {
                arena : ArenaPtr::Null,
                ptr : unsafe { segments[0].get_unchecked(0) },
                size : segments[0].len() as u32
            },
            more_segments : Vec::new(),
            cap_table : Vec::new(),
            fail_fast : options.fail_fast,
        });

        let arena_ptr = ArenaPtr::Reader (&*arena);

        arena.segment0.arena = arena_ptr;

        if segments.len() > 1 {
            let mut more_segment_readers = Vec::new();
            for segment in segments[1 ..].iter() {
                let segment_reader = SegmentReader {
                    arena : arena_ptr,
                    ptr : unsafe { segment.get_unchecked(0) },
                    size : segment.len() as u32
                };
                more_segment_readers.push(segment_reader);
            }
            arena.more_segments = more_segment_readers;
        }

        arena
    }

    pub fn try_get_segment(&self, id : SegmentId) -> *const SegmentReader {
        if id == 0 {
            return &self.segment0 as *const SegmentReader;
        } else {
            unsafe { self.more_segments.get_unchecked(id as usize - 1) as *const SegmentReader }
        }
    }

    #[inline]
    pub fn init_cap_table(&mut self, cap_table : Vec<Option<Box<ClientHook+Send>>>) {
        self.cap_table = cap_table;
    }

}

pub struct BuilderArena {
    pub segment0 : SegmentBuilder,
    pub more_segments : Vec<Box<SegmentBuilder>>,
    pub allocation_strategy : message::AllocationStrategy,
    pub owned_memory : Vec<*mut Word>,
    pub next_size : u32,
    pub cap_table : Vec<Option<Box<ClientHook+Send>>>,
    pub fail_fast : bool,
}

impl Drop for BuilderArena {
    fn drop(&mut self) {
        unsafe {
            ::std::rt::heap::deallocate(::std::mem::transmute(self.segment0.reader.ptr),
                                        BYTES_PER_WORD * self.segment0.reader.size as usize,
                                        BYTES_PER_WORD);
        }
        for ref segment_builder in self.more_segments.iter() {
            unsafe {
                ::std::rt::heap::deallocate(::std::mem::transmute(segment_builder.reader.ptr),
                                            BYTES_PER_WORD * segment_builder.reader.size as usize,
                                            BYTES_PER_WORD);
            }
        }
    }
}

pub enum FirstSegment<'a> {
    NumWords(u32),
    ZeroedWords(&'a mut [Word])
}

impl BuilderArena {

    pub fn new(allocation_strategy : message::AllocationStrategy,
               first_segment : FirstSegment,
               fail_fast : bool) -> Box<BuilderArena> {
        let (first_segment, num_words, owned_memory) : (*mut Word, u32, Vec<*mut Word>) = unsafe {
            match first_segment {
                NumWords(n) => {
                    let ptr : *mut Word = ::std::mem::transmute(
                        ::std::rt::heap::allocate(BYTES_PER_WORD * n as usize,
                                                  ::std::mem::min_align_of::<Word>()));
                    if ptr.is_null() {panic!("could not allocate segment")}
                    ::std::ptr::zero_memory(ptr, n as usize);
                    (ptr, n, vec!(ptr))
                }
                ZeroedWords(w) => (w.as_mut_ptr(), w.len() as u32, Vec::new())
            }};

        let mut result = Box::new(BuilderArena {
            segment0 : SegmentBuilder {
                reader : SegmentReader {
                    ptr : first_segment as *const Word,
                    size : num_words,
                    arena : ArenaPtr::Null },
                id : 0,
                pos : first_segment,
            },
            more_segments : Vec::new(),
            allocation_strategy : allocation_strategy,
            owned_memory : owned_memory,
            next_size : num_words,
            cap_table : Vec::new(),
            fail_fast : fail_fast,
        });

        let arena_ptr = { let ref mut ptr = *result; ptr as *mut BuilderArena};
        result.segment0.reader.arena = ArenaPtr::Builder(arena_ptr);

        result
    }

    pub fn allocate_owned_memory(&mut self, minimum_size : WordCount32) -> (*mut Word, WordCount32) {
        let size = ::std::cmp::max(minimum_size, self.next_size);
        let new_words : *mut Word = unsafe {
            ::std::mem::transmute(::std::rt::heap::allocate(BYTES_PER_WORD * size as usize,
                                                            ::std::mem::min_align_of::<Word>())) };
        if new_words.is_null() { panic!("could not allocate a new segment.") }
        unsafe { ::std::ptr::zero_memory(new_words, size as usize) };

        self.owned_memory.push(new_words);

        match self.allocation_strategy {
            message::AllocationStrategy::GrowHeuristically => { self.next_size += size; }
            _ => { }
        }
        (new_words, size)
    }

    #[inline]
    pub fn allocate(&mut self, amount : WordCount32) -> (*mut SegmentBuilder, *mut Word) {
        unsafe {
            match self.segment0.allocate(amount) {
                Some(result) => { return ((&mut self.segment0) as *mut SegmentBuilder, result) }
                None => {}
            }

            //# Need to fall back to additional segments.

            let id = {
                let len = self.more_segments.len();
                if len == 0 { 1 }
                else {
                    let result_ptr = &mut *self.more_segments.as_mut_slice()[len-1] as *mut SegmentBuilder;
                    match self.more_segments.as_mut_slice()[len - 1].allocate(amount) {
                        Some(result) => { return (result_ptr, result) }
                        None => { len + 1 }
                    }
                }};

            let (words, size) = self.allocate_owned_memory(amount);
            let mut new_builder = Box::new(SegmentBuilder::new(self, id as u32, words, size));
            let builder_ptr = &mut *new_builder as *mut SegmentBuilder;

            self.more_segments.push(new_builder);

            (builder_ptr, (*builder_ptr).allocate(amount).unwrap() )
        }
    }

    pub fn get_segment(&mut self, id : SegmentId) -> *mut SegmentBuilder {
        if id == 0 {
            &mut self.segment0 as *mut SegmentBuilder
        } else {
            &mut *self.more_segments.as_mut_slice()[(id - 1) as usize] as *mut SegmentBuilder
        }
    }

    pub fn get_segments_for_output<T, U : FnMut(&[&[Word]]) -> T>(&self, mut cont : U) -> T {
        unsafe {
            if self.more_segments.len() == 0 {
                let v = ::std::slice::from_raw_parts::<Word>(
                    self.segment0.reader.ptr,
                    self.segment0.current_size() as usize);
                cont(&[v])
            } else {
                let mut result = Vec::new();
                result.push(::std::slice::from_raw_parts(self.segment0.reader.ptr,
                                                         self.segment0.current_size() as usize));
                for seg in self.more_segments.iter() {
                    result.push(::std::slice::from_raw_parts(seg.reader.ptr,
                                                             seg.current_size() as usize))
                }
                cont(result.as_slice())
            }
        }
    }

    pub fn get_cap_table<'a>(&'a self) -> &'a [Option<Box<ClientHook+Send>>] {
        self.cap_table.as_slice()
    }

    pub fn inject_cap(&mut self, cap : Box<ClientHook+Send>) -> u32 {
        self.cap_table.push(Some(cap));
        self.cap_table.len() as u32 - 1
    }
}

#[derive(Copy)]
pub enum ArenaPtr {
    Reader(*const ReaderArena),
    Builder(*mut BuilderArena),
    Null
}

impl ArenaPtr {
    pub fn try_get_segment(&self, id : SegmentId) -> *const SegmentReader {
        unsafe {
            match self {
                &ArenaPtr::Reader(reader) => {
                    (&*reader).try_get_segment(id)
                }
                &ArenaPtr::Builder(builder) => {
                    if id == 0 {
                        &(*builder).segment0.reader as *const SegmentReader
                    } else {
                        &(*builder).more_segments.as_slice()[id as usize - 1].reader as *const SegmentReader
                    }
                }
                &ArenaPtr::Null => {
                    panic!()
                }
            }
        }
    }

    pub fn extract_cap(&self, index : usize) -> Option<Box<ClientHook+Send>> {
        unsafe {
            match self {
                &ArenaPtr::Reader(reader) => {
                    if index < (*reader).cap_table.len() {
                        match (*reader).cap_table.as_slice()[index] {
                            Some( ref hook ) => { Some(hook.copy()) }
                            None => {
                                None
                            }
                        }
                    } else {
                        None
                    }
                }
                &ArenaPtr::Builder(builder) => {
                    if index < (*builder).cap_table.len() {
                        match (*builder).cap_table.as_slice()[index] {
                            Some( ref hook ) => { Some(hook.copy()) }
                            None => {
                                None
                            }
                        }
                    } else {
                        None
                    }
                }
                &ArenaPtr::Null => {
                    panic!();
                }
            }
        }
    }

    pub fn fail_fast(&self) -> bool {
        unsafe {
            match self {
                &ArenaPtr::Reader(reader) => {
                    (*reader).fail_fast
                }
                &ArenaPtr::Builder(builder) => {
                    (*builder).fail_fast
                }
                &ArenaPtr::Null => {
                    panic!()
                }
            }
        }
    }

}
<|endoftext|>


<commit_before>use redox::{Box, String};
use redox::collections::VecDeque;
use redox::ops::DerefMut;

use orbital::{Color, Point, Size, Event, KeyEvent, MouseEvent, QuitEvent};

use super::display::Display;

/// A window
pub struct Window {
    /// The position of the window
    pub point: Point,
    /// The size of the window
    pub size: Size,
    /// The title of the window
    pub title: String,
    /// The content of the window
    pub content: Box<Display>,
    /// The color of the window title
    pub title_color: Color,
    /// The color of the border
    pub border_color: Color,
    /// Is the window focused?
    pub focused: bool,
    /// Is the window minimized?
    pub minimized: bool,
    dragging: bool,
    last_mouse_event: MouseEvent,
    events: VecDeque<Event>,
    ptr: *mut Window,
}

impl Window {
    /// Create a new window
    pub fn new(point: Point, size: Size, title: String) -> Box<Self> {
        let mut ret = box Window {
            point: point,
            size: size,
            title: title,
            content: Display::new(size.width, size.height),
            title_color: Color::rgb(255, 255, 255),
            border_color: Color::rgba(64, 64, 64, 128),
            focused: false,
            minimized: false,
            dragging: false,
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                right_button: false,
                middle_button: false,
            },
            events: VecDeque::new(),
            ptr: 0 as *mut Window,
        };

        unsafe {
            ret.ptr = ret.deref_mut();

            if ret.ptr as usize > 0 {
                //(*::session_ptr).add_window(ret.ptr);
            }
        }

        ret
    }

    /// Poll the window (new)
    pub fn poll(&mut self) -> Option<Event> {
        //let reenable = scheduler::start_no_ints();
        //scheduler::end_no_ints(reenable);
        return self.events.pop_front();
    }

    /// Redraw the window
    pub fn redraw(&mut self) {
        unsafe {
            //let reenable = scheduler::start_no_ints();
            self.content.flip();
            //(*::session_ptr).redraw = true;
            //scheduler::end_no_ints(reenable);
        }
    }

    /// Draw the window using a `Display`
    pub fn draw(&mut self, display: &Display) {
        if self.focused {
            self.border_color = Color::rgba(128, 128, 128, 192);
        } else {
            self.border_color = Color::rgba(64, 64, 64, 128);
        }

        if self.minimized {
            self.title_color = Color::rgb(0, 0, 0);
        } else {
            self.title_color = Color::rgb(255, 255, 255);

            display.rect(Point::new(self.point.x - 2, self.point.y - 18),
                         Size::new(self.size.width + 4, 18),
                         self.border_color);

            let mut cursor = Point::new(self.point.x, self.point.y - 17);
            for c in self.title.chars() {
                if cursor.x + 8 <= self.point.x + self.size.width as isize {
                    display.char(cursor, c, self.title_color);
                }
                cursor.x += 8;
            }

            display.rect(Point::new(self.point.x - 2, self.point.y),
                         Size::new(2, self.size.height),
                         self.border_color);
            display.rect(Point::new(self.point.x - 2,
                                    self.point.y + self.size.height as isize),
                         Size::new(self.size.width + 4, 2),
                         self.border_color);
            display.rect(Point::new(self.point.x + self.size.width as isize,
                                    self.point.y),
                         Size::new(2, self.size.height),
                         self.border_color);

            unsafe {
                //let reenable = scheduler::start_no_ints();
                display.image(self.point,
                              self.content.onscreen as *const u32,
                              Size::new(self.content.width, self.content.height));
                //scheduler::end_no_ints(reenable);
            }
        }
    }

    /// Called on key press
    pub fn on_key(&mut self, key_event: KeyEvent) {
        unsafe {
            //let reenable = scheduler::start_no_ints();
            self.events.push_back(key_event.to_event());
            //scheduler::end_no_ints(reenable);
        }
    }

    fn on_window_decoration(&self, x: isize, y: isize) -> bool {
        !self.minimized && x >= -2 &&
            x < self.size.width as isize + 4 &&
            y >= -18 &&
            y < 0
    }

    fn on_window_body(&self, x: isize, y: isize) -> bool {
        !self.minimized && x >= 0 &&
            x < self.size.width as isize &&
            y >= 0 &&
            y < self.size.height as isize
    }

    /// Called on mouse movement
    pub fn on_mouse(&mut self, orig_mouse_event: MouseEvent, allow_catch: bool) -> bool {
        let mut mouse_event = orig_mouse_event;

        mouse_event.x -= self.point.x;
        mouse_event.y -= self.point.y;

        let mut caught = false;

        if allow_catch {
            if mouse_event.left_button {
                if self.on_window_body(mouse_event.x, mouse_event.y) {
                    caught = true;
                }else if self.on_window_decoration(mouse_event.x, mouse_event.y) {
                    caught = true;
                    if !self.last_mouse_event.left_button {
                        self.dragging = true;
                    }
                }
            } else {
                self.dragging = false;
            }

            if mouse_event.right_button {
                if self.on_window_body(mouse_event.x, mouse_event.y) {
                    caught = true;
                }else if self.on_window_decoration(mouse_event.x, mouse_event.y) {
                    caught = true;
                    if !self.last_mouse_event.right_button {
                        self.minimized = !self.minimized;
                    }
                }
            }

            if mouse_event.middle_button {
                if self.on_window_body(mouse_event.x, mouse_event.y) {
                    caught = true;
                }else if self.on_window_decoration(mouse_event.x, mouse_event.y) {
                    caught = true;
                    unsafe {
                        //let reenable = scheduler::start_no_ints();
                        self.events.push_back(QuitEvent.to_event());
                        //scheduler::end_no_ints(reenable);
                    }
                }
            }

            if self.dragging {
                self.point.x += orig_mouse_event.x - self.last_mouse_event.x;
                self.point.y += orig_mouse_event.y - self.last_mouse_event.y;
                caught = true;
            }
        } else {
            self.dragging = false;
        }

        self.last_mouse_event = orig_mouse_event;

        if (caught && !self.dragging) || self.on_window_body(mouse_event.x, mouse_event.y) {
            unsafe {
                //let reenable = scheduler::start_no_ints();
                self.events.push_back(mouse_event.to_event());
                //scheduler::end_no_ints(reenable);
            }
        }

        caught
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        unsafe {
            if self.ptr as usize > 0 {
                //(*::session_ptr).remove_window(self.ptr);
            }
        }
    }
}
<commit_msg>Add session (wip)<commit_after>use redox::{Box, String};
use redox::collections::VecDeque;
use redox::ops::DerefMut;

use orbital::{Color, Point, Size, Event, KeyEvent, MouseEvent, QuitEvent};

use super::display::Display;

/// A window
pub struct Window {
    /// The position of the window
    pub point: Point,
    /// The size of the window
    pub size: Size,
    /// The title of the window
    pub title: String,
    /// The content of the window
    pub content: Box<Display>,
    /// The color of the window title
    pub title_color: Color,
    /// The color of the border
    pub border_color: Color,
    /// Is the window focused?
    pub focused: bool,
    /// Is the window minimized?
    pub minimized: bool,
    dragging: bool,
    last_mouse_event: MouseEvent,
    events: VecDeque<Event>,
    ptr: *mut Window,
}

impl Window {
    /// Create a new window
    pub fn new(point: Point, size: Size, title: String) -> Box<Self> {
        let mut ret = box Window {
            point: point,
            size: size,
            title: title,
            content: Display::new(size.width, size.height),
            title_color: Color::rgb(255, 255, 255),
            border_color: Color::rgba(64, 64, 64, 128),
            focused: false,
            minimized: false,
            dragging: false,
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                right_button: false,
                middle_button: false,
            },
            events: VecDeque::new(),
            ptr: 0 as *mut Window,
        };

        unsafe {
            ret.ptr = ret.deref_mut();

            if ret.ptr as usize > 0 {
                //(*::session_ptr).add_window(ret.ptr);
            }
        }

        ret
    }

    /// Poll the window (new)
    pub fn poll(&mut self) -> Option<Event> {
        //let reenable = scheduler::start_no_ints();
        //scheduler::end_no_ints(reenable);
        return self.events.pop_front();
    }

    /// Redraw the window
    pub fn redraw(&mut self) {
        unsafe {
            //let reenable = scheduler::start_no_ints();
            self.content.flip();
            (*::session_ptr).redraw = true;
            //scheduler::end_no_ints(reenable);
        }
    }

    /// Draw the window using a `Display`
    pub fn draw(&mut self, display: &Display) {
        if self.focused {
            self.border_color = Color::rgba(128, 128, 128, 192);
        } else {
            self.border_color = Color::rgba(64, 64, 64, 128);
        }

        if self.minimized {
            self.title_color = Color::rgb(0, 0, 0);
        } else {
            self.title_color = Color::rgb(255, 255, 255);

            display.rect(Point::new(self.point.x - 2, self.point.y - 18),
                         Size::new(self.size.width + 4, 18),
                         self.border_color);

            let mut cursor = Point::new(self.point.x, self.point.y - 17);
            for c in self.title.chars() {
                if cursor.x + 8 <= self.point.x + self.size.width as isize {
                    display.char(cursor, c, self.title_color);
                }
                cursor.x += 8;
            }

            display.rect(Point::new(self.point.x - 2, self.point.y),
                         Size::new(2, self.size.height),
                         self.border_color);
            display.rect(Point::new(self.point.x - 2,
                                    self.point.y + self.size.height as isize),
                         Size::new(self.size.width + 4, 2),
                         self.border_color);
            display.rect(Point::new(self.point.x + self.size.width as isize,
                                    self.point.y),
                         Size::new(2, self.size.height),
                         self.border_color);

            unsafe {
                //let reenable = scheduler::start_no_ints();
                display.image(self.point,
                              self.content.onscreen as *const u32,
                              Size::new(self.content.width, self.content.height));
                //scheduler::end_no_ints(reenable);
            }
        }
    }

    /// Called on key press
    pub fn on_key(&mut self, key_event: KeyEvent) {
        unsafe {
            //let reenable = scheduler::start_no_ints();
            self.events.push_back(key_event.to_event());
            //scheduler::end_no_ints(reenable);
        }
    }

    fn on_window_decoration(&self, x: isize, y: isize) -> bool {
        !self.minimized && x >= -2 &&
            x < self.size.width as isize + 4 &&
            y >= -18 &&
            y < 0
    }

    fn on_window_body(&self, x: isize, y: isize) -> bool {
        !self.minimized && x >= 0 &&
            x < self.size.width as isize &&
            y >= 0 &&
            y < self.size.height as isize
    }

    /// Called on mouse movement
    pub fn on_mouse(&mut self, orig_mouse_event: MouseEvent, allow_catch: bool) -> bool {
        let mut mouse_event = orig_mouse_event;

        mouse_event.x -= self.point.x;
        mouse_event.y -= self.point.y;

        let mut caught = false;

        if allow_catch {
            if mouse_event.left_button {
                if self.on_window_body(mouse_event.x, mouse_event.y) {
                    caught = true;
                }else if self.on_window_decoration(mouse_event.x, mouse_event.y) {
                    caught = true;
                    if !self.last_mouse_event.left_button {
                        self.dragging = true;
                    }
                }
            } else {
                self.dragging = false;
            }

            if mouse_event.right_button {
                if self.on_window_body(mouse_event.x, mouse_event.y) {
                    caught = true;
                }else if self.on_window_decoration(mouse_event.x, mouse_event.y) {
                    caught = true;
                    if !self.last_mouse_event.right_button {
                        self.minimized = !self.minimized;
                    }
                }
            }

            if mouse_event.middle_button {
                if self.on_window_body(mouse_event.x, mouse_event.y) {
                    caught = true;
                }else if self.on_window_decoration(mouse_event.x, mouse_event.y) {
                    caught = true;
                    unsafe {
                        //let reenable = scheduler::start_no_ints();
                        self.events.push_back(QuitEvent.to_event());
                        //scheduler::end_no_ints(reenable);
                    }
                }
            }

            if self.dragging {
                self.point.x += orig_mouse_event.x - self.last_mouse_event.x;
                self.point.y += orig_mouse_event.y - self.last_mouse_event.y;
                caught = true;
            }
        } else {
            self.dragging = false;
        }

        self.last_mouse_event = orig_mouse_event;

        if (caught && !self.dragging) || self.on_window_body(mouse_event.x, mouse_event.y) {
            unsafe {
                //let reenable = scheduler::start_no_ints();
                self.events.push_back(mouse_event.to_event());
                //scheduler::end_no_ints(reenable);
            }
        }

        caught
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        unsafe {
            if self.ptr as usize > 0 {
                //(*::session_ptr).remove_window(self.ptr);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! The `join` macro.

/// Polls multiple futures simultaneously, returning a tuple
/// of all results once complete.
///
/// While `join!(a, b)` is similar to `(await!(a), await!(b))`,
/// `join!` polls both futures concurrently and therefore is more efficent.
///
/// This macro is only usable inside of async functions, closures, and blocks.
///
/// # Examples
///
/// ```
/// #![feature(pin, async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{join, future};
///
/// let a = future::ready(1);
/// let b = future::ready(2);
///
/// assert_eq!(join!(a, b), (1, 2));
/// # });
/// ```
#[macro_export]
macro_rules! join {
    ($($fut:ident),*) => { {
        $(
            let mut $fut = $crate::future::maybe_done($fut);
            $crate::pin_mut!($fut);
        )*
        loop {
            let mut all_done = true;
            $(
                if $crate::poll!($fut.reborrow()).is_pending() {
                    all_done = false;
                }
            )*
            if all_done {
                break;
            } else {
                $crate::pending!();
            }
        }

        ($(
            $fut.reborrow().take_output().unwrap(),
        )*)
    } }
}

/// Attempts to poll multiple futures simultaneously, returning a `Result`
/// of a tuple of all of the results once complete.
///
/// `try_join!` is similar to `join!`, but completes immediately if any of
/// the futures return an error.
///
/// This macro is only usable inside of async functions, closures, and blocks.
///
/// # Examples
///
/// ```
/// #![feature(pin, async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{try_join, future};
///
/// let a = future::ready(Ok::<i32, i32>(1));
/// let b = future::ready(Err::<u64, i32>(2));
///
/// assert_eq!(try_join!(a, b), Err(2));
///
/// let a = future::ready(Ok::<i32, i32>(1));
/// let b = future::ready(Ok::<u64, i32>(2));
///
/// assert_eq!(try_join!(a, b), Ok((1, 2)));
/// # });
/// ```
#[macro_export]
macro_rules! try_join {
    ($($fut:ident),*) => { {
        $(
            let mut $fut = $crate::future::maybe_done($fut);
            $crate::pin_mut!($fut);
        )*
        let res: $crate::core_reexport::result::Result<(), _> = loop {
            let mut all_done = true;
            $(
                if $crate::poll!($fut.reborrow()).is_pending() {
                    all_done = false;
                } else if $fut.reborrow().output_mut().unwrap().is_err() {
                    // `.err().unwrap()` rather than `.unwrap_err()` so that we don't introduce
                    // a `T: Debug` bound.
                    break $crate::core_reexport::result::Result::Err(
                        $fut.reborrow().take_output().unwrap().err().unwrap()
                    );
                }
            )*
            if all_done {
                break $crate::core_reexport::result::Result::Ok(());
            } else {
                $crate::pending!();
            }
        };

        res.map(|()| ($(
            // `.ok().unwrap()` rather than `.unwrap()` so that we don't introduce
            // an `E: Debug` bound.
            $fut.reborrow().take_output().unwrap().ok().unwrap(),
        )*))
    } }
}
<commit_msg>Reorganize the doc examples of the try_join! combinator<commit_after>//! The `join` macro.

/// Polls multiple futures simultaneously, returning a tuple
/// of all results once complete.
///
/// While `join!(a, b)` is similar to `(await!(a), await!(b))`,
/// `join!` polls both futures concurrently and therefore is more efficent.
///
/// This macro is only usable inside of async functions, closures, and blocks.
///
/// # Examples
///
/// ```
/// #![feature(pin, async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{join, future};
///
/// let a = future::ready(1);
/// let b = future::ready(2);
///
/// assert_eq!(join!(a, b), (1, 2));
/// # });
/// ```
#[macro_export]
macro_rules! join {
    ($($fut:ident),*) => { {
        $(
            let mut $fut = $crate::future::maybe_done($fut);
            $crate::pin_mut!($fut);
        )*
        loop {
            let mut all_done = true;
            $(
                if $crate::poll!($fut.reborrow()).is_pending() {
                    all_done = false;
                }
            )*
            if all_done {
                break;
            } else {
                $crate::pending!();
            }
        }

        ($(
            $fut.reborrow().take_output().unwrap(),
        )*)
    } }
}

/// Polls multiple futures simultaneously, returning a [`Result`] containing
/// either a tuple of the successful outputs or an error.
///
/// `try_join!` is similar to [`join!`], but completes immediately if any of
/// the futures return an error.
///
/// This macro is only usable inside of async functions, closures, and blocks.
///
/// # Examples
///
/// When used on multiple futures that return `Ok`, `try_join!` will return
/// `Ok` of a tuple of the values:
///
/// ```
/// #![feature(pin, async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{try_join, future};
///
/// let a = future::ready(Ok::<i32, i32>(1));
/// let b = future::ready(Ok::<u64, i32>(2));
///
/// assert_eq!(try_join!(a, b), Ok((1, 2)));
/// # });
/// ```
///
/// If one of the futures resolves to an error, `try_join!` will return
/// that error:
///
/// ```
/// #![feature(pin, async_await, await_macro, futures_api)]
/// # futures::executor::block_on(async {
/// use futures::{try_join, future};
///
/// let a = future::ready(Ok::<i32, i32>(1));
/// let b = future::ready(Err::<u64, i32>(2));
///
/// assert_eq!(try_join!(a, b), Err(2));
/// # });
/// ```
#[macro_export]
macro_rules! try_join {
    ($($fut:ident),*) => { {
        $(
            let mut $fut = $crate::future::maybe_done($fut);
            $crate::pin_mut!($fut);
        )*
        let res: $crate::core_reexport::result::Result<(), _> = loop {
            let mut all_done = true;
            $(
                if $crate::poll!($fut.reborrow()).is_pending() {
                    all_done = false;
                } else if $fut.reborrow().output_mut().unwrap().is_err() {
                    // `.err().unwrap()` rather than `.unwrap_err()` so that we don't introduce
                    // a `T: Debug` bound.
                    break $crate::core_reexport::result::Result::Err(
                        $fut.reborrow().take_output().unwrap().err().unwrap()
                    );
                }
            )*
            if all_done {
                break $crate::core_reexport::result::Result::Ok(());
            } else {
                $crate::pending!();
            }
        };

        res.map(|()| ($(
            // `.ok().unwrap()` rather than `.unwrap()` so that we don't introduce
            // an `E: Debug` bound.
            $fut.reborrow().take_output().unwrap().ok().unwrap(),
        )*))
    } }
}
<|endoftext|>


<commit_before>// Generic AArch64 target for bare-metal code
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
//
// For example, `-C target-cpu=cortex-a53`.

use super::{LldFlavor, LinkerFlavor, Target, TargetOptions, PanicStrategy};

pub fn target() -> Result<Target, String> {
    let opts = TargetOptions {
        linker: Some("rust-lld".to_owned()),
        executables: true,
        relocation_model: "static".to_string(),
        disable_redzone: true,
        linker_is_gnu: true,
        max_atomic_width: Some(128),
        panic_strategy: PanicStrategy::Abort,
        abi_blacklist: super::arm_base::abi_blacklist(),
        .. Default::default()
    };
    Ok(Target {
        llvm_target: "aarch64-unknown-none".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "64".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: String::new(),
        target_vendor: String::new(),
        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
        arch: "aarch64".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        options: opts,
    })
}
<commit_msg>Auto merge of #58060 - andre-richter:master, r=nagisa<commit_after>// Generic AArch64 target for bare-metal code
//
// Can be used in conjunction with the `target-feature` and
// `target-cpu` compiler flags to opt-in more hardware-specific
// features.
//
// For example, `-C target-cpu=cortex-a53`.

use super::{LldFlavor, LinkerFlavor, Target, TargetOptions, PanicStrategy};

pub fn target() -> Result<Target, String> {
    let opts = TargetOptions {
        linker: Some("rust-lld".to_owned()),
        features: "+strict-align".to_string(),
        executables: true,
        relocation_model: "static".to_string(),
        disable_redzone: true,
        linker_is_gnu: true,
        max_atomic_width: Some(128),
        panic_strategy: PanicStrategy::Abort,
        abi_blacklist: super::arm_base::abi_blacklist(),
        .. Default::default()
    };
    Ok(Target {
        llvm_target: "aarch64-unknown-none".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "64".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: String::new(),
        target_vendor: String::new(),
        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
        arch: "aarch64".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
        options: opts,
    })
}
<|endoftext|>


<commit_before>//! Defines read and write operations for a kekbit channel.

///Channel Access errors
#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum ChannelError {
    ///The channel has an invalid signature. The channel signature must be `0x2A54_4942_4B45_4B2A`
    InvalidSignature {
        ///The expected signature always `0x2A54_4942_4B45_4B2A`
        expected: u64,
        ///The signature red from the kekbit storage
        actual: u64,
    },
    ///The channel's storage is of an incompatible file format
    IncompatibleVersion {
        ///Expected storage version
        expected: u64,
        ///Actual  storage version
        actual: u64,
    },
    ///The channel's capacity is invalid. Either too small or is not aligned to 8 bytes.
    InvalidCapacity {
        ///Actual capacity
        capacity: u32,
        ///Reason why the capacity is invalid
        msg: &'static str,
    },
    ///The maximum message length specified is invalid
    InvalidMaxMessageLength {
        ///The specified maximum message length
        msg_len: u32,
        ///Reason why maximum message length is invalid
        msg: &'static str,
    },
    ///The channel storage does not exist
    StorageNotFound {
        ///The file expected to back the channel storage
        file_name: String,
    },

    ///The channel storage is not ready to access
    StorageNotReady {
        ///The file that backs the channel storage
        file_name: String,
    },
    ///The channel storage is not ready to access
    StorageAlreadyExists {
        ///The file that backs the channel storage
        file_name: String,
    },
    ///The channel storage can't be accessed
    CouldNotAccessStorage {
        ///The file that backs the channel storage
        file_name: String,
    },
    ///Mapping the channel's file to memory had failed
    MemoryMappingFailed {
        reason: String,
    },

    AccessError {
        reason: String,
    },
}

///Write operation errors
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum WriteError {
    /// There is not enough space available in the channel for such an operation.
    NoSpaceAvailable {
        ///The space amount required by the record. It will be larger than the record size.
        required: u32,
        ///The space amount available in the channel.
        left: u32,
    },
    /// The record was longer than the maximum allowed.
    MaxRecordLenExceed {
        ///The size of the record to be written.
        rec_len: u32,
        ///The maximum allowed size for a record.
        max_allowed: u32,
    },
}

static HEARTBEAT_MSG: &[u8] = &[];

///The `Writer` trait allows writing chunk of bytes as records into a kekbit channel.
/// Implementers of this trait are called 'kekbit writers'. Usually a writer is bound to
/// a given channel, and it is expected that there is only one writer which directly writes into the channel, however
/// multiple writers may cooperate during the writing process.
pub trait Writer {
    /// Writes a given record to a kekbit channel.
    ///
    /// Returns the total amount of bytes wrote into the channel or a `WriteError` if the write operation fails.
    ///
    /// # Arguments
    ///
    /// * `data` - The buffer which contains the record data to be written.
    /// * `len` - The amount of data to be write in the channel, the record length.
    ///
    /// # Errors
    ///
    /// If the operation fails, than an error variant will be returned.
    /// Regardless the error variant a future write with a smaller record size may be successful.
    ///
    fn write(&mut self, data: &[u8], len: u32) -> Result<u32, WriteError>;
    /// Writes into the stream a heartbeat message. This method shall be used by all writers
    /// which want to respect to timeout interval associated to a channel. Hearbeating is the
    /// expected mechanism by which a channel writer will keep the active readers interested in
    /// the data published on the channel.
    /// Heartbeat shall be done regularly, at a time interval which ensures that at least one heartbeat
    /// is sent between any two 'timeout' long intervals.
    ///
    /// Returns the total amount of bytes wrote into the channel or a `WriteError` if the write operation fails.
    ///
    /// # Errors
    ///
    /// If this call fails, than an error variant will be returned. However
    /// in this case the errors are not recoverable, they signal that the channel is at the
    /// end of its lifetime.
    #[inline(always)]
    fn heartbeat(&mut self) -> Result<u32, WriteError> {
        self.write(HEARTBEAT_MSG, 0)
    }

    /// Flushes the stream which possibly backs the kekbit writer.
    /// By default this method does nothing, and should be implemented only for `Writer`s which
    /// it makes sense.
    /// Returns the success of the operation
    fn flush(&mut self) -> Result<(), std::io::Error> {
        Ok(())
    }
}

///Read operation errors
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum ReadError {
    ///Read operation had unexpectedly failed. Usually will happen when a channel was corrupted.
    Failed {
        ///The amount of bytes read *before* the error occurred.
        bytes_read: u32,
    },
    ///Writer timeout had been detected. While the writer may resume pushing data in to the channel, most likely he had abandoned the channel.
    Timeout {
        ///Last time stamp at which the channel was still considered valid.
        timeout: u64,
    },
    ///Channel is closed no more data will be pushed into.
    Closed {
        ///The amount of bytes read *before* the channel close mark was reached.
        bytes_read: u32,
    },
    ///Channel full. There is no more space available in this channel.
    ChannelFull {
        ///The amount of bytes read *before* the end of channel was reached.
        bytes_read: u32,
    },
}

impl ReadError {
    ///Returns the number of valid bytes read before an error occurred.
    pub fn bytes_read(&self) -> u32 {
        match self {
            ReadError::Timeout { .. } => 0,
            ReadError::Closed { bytes_read } => *bytes_read,
            ReadError::ChannelFull { bytes_read } => *bytes_read,
            ReadError::Failed { bytes_read } => *bytes_read,
        }
    }
}

///The `Reader` trait allows reading bytes from a kekbit channel. Implementers of this trait
/// are called 'kekbit readers'. Usually a reader is bound to a given channel, and it is
/// expected that multiple readers will safely access the same channel simultaneous.
pub trait Reader {
    ///Accesses a number of records from the kekbit channel, and for each record, calls
    ///the given callback.
    ///
    /// Returns the amount of bytes read from the channel
    ///
    /// # Arguments
    ///
    /// * `handler` - The callback function to be called when a record is pulled from the channel
    /// * `message_count` - A hint about how many records shall be read from the channel before the method completes.
    ///                     It is expected that this method will take from the channel at most this many records
    ///
    ///
    /// # Errors
    ///
    /// If this function fails, than an error variant will be returned. These errors are not expected to be recoverable. Once any error except `Timeout` occurred, there will never be
    /// data to read pass the current read marker. However reading from beginning of the channel to the current
    /// read marker should still be a valid operation. The `Timeout` exception,
    /// may or may not be recoverable, depends on the channel `Writer` behaviour.
    fn read(&mut self, handler: &mut impl FnMut(&[u8]) -> (), message_count: u16) -> Result<u32, ReadError>;
}
<commit_msg>Remove the non exhaustive annotation.<commit_after>//! Defines read and write operations for a kekbit channel.

///Channel Access errors
#[derive(Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum ChannelError {
    ///The channel has an invalid signature. The channel signature must be `0x2A54_4942_4B45_4B2A`
    InvalidSignature {
        ///The expected signature always `0x2A54_4942_4B45_4B2A`
        expected: u64,
        ///The signature red from the kekbit storage
        actual: u64,
    },
    ///The channel's storage is of an incompatible file format
    IncompatibleVersion {
        ///Expected storage version
        expected: u64,
        ///Actual  storage version
        actual: u64,
    },
    ///The channel's capacity is invalid. Either too small or is not aligned to 8 bytes.
    InvalidCapacity {
        ///Actual capacity
        capacity: u32,
        ///Reason why the capacity is invalid
        msg: &'static str,
    },
    ///The maximum message length specified is invalid
    InvalidMaxMessageLength {
        ///The specified maximum message length
        msg_len: u32,
        ///Reason why maximum message length is invalid
        msg: &'static str,
    },
    ///The channel storage does not exist
    StorageNotFound {
        ///The file expected to back the channel storage
        file_name: String,
    },

    ///The channel storage is not ready to access
    StorageNotReady {
        ///The file that backs the channel storage
        file_name: String,
    },
    ///The channel storage is not ready to access
    StorageAlreadyExists {
        ///The file that backs the channel storage
        file_name: String,
    },
    ///The channel storage can't be accessed
    CouldNotAccessStorage {
        ///The file that backs the channel storage
        file_name: String,
    },
    ///Mapping the channel's file to memory had failed
    MemoryMappingFailed {
        reason: String,
    },

    AccessError {
        reason: String,
    },
}

///Write operation errors
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum WriteError {
    /// There is not enough space available in the channel for such an operation.
    NoSpaceAvailable {
        ///The space amount required by the record. It will be larger than the record size.
        required: u32,
        ///The space amount available in the channel.
        left: u32,
    },
    /// The record was longer than the maximum allowed.
    MaxRecordLenExceed {
        ///The size of the record to be written.
        rec_len: u32,
        ///The maximum allowed size for a record.
        max_allowed: u32,
    },
}

static HEARTBEAT_MSG: &[u8] = &[];

///The `Writer` trait allows writing chunk of bytes as records into a kekbit channel.
/// Implementers of this trait are called 'kekbit writers'. Usually a writer is bound to
/// a given channel, and it is expected that there is only one writer which directly writes into the channel, however
/// multiple writers may cooperate during the writing process.
pub trait Writer {
    /// Writes a given record to a kekbit channel.
    ///
    /// Returns the total amount of bytes wrote into the channel or a `WriteError` if the write operation fails.
    ///
    /// # Arguments
    ///
    /// * `data` - The buffer which contains the record data to be written.
    /// * `len` - The amount of data to be write in the channel, the record length.
    ///
    /// # Errors
    ///
    /// If the operation fails, than an error variant will be returned.
    /// Regardless the error variant a future write with a smaller record size may be successful.
    ///
    fn write(&mut self, data: &[u8], len: u32) -> Result<u32, WriteError>;
    /// Writes into the stream a heartbeat message. This method shall be used by all writers
    /// which want to respect to timeout interval associated to a channel. Hearbeating is the
    /// expected mechanism by which a channel writer will keep the active readers interested in
    /// the data published on the channel.
    /// Heartbeat shall be done regularly, at a time interval which ensures that at least one heartbeat
    /// is sent between any two 'timeout' long intervals.
    ///
    /// Returns the total amount of bytes wrote into the channel or a `WriteError` if the write operation fails.
    ///
    /// # Errors
    ///
    /// If this call fails, than an error variant will be returned. However
    /// in this case the errors are not recoverable, they signal that the channel is at the
    /// end of its lifetime.
    #[inline(always)]
    fn heartbeat(&mut self) -> Result<u32, WriteError> {
        self.write(HEARTBEAT_MSG, 0)
    }

    /// Flushes the stream which possibly backs the kekbit writer.
    /// By default this method does nothing, and should be implemented only for `Writer`s which
    /// it makes sense.
    /// Returns the success of the operation
    fn flush(&mut self) -> Result<(), std::io::Error> {
        Ok(())
    }
}

///Read operation errors
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum ReadError {
    ///Read operation had unexpectedly failed. Usually will happen when a channel was corrupted.
    Failed {
        ///The amount of bytes read *before* the error occurred.
        bytes_read: u32,
    },
    ///Writer timeout had been detected. While the writer may resume pushing data in to the channel, most likely he had abandoned the channel.
    Timeout {
        ///Last time stamp at which the channel was still considered valid.
        timeout: u64,
    },
    ///Channel is closed no more data will be pushed into.
    Closed {
        ///The amount of bytes read *before* the channel close mark was reached.
        bytes_read: u32,
    },
    ///Channel full. There is no more space available in this channel.
    ChannelFull {
        ///The amount of bytes read *before* the end of channel was reached.
        bytes_read: u32,
    },
}

impl ReadError {
    ///Returns the number of valid bytes read before an error occurred.
    pub fn bytes_read(&self) -> u32 {
        match self {
            ReadError::Timeout { .. } => 0,
            ReadError::Closed { bytes_read } => *bytes_read,
            ReadError::ChannelFull { bytes_read } => *bytes_read,
            ReadError::Failed { bytes_read } => *bytes_read,
        }
    }
}

///The `Reader` trait allows reading bytes from a kekbit channel. Implementers of this trait
/// are called 'kekbit readers'. Usually a reader is bound to a given channel, and it is
/// expected that multiple readers will safely access the same channel simultaneous.
pub trait Reader {
    ///Accesses a number of records from the kekbit channel, and for each record, calls
    ///the given callback.
    ///
    /// Returns the amount of bytes read from the channel
    ///
    /// # Arguments
    ///
    /// * `handler` - The callback function to be called when a record is pulled from the channel
    /// * `message_count` - A hint about how many records shall be read from the channel before the method completes.
    ///                     It is expected that this method will take from the channel at most this many records
    ///
    ///
    /// # Errors
    ///
    /// If this function fails, than an error variant will be returned. These errors are not expected to be recoverable. Once any error except `Timeout` occurred, there will never be
    /// data to read pass the current read marker. However reading from beginning of the channel to the current
    /// read marker should still be a valid operation. The `Timeout` exception,
    /// may or may not be recoverable, depends on the channel `Writer` behaviour.
    fn read(&mut self, handler: &mut impl FnMut(&[u8]) -> (), message_count: u16) -> Result<u32, ReadError>;
}
<|endoftext|>


<commit_before>pub mod reader;
use reader::ShmReader;
pub mod writer;
use writer::ShmWriter;

use crate::header::{write_header, HEADER_LEN};
use crate::tick::TickUnit;
use crate::utils::{align, compute_max_msg_len, MIN_CAPACITY};
use log::{error, info};
use memmap::MmapOptions;
use std::cmp::max;
use std::cmp::min;
use std::fs::OpenOptions;
use std::fs::{remove_file, DirBuilder};
use std::ops::Shl;
use std::path::Path;
use std::result::Result;

pub fn shm_reader(
    root_path: &Path,
    producer_id: u64,
    channel_id: u64,
    file_id: u64,
) -> Result<ShmReader, String> {
    let dir_path = root_path
        .join(channel_id.to_string())
        .join(producer_id.to_string());
    let kek_file_name = dir_path.join(format!("{}.kekbit", file_id));
    let kek_file = OpenOptions::new()
        .write(true)
        .read(true)
        .open(&kek_file_name)
        .unwrap();
    info!("Kekbit file {:?} opened for read.", kek_file);
    let mmap = unsafe { MmapOptions::new().map_mut(&kek_file).unwrap() };
    ShmReader::new(mmap)
}

pub fn shm_writer(
    root_path: &Path,
    producer_id: u64,
    channel_id: u64,
    file_id: u64,
    len: u32,
    timeout: u64,
    tick_unit: TickUnit,
) -> Result<ShmWriter, String> {
    let dir_path = root_path
        .join(channel_id.to_string())
        .join(producer_id.to_string());
    let mut builder = DirBuilder::new();
    builder.recursive(true);
    builder.create(&dir_path).unwrap();
    let lock_file_name = dir_path.join(format!("{}.kekbit.lock", file_id));
    OpenOptions::new()
        .write(true)
        .create(true)
        .open(&lock_file_name)
        .unwrap();
    info!("Kekbit lock {:?} created", lock_file_name);
    let kek_file_name = dir_path.join(format!("{}.kekbit", file_id));
    let kek_file = OpenOptions::new()
        .write(true)
        .read(true)
        .create(true)
        .open(&kek_file_name)
        .unwrap();
    let capacity = max(MIN_CAPACITY, align(min(len, 1u32.shl(31))) as usize);
    let total_len = (capacity + HEADER_LEN) as u64;
    kek_file.set_len(total_len).unwrap();
    info!("Kekbit file {:?} created", kek_file);
    let max_msg_len = compute_max_msg_len(capacity as u32);
    let mut mmap = unsafe { MmapOptions::new().map_mut(&kek_file).unwrap() };
    let buf = &mut mmap[..];
    write_header(
        buf,
        producer_id,
        channel_id,
        capacity as u32,
        max_msg_len,
        timeout,
        tick_unit,
    );
    mmap.flush().unwrap();
    info!("Kekbit file {:?} initialized", kek_file_name);
    let res = ShmWriter::new(mmap);
    if res.is_err() {
        error!(
            "Kekbit writer creation error . The file {:?} will be removed!",
            kek_file_name
        );
        remove_file(&kek_file_name).expect("Could not remove kekbit file");
    }
    remove_file(&lock_file_name).expect("Could not remove kekbit lock file");
    info!("Kekbit lock file {:?} removed", lock_file_name);
    res
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::utils::{align, REC_HEADER_LEN};
    use std::sync::Once;

    static INIT_LOG: Once = Once::new();

    #[test]
    fn read_than_write() {
        INIT_LOG.call_once(|| {
            simple_logger::init().unwrap();
        });
        let test_tmp_dir = tempdir::TempDir::new("kektest").unwrap();
        let mut writer = shm_writer(
            &test_tmp_dir.path(),
            100,
            100,
            1,
            10000,
            99999999,
            TickUnit::Nanos,
        )
        .unwrap();
        let txt = "There are 10 kinds of people: those who know binary and those who don't";
        let msgs = txt.split_whitespace();
        let mut msg_count = 0;
        let mut bytes_written = 8; //accout for the initial heartbeat
        for m in msgs {
            let to_wr = m.as_bytes();
            let len = to_wr.len() as u32;
            let size = writer.write(&to_wr, len).unwrap();
            assert_eq!(size, align(len + REC_HEADER_LEN));
            bytes_written += size;
            msg_count += 1;
        }
        let mut reader = shm_reader(&test_tmp_dir.path(), 100, 100, 1).unwrap();
        let mut res_msg = StrMsgsAppender::default();
        let bytes_read = reader
            .read(&mut |msg| res_msg.on_message(msg), msg_count + 10 as u16)
            .unwrap();
        assert_eq!(res_msg.txt, txt);
        assert_eq!(bytes_written, bytes_read);
    }

    #[derive(Default, Debug)]
    struct StrMsgsAppender {
        txt: String,
    }

    impl StrMsgsAppender {
        pub fn on_message(&mut self, buf: &[u8]) {
            let msg_str = std::str::from_utf8(&buf).unwrap();
            if self.txt.len() > 0 {
                self.txt.push_str(" ");
            }
            self.txt.push_str(msg_str);
        }
    }
}
<commit_msg>Fix use statement for test case<commit_after>pub mod reader;
use reader::ShmReader;
pub mod writer;
use crate::header::{write_header, HEADER_LEN};
use crate::tick::TickUnit;
use crate::utils::{align, compute_max_msg_len, MIN_CAPACITY};
use log::{error, info};
use memmap::MmapOptions;
use std::cmp::max;
use std::cmp::min;
use std::fs::OpenOptions;
use std::fs::{remove_file, DirBuilder};
use std::ops::Shl;
use std::path::Path;
use std::result::Result;
use writer::ShmWriter;

pub fn shm_reader(
    root_path: &Path,
    producer_id: u64,
    channel_id: u64,
    file_id: u64,
) -> Result<ShmReader, String> {
    let dir_path = root_path
        .join(channel_id.to_string())
        .join(producer_id.to_string());
    let kek_file_name = dir_path.join(format!("{}.kekbit", file_id));
    let kek_file = OpenOptions::new()
        .write(true)
        .read(true)
        .open(&kek_file_name)
        .unwrap();
    info!("Kekbit file {:?} opened for read.", kek_file);
    let mmap = unsafe { MmapOptions::new().map_mut(&kek_file).unwrap() };
    ShmReader::new(mmap)
}

pub fn shm_writer(
    root_path: &Path,
    producer_id: u64,
    channel_id: u64,
    file_id: u64,
    len: u32,
    timeout: u64,
    tick_unit: TickUnit,
) -> Result<ShmWriter, String> {
    let dir_path = root_path
        .join(channel_id.to_string())
        .join(producer_id.to_string());
    let mut builder = DirBuilder::new();
    builder.recursive(true);
    builder.create(&dir_path).unwrap();
    let lock_file_name = dir_path.join(format!("{}.kekbit.lock", file_id));
    OpenOptions::new()
        .write(true)
        .create(true)
        .open(&lock_file_name)
        .unwrap();
    info!("Kekbit lock {:?} created", lock_file_name);
    let kek_file_name = dir_path.join(format!("{}.kekbit", file_id));
    let kek_file = OpenOptions::new()
        .write(true)
        .read(true)
        .create(true)
        .open(&kek_file_name)
        .unwrap();
    let capacity = max(MIN_CAPACITY, align(min(len, 1u32.shl(31))) as usize);
    let total_len = (capacity + HEADER_LEN) as u64;
    kek_file.set_len(total_len).unwrap();
    info!("Kekbit file {:?} created", kek_file);
    let max_msg_len = compute_max_msg_len(capacity as u32);
    let mut mmap = unsafe { MmapOptions::new().map_mut(&kek_file).unwrap() };
    let buf = &mut mmap[..];
    write_header(
        buf,
        producer_id,
        channel_id,
        capacity as u32,
        max_msg_len,
        timeout,
        tick_unit,
    );
    mmap.flush().unwrap();
    info!("Kekbit file {:?} initialized", kek_file_name);
    let res = ShmWriter::new(mmap);
    if res.is_err() {
        error!(
            "Kekbit writer creation error . The file {:?} will be removed!",
            kek_file_name
        );
        remove_file(&kek_file_name).expect("Could not remove kekbit file");
    }
    remove_file(&lock_file_name).expect("Could not remove kekbit lock file");
    info!("Kekbit lock file {:?} removed", lock_file_name);
    res
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::api::{Reader, Writer};
    use crate::utils::{align, REC_HEADER_LEN};
    use std::sync::Once;

    static INIT_LOG: Once = Once::new();

    #[test]
    fn read_than_write() {
        INIT_LOG.call_once(|| {
            simple_logger::init().unwrap();
        });
        let test_tmp_dir = tempdir::TempDir::new("kektest").unwrap();
        let mut writer = shm_writer(
            &test_tmp_dir.path(),
            100,
            100,
            1,
            10000,
            99999999,
            TickUnit::Nanos,
        )
        .unwrap();
        let txt = "There are 10 kinds of people: those who know binary and those who don't";
        let msgs = txt.split_whitespace();
        let mut msg_count = 0;
        let mut bytes_written = 8; //accout for the initial heartbeat
        for m in msgs {
            let to_wr = m.as_bytes();
            let len = to_wr.len() as u32;
            let size = writer.write(&to_wr, len).unwrap();
            assert_eq!(size, align(len + REC_HEADER_LEN));
            bytes_written += size;
            msg_count += 1;
        }
        let mut reader = shm_reader(&test_tmp_dir.path(), 100, 100, 1).unwrap();
        let mut res_msg = StrMsgsAppender::default();
        let bytes_read = reader
            .read(&mut |msg| res_msg.on_message(msg), msg_count + 10 as u16)
            .unwrap();
        assert_eq!(res_msg.txt, txt);
        assert_eq!(bytes_written, bytes_read);
    }

    #[derive(Default, Debug)]
    struct StrMsgsAppender {
        txt: String,
    }

    impl StrMsgsAppender {
        pub fn on_message(&mut self, buf: &[u8]) {
            let msg_str = std::str::from_utf8(&buf).unwrap();
            if self.txt.len() > 0 {
                self.txt.push_str(" ");
            }
            self.txt.push_str(msg_str);
        }
    }
}
<|endoftext|>