<commit_before>// TODO: Refactor using a matrix for performance

use redox::*;

mod cmd;

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Mode {
    Insert,
    Normal,
}

pub struct Editor {
    url: String,
    file: Option<File>,
    string: String,
    offset: usize,
    scroll_x: isize,
    scroll_y: isize,
}

impl Editor {
    #[inline(never)]
    pub fn new() -> Self {
        Editor {
            url: String::new(),
            file: None,
            string: String::new(),
            offset: 0,
            scroll_x: 0,
            scroll_y: 0,
        }
    }

    fn backspace(&mut self, window: &mut Window) {
        if self.offset > 0 {
            window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
            self.string = self.string[0 .. self.offset - 1].to_string() +
                &self.string[self.offset .. self.string.len()];
            self.offset -= 1;
        }
    }

    fn delete(&mut self, window: &mut Window) {
        if self.offset < self.string.len() {
            window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
            self.string = self.string[0 .. self.offset].to_string() +
                &self.string[self.offset + 1 .. self.string.len()];
        }
    }

    // TODO: Add methods for multiple movements
    fn up(&mut self) {
        if self.cur() == '\n' || self.cur() == '\0' {
            self.left();
            while self.cur() != '\n' &&
                  self.cur() != '\0' &&
                  self.offset >= 1 {
                self.left();
            }
        } else {
            let x = self.get_x(); //- if self.cur() == '\n' { 1 } else { 0 };

            while self.cur() != '\n' &&
                  self.offset >= 1 {
                self.left();
            }
            self.right();
            let mut new_offset = 0;

            for i in 2..self.offset {
                match self.string.as_bytes()[self.offset - i] {
                    0 => break,
                    10 => {
                        new_offset = self.offset - i + 1;
                        break;
                    }
                    _ => (),
                }
            }
            self.offset = new_offset;
            for _ in 1..x {
                if self.cur() != '\n' {
                    self.right();
                } else {
                    break;
                }
            }
        }
    }

    fn left(&mut self) {
        if self.offset > 0 {
            self.offset -= 1;
        }
    }

    fn right(&mut self) {
        if self.offset < self.string.len() {
            self.offset += 1;
        }
    }

    fn down(&mut self) {
        let x = self.get_x(); //- if self.cur() == '\n' { 1 } else { 0 };
        let original_c = self.cur();

        while self.offset < self.string.len() &&
              self.cur() != '\n' &&
              self.cur() != '\0' {
            self.right();
        }
        self.right();

        if original_c == '\n' {
            while self.cur() != '\n' &&
                  self.cur() != '\0' &&
                  self.offset < self.string.len() {
                self.right();
            }
        } else {
            for _ in 1..x {
                if self.cur() != '\n' {
                    self.right();
                } else {
                    break;
                }
            }
        }
    }

    fn cur(&self) -> char {
        self.string.chars().nth(self.offset).unwrap_or('\0')
    }

    fn insert(&mut self, c: char, window: &mut Window) {
        let ind = if c == '\n' {
            let mut mov = 0;

            for _ in 0..self.get_x() {
                self.left();
                mov += 1;
            }

            let mut ind = String::new();
            while (self.cur() == ' ' ||
                  self.cur() == '\t') &&
                  self.offset < self.string.len() {
                ind.push(self.cur());
                self.right();
                mov -= 1;
            }

            for _ in 0..mov {
                self.right();
            }

            ind
        } else {
            String::new()
        };

        window.set_title(&format!("{}{}{}","self (", &self.url, ") Changed"));
        self.string = self.string[0 .. self.offset].to_string() +
            &c.to_string() +
            &self.string[self.offset .. self.string.len()];

        self.right();

        if c == '\n' {
            for c in ind.chars() {
                self.insert(c, window);
            }

        }
    }

    fn reload(&mut self) {
        self.offset = 0;
        self.scroll_x = 0;
        self.scroll_y = 0;

        match self.file {
            Some(ref mut file) => {
                file.seek(SeekFrom::Start(0));
                let mut string = String::new();
                file.read_to_string(&mut string);
                self.string = string;
            }
            None => self.string = String::new(),
        }
    }

    fn save(&mut self, window: &Window) {
        match self.file {
            Some(ref mut file) => {
                file.seek(SeekFrom::Start(0));
                file.write(&self.string.as_bytes());
                file.sync();
            }
            None => {
                let mut save_window = {
                    const width: usize = 400;
                    const height: usize = 200;
                    Window::new((window.x() + (window.width()/2 - width/2) as isize),
                                (window.y() + (window.height()/2 - height/2) as isize),
                                width,
                                height,
                                "Save As").unwrap()
                };
                if let Some(event) = save_window.poll() {
                    //TODO: Create a Save/Cancel button for file saving
                    // and prompt the user for asking to save
                }
            }
        }
    }

    fn get_x(&self) -> usize {
        let mut x = 0;
        for (n, c) in self.string.chars().enumerate() {
            if c == '\n' {
                x = 0;
            } else {
                x += 1;
            }
            if n >= self.offset {
                break;
            }
        }
        x
    }

    fn draw_content(&mut self, window: &mut Window) {
        let mut redraw = false;

        {
            window.set([255, 255, 255, 255]);

            let scroll_x = self.scroll_x;
            let scroll_y = self.scroll_y;

            let mut offset = 0;

            let mut col = -scroll_x;
            let cols = window.width() as isize / 8;

            let mut row = -scroll_y;
            let rows = window.height() as isize / 16;

            for c in self.string.chars() {
                if offset == self.offset {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.rect(8 * col, 16 * row, 8, 16, [128, 128, 128, 128]);
                    } else {
                        if col < 0 { //Too far to the left
                            self.scroll_x += col;
                        } else if col >= cols { //Too far to the right
                            self.scroll_x += cols - col + 1;
                        }
                        if row < 0 { //Too far up
                            self.scroll_y += row;
                        } else if row >= rows { //Too far down
                            self.scroll_y += rows - row + 1;
                        }

                        redraw = true;
                    }
                }

                if c == '\n' {
                    col = -scroll_x;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.char(8 * col, 16 * row, c, [0, 0, 0, 255]);
                    }
                    col += 1;
                }

                offset += 1;
            }

            if offset == self.offset {
                if col >= 0 && col < cols && row >= 0 && row < rows {
                    window.char(8 * col, 16 * row, '_', [128, 128, 128, 255]);
                } else {
                    if col < 0 { //Too far to the left
                        self.scroll_x += col;
                    } else if col >= cols { //Too far to the right
                        self.scroll_x += cols - col + 1;
                    }
                    if row < 0 { //Too far up
                        self.scroll_y += row;
                    } else if row >= rows { //Too far down
                        self.scroll_y += rows - row + 1;
                    }

                    redraw = true;
                }
            }

            window.sync();
        }

        if redraw {
            self.draw_content(window);
        }
    }

    fn main(&mut self, url: &str) {
        let mut window = Window::new((rand() % 400 + 50) as isize,
                                     (rand() % 300 + 50) as isize,
                                     576,
                                     400,
                                     &("Editor (".to_string() + url + ")")).unwrap();

        self.url = url.to_string();
        self.file = File::open(&self.url);

        self.reload();
        self.draw_content(&mut window);

        let mut mode = Mode::Normal;

        let mut last_change = String::new();
        let mut multiplier: Option<u32> = None;
        let mut swap = 0;
        let mut period = String::new();
        let mut is_recording = false;
        let mut clipboard = String::new();

        while let Option::Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        cmd::exec(self, &mut mode, &mut multiplier, &mut last_change, key_event, &mut window, &mut swap, &mut period, &mut is_recording, &mut clipboard);
                        self.draw_content(&mut window);
                    }
                }
                _ => (),
            }
        }
    }
}

pub fn main() {
    match args().get(1) {
        Some(arg) => Editor::new().main(&arg),
        None => Editor::new().main("none://"),
    }
}
<commit_msg>More block cursors<commit_after>// TODO: Refactor using a matrix for performance

use redox::*;

mod cmd;

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Mode {
    Insert,
    Normal,
}

pub struct Editor {
    url: String,
    file: Option<File>,
    string: String,
    offset: usize,
    scroll_x: isize,
    scroll_y: isize,
}

impl Editor {
    #[inline(never)]
    pub fn new() -> Self {
        Editor {
            url: String::new(),
            file: None,
            string: String::new(),
            offset: 0,
            scroll_x: 0,
            scroll_y: 0,
        }
    }

    fn backspace(&mut self, window: &mut Window) {
        if self.offset > 0 {
            window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
            self.string = self.string[0 .. self.offset - 1].to_string() +
                &self.string[self.offset .. self.string.len()];
            self.offset -= 1;
        }
    }

    fn delete(&mut self, window: &mut Window) {
        if self.offset < self.string.len() {
            window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
            self.string = self.string[0 .. self.offset].to_string() +
                &self.string[self.offset + 1 .. self.string.len()];
        }
    }

    // TODO: Add methods for multiple movements
    fn up(&mut self) {
        if self.cur() == '\n' || self.cur() == '\0' {
            self.left();
            while self.cur() != '\n' &&
                  self.cur() != '\0' &&
                  self.offset >= 1 {
                self.left();
            }
        } else {
            let x = self.get_x(); //- if self.cur() == '\n' { 1 } else { 0 };

            while self.cur() != '\n' &&
                  self.offset >= 1 {
                self.left();
            }
            self.right();
            let mut new_offset = 0;

            for i in 2..self.offset {
                match self.string.as_bytes()[self.offset - i] {
                    0 => break,
                    10 => {
                        new_offset = self.offset - i + 1;
                        break;
                    }
                    _ => (),
                }
            }
            self.offset = new_offset;
            for _ in 1..x {
                if self.cur() != '\n' {
                    self.right();
                } else {
                    break;
                }
            }
        }
    }

    fn left(&mut self) {
        if self.offset > 0 {
            self.offset -= 1;
        }
    }

    fn right(&mut self) {
        if self.offset < self.string.len() {
            self.offset += 1;
        }
    }

    fn down(&mut self) {
        let x = self.get_x(); //- if self.cur() == '\n' { 1 } else { 0 };
        let original_c = self.cur();

        while self.offset < self.string.len() &&
              self.cur() != '\n' &&
              self.cur() != '\0' {
            self.right();
        }
        self.right();

        if original_c == '\n' {
            while self.cur() != '\n' &&
                  self.cur() != '\0' &&
                  self.offset < self.string.len() {
                self.right();
            }
        } else {
            for _ in 1..x {
                if self.cur() != '\n' {
                    self.right();
                } else {
                    break;
                }
            }
        }
    }

    fn cur(&self) -> char {
        self.string.chars().nth(self.offset).unwrap_or('\0')
    }

    fn insert(&mut self, c: char, window: &mut Window) {
        let ind = if c == '\n' {
            let mut mov = 0;

            for _ in 0..self.get_x() {
                self.left();
                mov += 1;
            }

            let mut ind = String::new();
            while (self.cur() == ' ' ||
                  self.cur() == '\t') &&
                  self.offset < self.string.len() {
                ind.push(self.cur());
                self.right();
                mov -= 1;
            }

            for _ in 0..mov {
                self.right();
            }

            ind
        } else {
            String::new()
        };

        window.set_title(&format!("{}{}{}","self (", &self.url, ") Changed"));
        self.string = self.string[0 .. self.offset].to_string() +
            &c.to_string() +
            &self.string[self.offset .. self.string.len()];

        self.right();

        if c == '\n' {
            for c in ind.chars() {
                self.insert(c, window);
            }

        }
    }

    fn reload(&mut self) {
        self.offset = 0;
        self.scroll_x = 0;
        self.scroll_y = 0;

        match self.file {
            Some(ref mut file) => {
                file.seek(SeekFrom::Start(0));
                let mut string = String::new();
                file.read_to_string(&mut string);
                self.string = string;
            }
            None => self.string = String::new(),
        }
    }

    fn save(&mut self, window: &Window) {
        match self.file {
            Some(ref mut file) => {
                file.seek(SeekFrom::Start(0));
                file.write(&self.string.as_bytes());
                file.sync();
            }
            None => {
                let mut save_window = {
                    const width: usize = 400;
                    const height: usize = 200;
                    Window::new((window.x() + (window.width()/2 - width/2) as isize),
                                (window.y() + (window.height()/2 - height/2) as isize),
                                width,
                                height,
                                "Save As").unwrap()
                };
                if let Some(event) = save_window.poll() {
                    //TODO: Create a Save/Cancel button for file saving
                    // and prompt the user for asking to save
                }
            }
        }
    }

    fn get_x(&self) -> usize {
        let mut x = 0;
        for (n, c) in self.string.chars().enumerate() {
            if c == '\n' {
                x = 0;
            } else {
                x += 1;
            }
            if n >= self.offset {
                break;
            }
        }
        x
    }

    fn draw_content(&mut self, window: &mut Window) {
        let mut redraw = false;

        {
            window.set([255, 255, 255, 255]);

            let scroll_x = self.scroll_x;
            let scroll_y = self.scroll_y;

            let mut offset = 0;

            let mut col = -scroll_x;
            let cols = window.width() as isize / 8;

            let mut row = -scroll_y;
            let rows = window.height() as isize / 16;

            for c in self.string.chars() {
                if offset == self.offset {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.rect(8 * col, 16 * row, 8, 16, [128, 128, 128, 128]);
                    } else {
                        if col < 0 { //Too far to the left
                            self.scroll_x += col;
                        } else if col >= cols { //Too far to the right
                            self.scroll_x += cols - col + 1;
                        }
                        if row < 0 { //Too far up
                            self.scroll_y += row;
                        } else if row >= rows { //Too far down
                            self.scroll_y += rows - row + 1;
                        }

                        redraw = true;
                    }
                }

                if c == '\n' {
                    col = -scroll_x;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.char(8 * col, 16 * row, c, [0, 0, 0, 255]);
                    }
                    col += 1;
                }

                offset += 1;
            }

            if offset == self.offset {
                if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.rect(8 * col, 16 * row, 8, 16, [128, 128, 128, 128]);
                } else {
                    if col < 0 { //Too far to the left
                        self.scroll_x += col;
                    } else if col >= cols { //Too far to the right
                        self.scroll_x += cols - col + 1;
                    }
                    if row < 0 { //Too far up
                        self.scroll_y += row;
                    } else if row >= rows { //Too far down
                        self.scroll_y += rows - row + 1;
                    }

                    redraw = true;
                }
            }

            window.sync();
        }

        if redraw {
            self.draw_content(window);
        }
    }

    fn main(&mut self, url: &str) {
        let mut window = Window::new((rand() % 400 + 50) as isize,
                                     (rand() % 300 + 50) as isize,
                                     576,
                                     400,
                                     &("Editor (".to_string() + url + ")")).unwrap();

        self.url = url.to_string();
        self.file = File::open(&self.url);

        self.reload();
        self.draw_content(&mut window);

        let mut mode = Mode::Normal;

        let mut last_change = String::new();
        let mut multiplier: Option<u32> = None;
        let mut swap = 0;
        let mut period = String::new();
        let mut is_recording = false;
        let mut clipboard = String::new();

        while let Option::Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        cmd::exec(self, &mut mode, &mut multiplier, &mut last_change, key_event, &mut window, &mut swap, &mut period, &mut is_recording, &mut clipboard);
                        self.draw_content(&mut window);
                    }
                }
                _ => (),
            }
        }
    }
}

pub fn main() {
    match args().get(1) {
        Some(arg) => Editor::new().main(&arg),
        None => Editor::new().main("none://"),
    }
}
<|endoftext|>


<commit_before>
#[derive(Debug)]
#[repr(packed)] // repr(C) would add unwanted padding before first_section
pub struct ElfSectionsTag {
    typ: u32,
    size: u32,
    pub number_of_sections: u32,
    entry_size: u32,
    shndx: u32, // string table
    first_section: ElfSection,
}

impl ElfSectionsTag {
    pub fn sections(&'static self) -> ElfSectionIter {
        ElfSectionIter {
            current_section: &self.first_section,
            remaining_sections: self.number_of_sections - 1,
            entry_size: self.entry_size,
        }
    }

    pub fn string_table(&self) -> &'static StringTable {
        unsafe {
            let string_table_ptr =
                (&self.first_section as *const ElfSection).offset(self.shndx as isize);
            &*((*string_table_ptr).addr as *const StringTable)
        }
    }
}

pub struct StringTable(u8);

impl StringTable {
    pub fn section_name(&self, section: &ElfSection) -> &'static str {
        use core::{str, slice};

        let name_ptr = unsafe {
            (&self.0 as *const u8).offset(section.name_index as isize)
        };
        let strlen = {
            let mut len = 0;
            while unsafe { *name_ptr.offset(len) } != 0 {
                len += 1;
            }
            len as usize
        };

        str::from_utf8( unsafe {
            slice::from_raw_parts(name_ptr, strlen)
        }).unwrap()
    }
}

#[derive(Clone)]
pub struct ElfSectionIter {
    current_section: &'static ElfSection,
    remaining_sections: u32,
    entry_size: u32,
}

impl Iterator for ElfSectionIter {
    type Item = &'static ElfSection;
    fn next(&mut self) -> Option<&'static ElfSection> {
        if self.remaining_sections == 0 {
            None
        } else {
            let section = self.current_section;
            let next_section_addr = (self.current_section as *const _ as u64) + self.entry_size as u64;
            self.current_section = unsafe{ &*(next_section_addr as *const ElfSection) };
            self.remaining_sections -= 1;
            if section.typ == ElfSectionType::Unused as u32 {
                self.next()
            } else {
                Some(section)
            }
        }
    }
}

#[cfg(feature = "elf32")]
#[derive(Debug)]
#[repr(C)]
pub struct ElfSection {
    name_index: u32,
    typ: u32,
    pub flags: u32,
    pub addr: u32,
    offset: u32,
    pub size: u32,
    link: u32,
    info: u32,
    addralign: u32,
    entry_size: u32,
}

#[cfg(not(feature = "elf32"))]
#[derive(Debug)]
#[repr(C)]
pub struct ElfSection {
    name_index: u32,
    typ: u32,
    pub flags: u64,
    pub addr: u64,
    offset: u64,
    pub size: u64,
    link: u32,
    info: u32,
    addralign: u64,
    entry_size: u64,
}

impl ElfSection {
    pub fn start_address(&self) -> usize {
        self.addr as usize
    }

    pub fn end_address(&self) -> usize {
        (self.addr + self.size) as usize
    }

    pub fn flags(&self) -> ElfSectionFlags {
        ElfSectionFlags::from_bits_truncate(self.flags)
    }

    pub fn is_allocated(&self) -> bool {
        self.flags().contains(ELF_SECTION_ALLOCATED)
    }
}

#[repr(u32)]
pub enum ElfSectionType {
    Unused = 0,
    ProgramSection = 1,
    LinkerSymbolTable = 2,
    StringTable = 3,
    RelaRelocation = 4,
    SymbolHashTable = 5,
    DynamicLinkingTable = 6,
    Note = 7,
    Uninitialized = 8,
    RelRelocation = 9,
    Reserved = 10,
    DynamicLoaderSymbolTable = 11,
    // plus environment-specific use from 0x60000000 to 0x6FFFFFFF
    // plus processor-specific use from 0x70000000 to 0x7FFFFFFF
}

#[cfg(feature = "elf32")]
type ElfSectionFlagsType = u32;

#[cfg(not(feature = "elf32"))]
type ElfSectionFlagsType = u32;

bitflags! {
    flags ElfSectionFlags: ElfSectionFlagsType {
        const ELF_SECTION_WRITABLE = 0x1,
        const ELF_SECTION_ALLOCATED = 0x2,
        const ELF_SECTION_EXECUTABLE = 0x4,
        // plus environment-specific use at 0x0F000000
        // plus processor-specific use at 0xF0000000
    }
}
<commit_msg>Fix mistake with ElfSectionFlagsType<commit_after>
#[derive(Debug)]
#[repr(packed)] // repr(C) would add unwanted padding before first_section
pub struct ElfSectionsTag {
    typ: u32,
    size: u32,
    pub number_of_sections: u32,
    entry_size: u32,
    shndx: u32, // string table
    first_section: ElfSection,
}

impl ElfSectionsTag {
    pub fn sections(&'static self) -> ElfSectionIter {
        ElfSectionIter {
            current_section: &self.first_section,
            remaining_sections: self.number_of_sections - 1,
            entry_size: self.entry_size,
        }
    }

    pub fn string_table(&self) -> &'static StringTable {
        unsafe {
            let string_table_ptr =
                (&self.first_section as *const ElfSection).offset(self.shndx as isize);
            &*((*string_table_ptr).addr as *const StringTable)
        }
    }
}

pub struct StringTable(u8);

impl StringTable {
    pub fn section_name(&self, section: &ElfSection) -> &'static str {
        use core::{str, slice};

        let name_ptr = unsafe {
            (&self.0 as *const u8).offset(section.name_index as isize)
        };
        let strlen = {
            let mut len = 0;
            while unsafe { *name_ptr.offset(len) } != 0 {
                len += 1;
            }
            len as usize
        };

        str::from_utf8( unsafe {
            slice::from_raw_parts(name_ptr, strlen)
        }).unwrap()
    }
}

#[derive(Clone)]
pub struct ElfSectionIter {
    current_section: &'static ElfSection,
    remaining_sections: u32,
    entry_size: u32,
}

impl Iterator for ElfSectionIter {
    type Item = &'static ElfSection;
    fn next(&mut self) -> Option<&'static ElfSection> {
        if self.remaining_sections == 0 {
            None
        } else {
            let section = self.current_section;
            let next_section_addr = (self.current_section as *const _ as u64) + self.entry_size as u64;
            self.current_section = unsafe{ &*(next_section_addr as *const ElfSection) };
            self.remaining_sections -= 1;
            if section.typ == ElfSectionType::Unused as u32 {
                self.next()
            } else {
                Some(section)
            }
        }
    }
}

#[cfg(feature = "elf32")]
#[derive(Debug)]
#[repr(C)]
pub struct ElfSection {
    name_index: u32,
    typ: u32,
    pub flags: u32,
    pub addr: u32,
    offset: u32,
    pub size: u32,
    link: u32,
    info: u32,
    addralign: u32,
    entry_size: u32,
}

#[cfg(not(feature = "elf32"))]
#[derive(Debug)]
#[repr(C)]
pub struct ElfSection {
    name_index: u32,
    typ: u32,
    pub flags: u64,
    pub addr: u64,
    offset: u64,
    pub size: u64,
    link: u32,
    info: u32,
    addralign: u64,
    entry_size: u64,
}

impl ElfSection {
    pub fn start_address(&self) -> usize {
        self.addr as usize
    }

    pub fn end_address(&self) -> usize {
        (self.addr + self.size) as usize
    }

    pub fn flags(&self) -> ElfSectionFlags {
        ElfSectionFlags::from_bits_truncate(self.flags)
    }

    pub fn is_allocated(&self) -> bool {
        self.flags().contains(ELF_SECTION_ALLOCATED)
    }
}

#[repr(u32)]
pub enum ElfSectionType {
    Unused = 0,
    ProgramSection = 1,
    LinkerSymbolTable = 2,
    StringTable = 3,
    RelaRelocation = 4,
    SymbolHashTable = 5,
    DynamicLinkingTable = 6,
    Note = 7,
    Uninitialized = 8,
    RelRelocation = 9,
    Reserved = 10,
    DynamicLoaderSymbolTable = 11,
    // plus environment-specific use from 0x60000000 to 0x6FFFFFFF
    // plus processor-specific use from 0x70000000 to 0x7FFFFFFF
}

#[cfg(feature = "elf32")]
type ElfSectionFlagsType = u32;

#[cfg(not(feature = "elf32"))]
type ElfSectionFlagsType = u64;

bitflags! {
    flags ElfSectionFlags: ElfSectionFlagsType {
        const ELF_SECTION_WRITABLE = 0x1,
        const ELF_SECTION_ALLOCATED = 0x2,
        const ELF_SECTION_EXECUTABLE = 0x4,
        // plus environment-specific use at 0x0F000000
        // plus processor-specific use at 0xF0000000
    }
}
<|endoftext|>


<commit_before>use super::*;
use crate::norm::Norm;
use num_traits::One;
use std::iter::*;

/// Execute Arnodi iteration as Rust iterator
///
/// - [Arnoldi iteration - Wikipedia](https://en.wikipedia.org/wiki/Arnoldi_iteration)
///
pub struct Arnoldi<A, S, F, Ortho>
where
    A: Scalar,
    S: DataMut<Elem = A>,
    F: Fn(&mut ArrayBase<S, Ix1>),
    Ortho: Orthogonalizer<Elem = A>,
{
    a: F,
    /// Next vector (normalized `|v|=1`)
    v: ArrayBase<S, Ix1>,
    /// Orthogonalizer
    ortho: Ortho,
    /// Coefficients to be composed into H-matrix
    h: Vec<Array1<A>>,
}

impl<A, S, F, Ortho> Arnoldi<A, S, F, Ortho>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
    F: Fn(&mut ArrayBase<S, Ix1>),
    Ortho: Orthogonalizer<Elem = A>,
{
    pub fn new(a: F, mut v: ArrayBase<S, Ix1>, mut ortho: Ortho) -> Self {
        assert_eq!(ortho.len(), 0);
        assert!(ortho.tolerance() < One::one());
        // normalize before append because |v| may be smaller than ortho.tolerance()
        let norm = v.norm_l2();
        azip!(mut v(&mut v) in { *v = v.div_real(norm) });
        ortho.append(v.view());
        Arnoldi {
            a,
            v,
            ortho,
            h: Vec::new(),
        }
    }

    /// Dimension of Krylov subspace
    pub fn dim(&self) -> usize {
        self.ortho.len()
    }

    /// Iterate until convergent
    pub fn complete(mut self) -> (Q<A>, H<A>) {
        for _ in &mut self {} // execute iteration until convergent
        let q = self.ortho.get_q();
        let n = self.h.len();
        let mut h = Array2::zeros((n, n).f());
        for (i, hc) in self.h.iter().enumerate() {
            let m = std::cmp::min(n, i + 2);
            for j in 0..m {
                h[(j, i)] = hc[j];
            }
        }
        (q, h)
    }
}

impl<A, S, F, Ortho> Iterator for Arnoldi<A, S, F, Ortho>
where
    A: Scalar,
    S: DataMut<Elem = A>,
    F: Fn(&mut ArrayBase<S, Ix1>),
    Ortho: Orthogonalizer<Elem = A>,
{
    type Item = Array1<A>;

    fn next(&mut self) -> Option<Self::Item> {
        (self.a)(&mut self.v);
        let result = self.ortho.div_append(&mut self.v);
        azip!(mut v(&mut self.v) in { *v = v.div_real(result.residual_norm()) });
        match result {
            AppendResult::Added(coef) => {
                dbg!(&coef);
                self.h.push(coef.clone());
                Some(coef)
            }
            AppendResult::Dependent(coef) => {
                dbg!(&coef);
                self.h.push(coef);
                None
            }
        }
    }
}

/// Interpret a matrix as a linear operator
pub fn mul_mat<A, S1, S2>(a: ArrayBase<S1, Ix2>) -> impl Fn(&mut ArrayBase<S2, Ix1>)
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: DataMut<Elem = A>,
{
    let (n, m) = a.dim();
    assert_eq!(n, m, "Input matrix must be square");
    move |x| {
        assert_eq!(m, x.len(), "Input matrix and vector sizes mismatch");
        let ax = a.dot(x);
        azip!(mut x(x), ax in { *x = ax });
    }
}

/// Utility to execute Arnoldi iteration with Householder reflection
pub fn arnoldi_householder<A, S1, S2>(a: ArrayBase<S1, Ix2>, v: ArrayBase<S2, Ix1>, tol: A::Real) -> (Q<A>, H<A>)
where
    A: Scalar + Lapack,
    S1: Data<Elem = A>,
    S2: DataMut<Elem = A>,
{
    let householder = Householder::new(v.len(), tol);
    Arnoldi::new(mul_mat(a), v, householder).complete()
}

/// Utility to execute Arnoldi iteration with modified Gram-Schmit orthogonalizer
pub fn arnoldi_mgs<A, S1, S2>(a: ArrayBase<S1, Ix2>, v: ArrayBase<S2, Ix1>, tol: A::Real) -> (Q<A>, H<A>)
where
    A: Scalar + Lapack,
    S1: Data<Elem = A>,
    S2: DataMut<Elem = A>,
{
    let mgs = MGS::new(v.len(), tol);
    Arnoldi::new(mul_mat(a), v, mgs).complete()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::generate::*;

    #[test]
    fn aq_qh() {
        let a = array![[1.0, 2.0], [3.0, 5.0]];
        let mut v = Array::zeros(2);
        v[0] = 1.0;
        let (q, h) = arnoldi_mgs(a.clone(), v, 1e-9);
        println!("A = \n{:?}", &a);
        println!("Q = \n{:?}", &q);
        println!("H = \n{:?}", &h);
        println!("AQ = \n{:?}", a.dot(&q));
        println!("QH = \n{:?}", q.dot(&h));
        panic!()
    }

    #[test]
    fn aq_qh_random() {
        let a: Array2<f64> = random((5, 5));
        let mut v = Array::zeros(5);
        v[0] = 1.0;
        let (q, h) = arnoldi_mgs(a.clone(), v, 1e-9);
        println!("A = \n{:?}", &a);
        println!("Q = \n{:?}", &q);
        println!("H = \n{:?}", &h);
        println!("AQ = \n{:?}", a.dot(&q));
        println!("QH = \n{:?}", q.dot(&h));
        panic!()
    }

}
<commit_msg>Add test and bug fix<commit_after>use super::*;
use crate::norm::Norm;
use num_traits::One;
use std::iter::*;

/// Execute Arnodi iteration as Rust iterator
///
/// - [Arnoldi iteration - Wikipedia](https://en.wikipedia.org/wiki/Arnoldi_iteration)
///
pub struct Arnoldi<A, S, F, Ortho>
where
    A: Scalar,
    S: DataMut<Elem = A>,
    F: Fn(&mut ArrayBase<S, Ix1>),
    Ortho: Orthogonalizer<Elem = A>,
{
    a: F,
    /// Next vector (normalized `|v|=1`)
    v: ArrayBase<S, Ix1>,
    /// Orthogonalizer
    ortho: Ortho,
    /// Coefficients to be composed into H-matrix
    h: Vec<Array1<A>>,
}

impl<A, S, F, Ortho> Arnoldi<A, S, F, Ortho>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
    F: Fn(&mut ArrayBase<S, Ix1>),
    Ortho: Orthogonalizer<Elem = A>,
{
    pub fn new(a: F, mut v: ArrayBase<S, Ix1>, mut ortho: Ortho) -> Self {
        assert_eq!(ortho.len(), 0);
        assert!(ortho.tolerance() < One::one());
        // normalize before append because |v| may be smaller than ortho.tolerance()
        let norm = v.norm_l2();
        azip!(mut v(&mut v) in { *v = v.div_real(norm) });
        ortho.append(v.view());
        Arnoldi {
            a,
            v,
            ortho,
            h: Vec::new(),
        }
    }

    /// Dimension of Krylov subspace
    pub fn dim(&self) -> usize {
        self.ortho.len()
    }

    /// Iterate until convergent
    pub fn complete(mut self) -> (Q<A>, H<A>) {
        for _ in &mut self {} // execute iteration until convergent
        let q = self.ortho.get_q();
        let n = self.h.len();
        let mut h = Array2::zeros((n, n).f());
        for (i, hc) in self.h.iter().enumerate() {
            let m = std::cmp::min(n, i + 2);
            for j in 0..m {
                h[(j, i)] = hc[j];
            }
        }
        (q, h)
    }
}

impl<A, S, F, Ortho> Iterator for Arnoldi<A, S, F, Ortho>
where
    A: Scalar + Lapack,
    S: DataMut<Elem = A>,
    F: Fn(&mut ArrayBase<S, Ix1>),
    Ortho: Orthogonalizer<Elem = A>,
{
    type Item = Array1<A>;

    fn next(&mut self) -> Option<Self::Item> {
        (self.a)(&mut self.v);
        let result = self.ortho.div_append(&mut self.v);
        let norm = self.v.norm_l2();
        azip!(mut v(&mut self.v) in { *v = v.div_real(norm) });
        match result {
            AppendResult::Added(coef) => {
                self.h.push(coef.clone());
                Some(coef)
            }
            AppendResult::Dependent(coef) => {
                self.h.push(coef);
                None
            }
        }
    }
}

/// Interpret a matrix as a linear operator
pub fn mul_mat<A, S1, S2>(a: ArrayBase<S1, Ix2>) -> impl Fn(&mut ArrayBase<S2, Ix1>)
where
    A: Scalar,
    S1: Data<Elem = A>,
    S2: DataMut<Elem = A>,
{
    let (n, m) = a.dim();
    assert_eq!(n, m, "Input matrix must be square");
    move |x| {
        assert_eq!(m, x.len(), "Input matrix and vector sizes mismatch");
        let ax = a.dot(x);
        azip!(mut x(x), ax in { *x = ax });
    }
}

/// Utility to execute Arnoldi iteration with Householder reflection
pub fn arnoldi_householder<A, S1, S2>(a: ArrayBase<S1, Ix2>, v: ArrayBase<S2, Ix1>, tol: A::Real) -> (Q<A>, H<A>)
where
    A: Scalar + Lapack,
    S1: Data<Elem = A>,
    S2: DataMut<Elem = A>,
{
    let householder = Householder::new(v.len(), tol);
    Arnoldi::new(mul_mat(a), v, householder).complete()
}

/// Utility to execute Arnoldi iteration with modified Gram-Schmit orthogonalizer
pub fn arnoldi_mgs<A, S1, S2>(a: ArrayBase<S1, Ix2>, v: ArrayBase<S2, Ix1>, tol: A::Real) -> (Q<A>, H<A>)
where
    A: Scalar + Lapack,
    S1: Data<Elem = A>,
    S2: DataMut<Elem = A>,
{
    let mgs = MGS::new(v.len(), tol);
    Arnoldi::new(mul_mat(a), v, mgs).complete()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{assert::*, generate::*};

    #[test]
    fn aq_qh() {
        let a = array![[1.0, 2.0], [3.0, 5.0]];
        let mut v = Array::zeros(2);
        v[0] = 1.0;
        let (q, h) = arnoldi_mgs(a.clone(), v, 1e-9);
        println!("A = \n{:?}", &a);
        println!("Q = \n{:?}", &q);
        println!("H = \n{:?}", &h);
        let aq = a.dot(&q);
        let qh = q.dot(&h);
        println!("AQ = \n{:?}", a.dot(&q));
        println!("QH = \n{:?}", q.dot(&h));
        close_l2(&aq, &qh, 1e-9);
    }

    #[test]
    fn aq_qh_random() {
        let a: Array2<f64> = random((5, 5));
        let v: Array1<f64> = random(5);
        let (q, h) = arnoldi_mgs(a.clone(), v, 1e-9);
        println!("A = \n{:?}", &a);
        println!("Q = \n{:?}", &q);
        println!("H = \n{:?}", &h);
        let aq = a.dot(&q);
        let qh = q.dot(&h);
        println!("AQ = \n{:?}", &aq);
        println!("QH = \n{:?}", &qh);
        close_l2(&aq, &qh, 1e-9);
    }

}
<|endoftext|>


<commit_before>extern crate rand;

use self::rand::Rng;
use std::fmt;

#[derive(Debug, PartialEq)]
pub enum AliasDistributionError {
    NegativeWeight,
    NullDistribution,
}

impl ::std::error::Error for AliasDistributionError {}

impl fmt::Display for AliasDistributionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            AliasDistributionError::NegativeWeight => {
                write!(f, "Negative weights are not allowed.")
            }
            AliasDistributionError::NullDistribution => {
                write!(f, "Sum of weights must be non-zero.")
            }
        }
    }
}

#[derive(Debug)]
pub struct AliasDistribution {
    probability_table: Vec<f64>,
    alias_table: Vec<usize>,
    pub entropy: f64,
}

impl AliasDistribution {
    pub fn new(weights: &Vec<f64>) -> Result<AliasDistribution, AliasDistributionError> {
        if weights.iter().any(|&w| w < 0.0) {
            return Err(AliasDistributionError::NegativeWeight);
        };
        let size = weights.len();
        let total = weights.iter().fold(0.0, |sum, x| sum + x);
        if total == 0.0 {
            return Err(AliasDistributionError::NullDistribution);
        };
        let mut entropy = 0.0;

        let mut probability_table = Vec::with_capacity(size);
        for weight in weights {
            let prob = weight / total;
            entropy -= prob * prob.log(2.0);
            probability_table.push(prob * (size as f64));
        }

        let mut alias_table: Vec<usize> = (0..size).collect();
        let mut overfull: Vec<usize> = Vec::new();
        let mut underfull: Vec<usize> = Vec::new();
        for (i, &prob) in probability_table.iter().enumerate() {
            if prob < 1.0 {
                underfull.push(i);
            } else {
                overfull.push(i);
            }
        }
        while let (Some(i), Some(j)) = (underfull.pop(), overfull.pop()) {
            alias_table[i] = j;
            probability_table[j] += probability_table[i] - 1.0;
            if probability_table[j] < 1.0 {
                underfull.push(j)
            } else {
                overfull.push(j)
            };
        }

        Ok(AliasDistribution {
            probability_table: probability_table,
            alias_table: alias_table,
            entropy: entropy,
        })
    }

    pub fn choice(&self) -> usize {
        // TODO: Catch the potential error and let the caller decide what to do.
        let mut rng = rand::OsRng::new().unwrap();
        let i = rng.gen_range(0, self.probability_table.len());
        let y = rng.gen();
        let choice = if self.probability_table[i] >= y {
            i
        } else {
            self.alias_table[i]
        };

        choice
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    macro_rules! assert_approx_eq {
        ($a:expr, $b:expr) => {{
            let (a, b) = (&$a, &$b);
            assert!(
                (*a - *b).abs() < 1.0e-6,
                "{} is not approximately equal to {}",
                *a,
                *b
            );
        }};
    }

    #[test]
    fn test_new() {
        let mut test_cases = Vec::new();
        test_cases.push(vec![1.0, 2.0, 3.0, 4.0]);
        test_cases.push(vec![0.2, 0.2, 0.2, 0.2, 0.2]);
        test_cases.push(vec![3.0, 0.0, 5.0]);
        test_cases.push(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);

        for weights in test_cases {
            let total = weights.iter().fold(0.0, |x, sum| sum + x);
            let count = weights.len() as f64;
            let dist = AliasDistribution::new(&weights).unwrap();
            let mut ps = vec![0.0; weights.len()];
            for (i, (&j, p)) in dist
                .alias_table
                .iter()
                .zip(dist.probability_table)
                .enumerate()
            {
                ps[i] += p / count;
                ps[j] += (1.0 - p) / count;
            }
            for (p, w) in ps.iter().zip(weights) {
                assert_approx_eq!(p, w / total);
            }
        }
    }

    #[test]
    fn test_negative_weight() {
        let err = AliasDistribution::new(&vec![3.2, -0.3, 4.5]).unwrap_err();
        assert_eq!(err, AliasDistributionError::NegativeWeight);
    }

    #[test]
    fn test_zero_distribution() {
        let err = AliasDistribution::new(&vec![0.0, 0.0, 0.0]).unwrap_err();
        assert_eq!(err, AliasDistributionError::NullDistribution);
    }

    #[test]
    fn test_empty_distribution() {
        let err = AliasDistribution::new(&Vec::new()).unwrap_err();
        assert_eq!(err, AliasDistributionError::NullDistribution);
    }

    #[test]
    fn test_entropy() {
        let dist = AliasDistribution::new(&vec![1.0, 1.0]).unwrap();
        assert_approx_eq!(dist.entropy, 1.0);
        let dist = AliasDistribution::new(&vec![0.5, 0.5, 1.0, 2.0]).unwrap();
        assert_approx_eq!(dist.entropy, 1.75);
    }

    #[test]
    fn test_choice() {
        let dist = AliasDistribution::new(&vec![1.0, 2.0, 3.0]).unwrap();
        let choice = dist.choice();
        assert!(choice < 3, "{} is too large");
    }
}
<commit_msg>Handle Nan/Infinity errors in AliasDistribution<commit_after>extern crate rand;

use self::rand::Rng;
use std::fmt;

#[derive(Debug, PartialEq)]
pub enum AliasDistributionError {
    InvalidWeight,
    NullDistribution,
}

impl ::std::error::Error for AliasDistributionError {}

impl fmt::Display for AliasDistributionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            AliasDistributionError::InvalidWeight => {
                write!(f, "Weights must be finite non-negative values.")
            }
            AliasDistributionError::NullDistribution => {
                write!(f, "Sum of weights must be non-zero.")
            }
        }
    }
}

#[derive(Debug)]
pub struct AliasDistribution {
    probability_table: Vec<f64>,
    alias_table: Vec<usize>,
    pub entropy: f64,
}

impl AliasDistribution {
    pub fn new(weights: &Vec<f64>) -> Result<AliasDistribution, AliasDistributionError> {
        if weights
            .iter()
            .any(|&w| w.is_sign_negative() || !w.is_finite())
        {
            return Err(AliasDistributionError::InvalidWeight);
        };
        let size = weights.len();
        let total: f64 = weights.iter().sum();
        if total == 0.0 {
            return Err(AliasDistributionError::NullDistribution);
        };
        let mut entropy = 0.0;

        let mut probability_table = Vec::with_capacity(size);
        for weight in weights {
            let prob = weight / total;
            entropy -= prob * prob.log(2.0);
            probability_table.push(prob * (size as f64));
        }

        let mut alias_table: Vec<usize> = (0..size).collect();
        let mut overfull: Vec<usize> = Vec::new();
        let mut underfull: Vec<usize> = Vec::new();
        for (i, &prob) in probability_table.iter().enumerate() {
            if prob < 1.0 {
                underfull.push(i);
            } else {
                overfull.push(i);
            }
        }
        while let (Some(i), Some(j)) = (underfull.pop(), overfull.pop()) {
            alias_table[i] = j;
            probability_table[j] += probability_table[i] - 1.0;
            if probability_table[j] < 1.0 {
                underfull.push(j)
            } else {
                overfull.push(j)
            };
        }

        Ok(AliasDistribution {
            probability_table: probability_table,
            alias_table: alias_table,
            entropy: entropy,
        })
    }

    pub fn choice(&self) -> usize {
        // TODO: Catch the potential error and let the caller decide what to do.
        let mut rng = rand::OsRng::new().unwrap();
        let i = rng.gen_range(0, self.probability_table.len());
        if self.probability_table[i] >= rng.gen() {
            i
        } else {
            self.alias_table[i]
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    macro_rules! assert_approx_eq {
        ($a:expr, $b:expr) => {{
            let (a, b) = (&$a, &$b);
            assert!(
                (*a - *b).abs() < 1.0e-6,
                "{} is not approximately equal to {}",
                *a,
                *b
            );
        }};
    }

    #[test]
    fn test_new() {
        let mut test_cases = Vec::new();
        test_cases.push(vec![1.0, 2.0, 3.0, 4.0]);
        test_cases.push(vec![0.2, 0.2, 0.2, 0.2, 0.2]);
        test_cases.push(vec![3.0, 0.0, 5.0]);
        test_cases.push(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);

        for weights in test_cases {
            let total = weights.iter().fold(0.0, |x, sum| sum + x);
            let count = weights.len() as f64;
            let dist = AliasDistribution::new(&weights).unwrap();
            let mut ps = vec![0.0; weights.len()];
            for (i, (&j, p)) in dist
                .alias_table
                .iter()
                .zip(dist.probability_table)
                .enumerate()
            {
                ps[i] += p / count;
                ps[j] += (1.0 - p) / count;
            }
            for (p, w) in ps.iter().zip(weights) {
                assert_approx_eq!(p, w / total);
            }
        }
    }

    #[test]
    fn test_negative_weight() {
        let err = AliasDistribution::new(&vec![3.2, -0.3, 4.5]).unwrap_err();
        assert_eq!(err, AliasDistributionError::InvalidWeight);
    }

    #[test]
    fn test_nan_weight() {
        let err = AliasDistribution::new(&vec![3.2, f64::NAN, 4.5]).unwrap_err();
        assert_eq!(err, AliasDistributionError::InvalidWeight);
    }

    #[test]
    fn test_infinite() {
        let err = AliasDistribution::new(&vec![3.2, 0.5, f64::INFINITY]).unwrap_err();
        assert_eq!(err, AliasDistributionError::InvalidWeight);
    }

    #[test]
    fn test_zero_distribution() {
        let err = AliasDistribution::new(&vec![0.0, 0.0, 0.0]).unwrap_err();
        assert_eq!(err, AliasDistributionError::NullDistribution);
    }

    #[test]
    fn test_empty_distribution() {
        let err = AliasDistribution::new(&Vec::new()).unwrap_err();
        assert_eq!(err, AliasDistributionError::NullDistribution);
    }

    #[test]
    fn test_entropy() {
        let dist = AliasDistribution::new(&vec![1.0, 1.0]).unwrap();
        assert_approx_eq!(dist.entropy, 1.0);
        let dist = AliasDistribution::new(&vec![0.5, 0.5, 1.0, 2.0]).unwrap();
        assert_approx_eq!(dist.entropy, 1.75);
    }

    #[test]
    fn test_choice() {
        let dist = AliasDistribution::new(&vec![1.0, 2.0, 3.0]).unwrap();
        let choice = dist.choice();
        assert!(choice < 3, "{} is too large");
    }
}
<|endoftext|>


<commit_before>use nom::{
  be_u8, be_u16,
  IResult,
  ErrorCode, Err,
};

use frame::{
  ChannelAssignment, NumberType,
  Frame,
  Header, Footer,
};

use metadata::StreamInfo;
use utility::{crc8, crc16, to_u32};

pub fn frame_parser<'a>(input: &'a [u8], stream_info: &StreamInfo)
                        -> IResult<'a, &'a [u8], Frame> {
  let result = chain!(input,
    frame_header: apply!(header, stream_info) ~
    frame_footer: footer,
    || {
      Frame {
        header: frame_header,
        footer: frame_footer,
      }
    }
  );

  match result {
    IResult::Done(i, frame)   => {
      // All frame bytes before the crc-16
      let end         = (input.len() - i.len()) - 2;
      let Footer(crc) = frame.footer;

      if crc16(&input[0..end]) == crc {
        IResult::Done(i, frame)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn blocking_strategy(input: &[u8]) -> IResult<&[u8], bool> {
  match take!(input, 2) {
    IResult::Done(i, bytes)   => {
      let sync_code = ((bytes[0] as u16) << 6) +
                      (bytes[1] as u16) >> 2;
      let is_valid  = ((bytes[1] >> 1) & 0b01) == 0;

      if sync_code == 0b11111111111110 && is_valid {
        let is_variable_block_size = (bytes[1] & 0b01) == 1;

        IResult::Done(i, is_variable_block_size)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn block_sample(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let block_byte  = bytes[0] >> 4;
      let sample_byte = bytes[0] & 0x0f;
      let is_valid    = block_byte != 0b0000 && sample_byte != 0b1111;

      if is_valid {
        IResult::Done(i, (block_byte, sample_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn channel_bits(input: &[u8]) -> IResult<&[u8], (ChannelAssignment, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let channel_byte       = bytes[0] >> 4
      let channel_assignment = match channel_byte {
        0b0000...0b0111 => ChannelAssignment::Independent,
        0b1000          => ChannelAssignment::LeftSide,
        0b1001          => ChannelAssignment::RightSide,
        0b1010          => ChannelAssignment::MiddleSide,
        _               => ChannelAssignment::Independent,
      };
      let size_byte = (bytes[0] >> 1) & 0b0111;
      let is_valid  = channel_byte < 0b1011 &&
                      (size_byte != 0b0011 && size_byte != 0b0111) &&
                      (bytes[0] & 0b01) == 0;

      if is_valid {
        IResult::Done(i, (channel_assignment, size_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn utf8_size(input: &[u8], is_u64: bool)
             -> IResult<&[u8], Option<(usize, u8)>> {
  map!(input, be_u8, |utf8_header| {
    match utf8_header {
      0b00000000...0b01111111 => Some((0, utf8_header)),
      0b11000000...0b11011111 => Some((1, utf8_header & 0b00011111)),
      0b11100000...0b11101111 => Some((2, utf8_header & 0b00001111)),
      0b11110000...0b11110111 => Some((3, utf8_header & 0b00000111)),
      0b11111000...0b11111011 => Some((4, utf8_header & 0b00000011)),
      0b11111100...0b11111101 => Some((5, utf8_header & 0b00000001)),
      0b11111110              => if is_u64 { Some((6, 0)) } else { None },
      _                       => None,
    }
  })
}

fn sample_or_frame_number(input: &[u8], is_sample: bool,
                          (size, value): (usize, u8))
                          -> IResult<&[u8], NumberType> {
  let mut result   = value as u64;
  let mut is_error = false;

  match take!(input, size) {
    IResult::Done(i, bytes)   => {
      for i in 0..size {
        let byte = bytes[i] as u64;

        if byte >= 0b10000000 && byte <= 0b10111111 {
          result = (result << 6) + (byte & 0b00111111);
        } else {
          is_error = true;
          break;
        }
      }

      if is_error {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      } else if is_sample {
        IResult::Done(i, NumberType::Sample(result))
      } else {
        IResult::Done(i, NumberType::Frame(result as u32))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn secondary_block_size(input: &[u8], block_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match block_byte {
    0b0110 => opt!(input, map!(take!(1), to_u32)),
    0b0111 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn secondary_sample_rate(input: &[u8], sample_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match sample_byte {
    0b1100 => opt!(input, map!(take!(1), to_u32)),
    0b1101 => opt!(input, map!(take!(2), to_u32)),
    0b1110 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn header<'a>(input: &'a [u8], stream_info: &StreamInfo)
              -> IResult<'a, &'a [u8], Header> {
  let result = chain!(input,
    is_variable_block_size: blocking_strategy ~
    tuple0: block_sample ~
    tuple1: channel_bits ~
    number_opt: apply!(utf8_size, is_variable_block_size) ~
    number_length: expr_opt!(number_opt) ~
    number: apply!(sample_or_frame_number, is_variable_block_size,
                   number_length) ~
    alt_block_size: apply!(secondary_block_size, tuple0.0) ~
    alt_sample_rate: apply!(secondary_sample_rate, tuple0.1) ~
    crc: be_u8,
    || {
      let (block_byte, sample_byte)       = tuple0;
      let (channel_assignment, size_byte) = tuple1;

      let block_size = match block_byte {
        0b0000          => 0,
        0b0001          => 192,
        0b0010...0b0101 => 576 * 2_u32.pow(block_byte as u32 - 2),
        0b0110 | 0b0111 => alt_block_size.unwrap() + 1,
        0b1000...0b1111 => 256 * 2_u32.pow(block_byte as u32 - 8),
        _               => unreachable!(),
      };

      let sample_rate = match sample_byte {
        0b0000 => stream_info.sample_rate,
        0b0001 => 88200,
        0b0010 => 176400,
        0b0011 => 192000,
        0b0100 => 8000,
        0b0101 => 16000,
        0b0110 => 22050,
        0b0111 => 24000,
        0b1000 => 32000,
        0b1001 => 44100,
        0b1010 => 48000,
        0b1011 => 96000,
        0b1100 => alt_sample_rate.unwrap() * 1000,
        0b1101 => alt_sample_rate.unwrap(),
        0b1110 => alt_sample_rate.unwrap() * 10,
        0b1111 => 0,
        _      => unreachable!(),
      };

      let bits_per_sample = match size_byte {
        0b0000 => stream_info.bits_per_sample as usize,
        0b0001 => 8,
        0b0010 => 12,
        0b0011 => 0,
        0b0100 => 16,
        0b0101 => 20,
        0b0110 => 24,
        0b0111 => 0,
        _      => unreachable!(),
      };

      Header {
        block_size: block_size,
        sample_rate: sample_rate,
        channel_assignment: channel_assignment,
        bits_per_sample: bits_per_sample,
        number: number,
        crc: crc,
      }
    }
  );

  match result {
    IResult::Done(i, frame_header) => {
      // All header bytes before the crc-8
      let end = (input.len() - i.len()) - 1;

      if crc8(&input[0..end]) == frame_header.crc {
        IResult::Done(i, frame_header)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)          => IResult::Error(error),
    IResult::Incomplete(need)      => IResult::Incomplete(need),
  }
}

named!(footer <&[u8], Footer>, map!(be_u16, Footer));
<commit_msg>Remove the zero value for certain bits<commit_after>use nom::{
  be_u8, be_u16,
  IResult,
  ErrorCode, Err,
};

use frame::{
  ChannelAssignment, NumberType,
  Frame,
  Header, Footer,
};

use metadata::StreamInfo;
use utility::{crc8, crc16, to_u32};

pub fn frame_parser<'a>(input: &'a [u8], stream_info: &StreamInfo)
                        -> IResult<'a, &'a [u8], Frame> {
  let result = chain!(input,
    frame_header: apply!(header, stream_info) ~
    frame_footer: footer,
    || {
      Frame {
        header: frame_header,
        footer: frame_footer,
      }
    }
  );

  match result {
    IResult::Done(i, frame)   => {
      // All frame bytes before the crc-16
      let end         = (input.len() - i.len()) - 2;
      let Footer(crc) = frame.footer;

      if crc16(&input[0..end]) == crc {
        IResult::Done(i, frame)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn blocking_strategy(input: &[u8]) -> IResult<&[u8], bool> {
  match take!(input, 2) {
    IResult::Done(i, bytes)   => {
      let sync_code = ((bytes[0] as u16) << 6) +
                      (bytes[1] as u16) >> 2;
      let is_valid  = ((bytes[1] >> 1) & 0b01) == 0;

      if sync_code == 0b11111111111110 && is_valid {
        let is_variable_block_size = (bytes[1] & 0b01) == 1;

        IResult::Done(i, is_variable_block_size)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn block_sample(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let block_byte  = bytes[0] >> 4;
      let sample_byte = bytes[0] & 0x0f;
      let is_valid    = block_byte != 0b0000 && sample_byte != 0b1111;

      if is_valid {
        IResult::Done(i, (block_byte, sample_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn channel_bits(input: &[u8]) -> IResult<&[u8], (ChannelAssignment, u8)> {
  match take!(input, 1) {
    IResult::Done(i, bytes)   => {
      let channel_byte       = bytes[0] >> 4
      let channel_assignment = match channel_byte {
        0b0000...0b0111 => ChannelAssignment::Independent,
        0b1000          => ChannelAssignment::LeftSide,
        0b1001          => ChannelAssignment::RightSide,
        0b1010          => ChannelAssignment::MiddleSide,
        _               => ChannelAssignment::Independent,
      };
      let size_byte = (bytes[0] >> 1) & 0b0111;
      let is_valid  = channel_byte < 0b1011 &&
                      (size_byte != 0b0011 && size_byte != 0b0111) &&
                      (bytes[0] & 0b01) == 0;

      if is_valid {
        IResult::Done(i, (channel_assignment, size_byte))
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn utf8_size(input: &[u8], is_u64: bool)
             -> IResult<&[u8], Option<(usize, u8)>> {
  map!(input, be_u8, |utf8_header| {
    match utf8_header {
      0b00000000...0b01111111 => Some((0, utf8_header)),
      0b11000000...0b11011111 => Some((1, utf8_header & 0b00011111)),
      0b11100000...0b11101111 => Some((2, utf8_header & 0b00001111)),
      0b11110000...0b11110111 => Some((3, utf8_header & 0b00000111)),
      0b11111000...0b11111011 => Some((4, utf8_header & 0b00000011)),
      0b11111100...0b11111101 => Some((5, utf8_header & 0b00000001)),
      0b11111110              => if is_u64 { Some((6, 0)) } else { None },
      _                       => None,
    }
  })
}

fn sample_or_frame_number(input: &[u8], is_sample: bool,
                          (size, value): (usize, u8))
                          -> IResult<&[u8], NumberType> {
  let mut result   = value as u64;
  let mut is_error = false;

  match take!(input, size) {
    IResult::Done(i, bytes)   => {
      for i in 0..size {
        let byte = bytes[i] as u64;

        if byte >= 0b10000000 && byte <= 0b10111111 {
          result = (result << 6) + (byte & 0b00111111);
        } else {
          is_error = true;
          break;
        }
      }

      if is_error {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      } else if is_sample {
        IResult::Done(i, NumberType::Sample(result))
      } else {
        IResult::Done(i, NumberType::Frame(result as u32))
      }
    }
    IResult::Error(error)     => IResult::Error(error),
    IResult::Incomplete(need) => IResult::Incomplete(need),
  }
}

fn secondary_block_size(input: &[u8], block_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match block_byte {
    0b0110 => opt!(input, map!(take!(1), to_u32)),
    0b0111 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn secondary_sample_rate(input: &[u8], sample_byte: u8)
                        -> IResult<&[u8], Option<u32>> {
  match sample_byte {
    0b1100 => opt!(input, map!(take!(1), to_u32)),
    0b1101 => opt!(input, map!(take!(2), to_u32)),
    0b1110 => opt!(input, map!(take!(2), to_u32)),
    _      => IResult::Done(input, None)
  }
}

fn header<'a>(input: &'a [u8], stream_info: &StreamInfo)
              -> IResult<'a, &'a [u8], Header> {
  let result = chain!(input,
    is_variable_block_size: blocking_strategy ~
    tuple0: block_sample ~
    tuple1: channel_bits ~
    number_opt: apply!(utf8_size, is_variable_block_size) ~
    number_length: expr_opt!(number_opt) ~
    number: apply!(sample_or_frame_number, is_variable_block_size,
                   number_length) ~
    alt_block_size: apply!(secondary_block_size, tuple0.0) ~
    alt_sample_rate: apply!(secondary_sample_rate, tuple0.1) ~
    crc: be_u8,
    || {
      let (block_byte, sample_byte)       = tuple0;
      let (channel_assignment, size_byte) = tuple1;

      let block_size = match block_byte {
        0b0001          => 192,
        0b0010...0b0101 => 576 * 2_u32.pow(block_byte as u32 - 2),
        0b0110 | 0b0111 => alt_block_size.unwrap() + 1,
        0b1000...0b1111 => 256 * 2_u32.pow(block_byte as u32 - 8),
        _               => unreachable!(),
      };

      let sample_rate = match sample_byte {
        0b0000 => stream_info.sample_rate,
        0b0001 => 88200,
        0b0010 => 176400,
        0b0011 => 192000,
        0b0100 => 8000,
        0b0101 => 16000,
        0b0110 => 22050,
        0b0111 => 24000,
        0b1000 => 32000,
        0b1001 => 44100,
        0b1010 => 48000,
        0b1011 => 96000,
        0b1100 => alt_sample_rate.unwrap() * 1000,
        0b1101 => alt_sample_rate.unwrap(),
        0b1110 => alt_sample_rate.unwrap() * 10,
        _      => unreachable!(),
      };

      let bits_per_sample = match size_byte {
        0b0000 => stream_info.bits_per_sample as usize,
        0b0001 => 8,
        0b0010 => 12,
        0b0100 => 16,
        0b0101 => 20,
        0b0110 => 24,
        _      => unreachable!(),
      };

      Header {
        block_size: block_size,
        sample_rate: sample_rate,
        channel_assignment: channel_assignment,
        bits_per_sample: bits_per_sample,
        number: number,
        crc: crc,
      }
    }
  );

  match result {
    IResult::Done(i, frame_header) => {
      // All header bytes before the crc-8
      let end = (input.len() - i.len()) - 1;

      if crc8(&input[0..end]) == frame_header.crc {
        IResult::Done(i, frame_header)
      } else {
        IResult::Error(Err::Position(ErrorCode::Digit as u32, input))
      }
    }
    IResult::Error(error)          => IResult::Error(error),
    IResult::Incomplete(need)      => IResult::Incomplete(need),
  }
}

named!(footer <&[u8], Footer>, map!(be_u16, Footer));
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Rust runtime services, including the task scheduler and I/O interface

#[doc(hidden)];

use libc::c_char;

/// The global (exchange) heap.
pub mod global_heap;

/// The Scheduler and Task types.
mod sched;

/// Thread-local access to the current Scheduler
pub mod local_sched;

/// Synchronous I/O
#[path = "io/mod.rs"]
pub mod io;

/// Thread-local implementations of language-critical runtime features like @
pub mod local_services;

/// The EventLoop and internal synchronous I/O interface, dynamically
/// overridable so that it's primary implementation on libuv can
/// live outside of core.
mod rtio;

/// libuv
#[path = "uv/mod.rs"]
pub mod uv;

// FIXME #5248: The import in `sched` doesn't resolve unless this is pub!
/// Bindings to pthread/windows thread-local storage
pub mod thread_local_storage;

/// A parallel work-stealing queue
mod work_queue;

/// Stack segments and their cacheing
mod stack;

/// CPU context swapping
mod context;

/// Bindings to system threading libraries
mod thread;

/// The runtime configuration, read from environment variables
pub mod env;

/// The local, managed heap
mod local_heap;

/// The Logger trait and implementations
pub mod logging;

/// Tools for testing the runtime
#[cfg(test)]
pub mod test;

/// Reference counting
pub mod rc;

/// A simple single-threaded channel type for passing buffered data between
/// scheduler and task context
pub mod tube;

/// Set up a default runtime configuration, given compiler-supplied arguments.
///
/// This is invoked by the `start` _language item_ (unstable::lang) to
/// run a Rust executable.
///
/// # Arguments
///
/// * `main` - A C-abi function that takes no arguments and returns `c_void`.
///   It is a wrapper around the user-defined `main` function, and will be run
///   in a task.
/// * `argc` & `argv` - The argument vector. On Unix this information is used
///   by os::args.
/// * `crate_map` - Runtime information about the executing crate, mostly for logging
///
/// # Return value
///
/// The return value is used as the process return code. 0 on success, 101 on error.
pub fn start(main: *u8, _argc: int, _argv: **c_char, _crate_map: *u8) -> int {

    use self::sched::{Scheduler, Task};
    use self::uv::uvio::UvEventLoop;
    use sys::Closure;
    use ptr;
    use cast;

    let loop_ = ~UvEventLoop::new();
    let mut sched = ~Scheduler::new(loop_);

    let main_task = ~do Task::new(&mut sched.stack_pool) {

        unsafe {
            // `main` is an `fn() -> ()` that doesn't take an environment
            // XXX: Could also call this as an `extern "Rust" fn` once they work
            let main = Closure {
                code: main as *(),
                env: ptr::null(),
            };
            let mainfn: &fn() = cast::transmute(main);

            mainfn();
        }
    };

    sched.task_queue.push_back(main_task);
    sched.run();

    return 0;
}

/// Possible contexts in which Rust code may be executing.
/// Different runtime services are available depending on context.
/// Mostly used for determining if we're using the new scheduler
/// or the old scheduler.
#[deriving(Eq)]
pub enum RuntimeContext {
    // Only the exchange heap is available
    GlobalContext,
    // The scheduler may be accessed
    SchedulerContext,
    // Full task services, e.g. local heap, unwinding
    TaskContext,
    // Running in an old-style task
    OldTaskContext
}

/// Determine the current RuntimeContext
pub fn context() -> RuntimeContext {

    use task::rt::rust_task;
    use self::sched::local_sched;

    // XXX: Hitting TLS twice to check if the scheduler exists
    // then to check for the task is not good for perf
    if unsafe { rust_try_get_task().is_not_null() } {
        return OldTaskContext;
    } else {
        if local_sched::exists() {
            let context = ::cell::empty_cell();
            do local_sched::borrow |sched| {
                if sched.in_task_context() {
                    context.put_back(TaskContext);
                } else {
                    context.put_back(SchedulerContext);
                }
            }
            return context.take();
        } else {
            return GlobalContext;
        }
    }

    pub extern {
        #[rust_stack]
        fn rust_try_get_task() -> *rust_task;
    }
}

#[test]
fn test_context() {
    use unstable::run_in_bare_thread;
    use self::sched::{local_sched, Task};
    use rt::uv::uvio::UvEventLoop;
    use cell::Cell;

    assert!(context() == OldTaskContext);
    do run_in_bare_thread {
        assert!(context() == GlobalContext);
        let mut sched = ~UvEventLoop::new_scheduler();
        let task = ~do Task::new(&mut sched.stack_pool) {
            assert!(context() == TaskContext);
            let sched = local_sched::take();
            do sched.deschedule_running_task_and_then() |task| {
                assert!(context() == SchedulerContext);
                let task = Cell(task);
                do local_sched::borrow |sched| {
                    sched.task_queue.push_back(task.take());
                }
            }
        };
        sched.task_queue.push_back(task);
        sched.run();
    }
}
<commit_msg>core::rt: Docs<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! The Rust Runtime, including the task scheduler and I/O

The `rt` module provides the private runtime infrastructure necessary
to support core language features like the exchange and local heap,
the garbage collector, logging, local data and unwinding. It also
implements the default task scheduler and task model. Initialization
routines are provided for setting up runtime resources in common
configurations, including that used by `rustc` when generating
executables.

It is intended that the features provided by `rt` can be factored in a
way such that the core library can be built with different 'profiles'
for different use cases, e.g. excluding the task scheduler. A number
of runtime features though are critical to the functioning of the
language and an implementation must be provided regardless of the
execution environment.

Of foremost importance is the global exchange heap, in the module
`global_heap`. Very little practical Rust code can be written without
access to the global heap. Unlike most of `rt` the global heap is
truly a global resource and generally operates independently of the
rest of the runtime.

All other runtime features are 'local', either thread-local or
task-local.  Those critical to the functioning of the language are
defined in the module `local_services`. Local services are those which
are expected to be available to Rust code generally but rely on
thread- or task-local state. These currently include the local heap,
the garbage collector, local storage, logging and the stack unwinder.
Local services are primarily implemented for tasks, but may also
be implemented for use outside of tasks.

The relationship between `rt` and the rest of the core library is
not entirely clear yet and some modules will be moving into or
out of `rt` as development proceeds.

Several modules in `core` are clients of `rt`:

* `core::task` - The user-facing interface to the Rust task model.
* `core::task::local_data` - The interface to local data.
* `core::gc` - The garbage collector.
* `core::unstable::lang` - Miscellaneous lang items, some of which rely on `core::rt`.
* `core::condition` - Uses local data.
* `core::cleanup` - Local heap destruction.
* `core::io` - In the future `core::io` will use an `rt` implementation.
* `core::logging`
* `core::pipes`
* `core::comm`
* `core::stackwalk`

*/

#[doc(hidden)];

use libc::c_char;

/// The global (exchange) heap.
pub mod global_heap;

/// The Scheduler and Task types.
mod sched;

/// Thread-local access to the current Scheduler.
pub mod local_sched;

/// Synchronous I/O.
#[path = "io/mod.rs"]
pub mod io;

/// Thread-local implementations of language-critical runtime features like @.
pub mod local_services;

/// The EventLoop and internal synchronous I/O interface.
mod rtio;

/// libuv and default rtio implementation.
#[path = "uv/mod.rs"]
pub mod uv;

// FIXME #5248: The import in `sched` doesn't resolve unless this is pub!
/// Bindings to pthread/windows thread-local storage.
pub mod thread_local_storage;

/// A parallel work-stealing dequeue.
mod work_queue;

/// Stack segments and caching.
mod stack;

/// CPU context swapping.
mod context;

/// Bindings to system threading libraries.
mod thread;

/// The runtime configuration, read from environment variables
pub mod env;

/// The local, managed heap
mod local_heap;

/// The Logger trait and implementations
pub mod logging;

/// Tools for testing the runtime
#[cfg(test)]
pub mod test;

/// Reference counting
pub mod rc;

/// A simple single-threaded channel type for passing buffered data between
/// scheduler and task context
pub mod tube;

/// Set up a default runtime configuration, given compiler-supplied arguments.
///
/// This is invoked by the `start` _language item_ (unstable::lang) to
/// run a Rust executable.
///
/// # Arguments
///
/// * `main` - A C-abi function that takes no arguments and returns `c_void`.
///   It is a wrapper around the user-defined `main` function, and will be run
///   in a task.
/// * `argc` & `argv` - The argument vector. On Unix this information is used
///   by os::args.
/// * `crate_map` - Runtime information about the executing crate, mostly for logging
///
/// # Return value
///
/// The return value is used as the process return code. 0 on success, 101 on error.
pub fn start(main: *u8, _argc: int, _argv: **c_char, _crate_map: *u8) -> int {

    use self::sched::{Scheduler, Task};
    use self::uv::uvio::UvEventLoop;
    use sys::Closure;
    use ptr;
    use cast;

    let loop_ = ~UvEventLoop::new();
    let mut sched = ~Scheduler::new(loop_);

    let main_task = ~do Task::new(&mut sched.stack_pool) {

        unsafe {
            // `main` is an `fn() -> ()` that doesn't take an environment
            // XXX: Could also call this as an `extern "Rust" fn` once they work
            let main = Closure {
                code: main as *(),
                env: ptr::null(),
            };
            let mainfn: &fn() = cast::transmute(main);

            mainfn();
        }
    };

    sched.task_queue.push_back(main_task);
    sched.run();

    return 0;
}

/// Possible contexts in which Rust code may be executing.
/// Different runtime services are available depending on context.
/// Mostly used for determining if we're using the new scheduler
/// or the old scheduler.
#[deriving(Eq)]
pub enum RuntimeContext {
    // Only the exchange heap is available
    GlobalContext,
    // The scheduler may be accessed
    SchedulerContext,
    // Full task services, e.g. local heap, unwinding
    TaskContext,
    // Running in an old-style task
    OldTaskContext
}

/// Determine the current RuntimeContext
pub fn context() -> RuntimeContext {

    use task::rt::rust_task;
    use self::sched::local_sched;

    // XXX: Hitting TLS twice to check if the scheduler exists
    // then to check for the task is not good for perf
    if unsafe { rust_try_get_task().is_not_null() } {
        return OldTaskContext;
    } else {
        if local_sched::exists() {
            let context = ::cell::empty_cell();
            do local_sched::borrow |sched| {
                if sched.in_task_context() {
                    context.put_back(TaskContext);
                } else {
                    context.put_back(SchedulerContext);
                }
            }
            return context.take();
        } else {
            return GlobalContext;
        }
    }

    pub extern {
        #[rust_stack]
        fn rust_try_get_task() -> *rust_task;
    }
}

#[test]
fn test_context() {
    use unstable::run_in_bare_thread;
    use self::sched::{local_sched, Task};
    use rt::uv::uvio::UvEventLoop;
    use cell::Cell;

    assert!(context() == OldTaskContext);
    do run_in_bare_thread {
        assert!(context() == GlobalContext);
        let mut sched = ~UvEventLoop::new_scheduler();
        let task = ~do Task::new(&mut sched.stack_pool) {
            assert!(context() == TaskContext);
            let sched = local_sched::take();
            do sched.deschedule_running_task_and_then() |task| {
                assert!(context() == SchedulerContext);
                let task = Cell(task);
                do local_sched::borrow |sched| {
                    sched.task_queue.push_back(task.take());
                }
            }
        };
        sched.task_queue.push_back(task);
        sched.run();
    }
}
<|endoftext|>


<commit_before>//! Schizofrenic methods which are useful in more than one of request-or-response reading-or-writing
use std::rt::io::Reader;
use std::rt::io::extensions::ReaderUtil;

#[inline]
pub fn read_http_version<T: Reader>(reader: &mut T, next_u8: u8) -> Option<(uint, uint)> {
    // XXX: by doing this, I've stopped the more efficient BufferedReader.read_byte from being used
    // HTTP/%u.%u
    match reader.read_byte() {
        Some(b) if b == 'h' as u8 || b == 'H' as u8 => (),
        _ => return None,
    }
    match reader.read_byte() {
        Some(b) if b == 't' as u8 || b == 'T' as u8 => (),
        _ => return None,
    }
    match reader.read_byte() {
        Some(b) if b == 't' as u8 || b == 'T' as u8 => (),
        _ => return None,
    }
    match reader.read_byte() {
        Some(b) if b == 'p' as u8 || b == 'P' as u8 => (),
        _ => return None,
    }
    match reader.read_byte() {
        Some(b) if b == ('/' as u8) => (),
        _ => return None,
    }

    // First number
    let mut digits = 0u8;
    let mut n1 = 0u;
    loop {
        if digits == 5u8 {
            return None;
        }
        match reader.read_byte() {
            Some(b) if b >= '0' as u8 && b <= '9' as u8 => {
                n1 = n1 * 10 + b as uint - '0' as uint;
            },
            Some(b) if b == '.' as u8 => break,
            _ => return None,
        }
        digits += 1;
    }

    // Second number
    digits = 0u8;
    let mut n2 = 0u;
    loop {
        if digits == 5u8 {
            return None;
        }
        match reader.read_byte() {
            Some(b) if b >= '0' as u8 && b <= '9' as u8 => {
                n2 = n1 * 10 + b as uint - '0' as uint;
            },
            Some(b) if b == next_u8 => break,
            _ => return None,
        }
        digits += 1;
    }
    Some((n1, n2))
}
<commit_msg>Fix broken HTTP minor version parsing.<commit_after>//! Schizofrenic methods which are useful in more than one of request-or-response reading-or-writing
use std::rt::io::Reader;
use std::rt::io::extensions::ReaderUtil;

#[inline]
pub fn read_http_version<T: Reader>(reader: &mut T, next_u8: u8) -> Option<(uint, uint)> {
    // XXX: by doing this, I've stopped the more efficient BufferedReader.read_byte from being used
    // HTTP/%u.%u
    match reader.read_byte() {
        Some(b) if b == 'h' as u8 || b == 'H' as u8 => (),
        _ => return None,
    }
    match reader.read_byte() {
        Some(b) if b == 't' as u8 || b == 'T' as u8 => (),
        _ => return None,
    }
    match reader.read_byte() {
        Some(b) if b == 't' as u8 || b == 'T' as u8 => (),
        _ => return None,
    }
    match reader.read_byte() {
        Some(b) if b == 'p' as u8 || b == 'P' as u8 => (),
        _ => return None,
    }
    match reader.read_byte() {
        Some(b) if b == ('/' as u8) => (),
        _ => return None,
    }

    // First number
    let mut digits = 0u8;
    let mut n1 = 0u;
    loop {
        if digits == 5u8 {
            return None;
        }
        match reader.read_byte() {
            Some(b) if b >= '0' as u8 && b <= '9' as u8 => {
                n1 = n1 * 10 + b as uint - '0' as uint;
            },
            Some(b) if b == '.' as u8 => break,
            _ => return None,
        }
        digits += 1;
    }

    // Second number
    digits = 0u8;
    let mut n2 = 0u;
    loop {
        if digits == 5u8 {
            return None;
        }
        match reader.read_byte() {
            Some(b) if b >= '0' as u8 && b <= '9' as u8 => {
                n2 = n2 * 10 + b as uint - '0' as uint;
            },
            Some(b) if b == next_u8 => break,
            _ => return None,
        }
        digits += 1;
    }
    Some((n1, n2))
}
<|endoftext|>