<commit_before>//! Parser for bitmap fonts

mod char;
mod config_parse_error;
mod error;
mod kerning_value;
mod page;
mod rect;
mod sections;
mod string_parse_error;
mod utils;

pub use self::config_parse_error::ConfigParseError;
pub use self::error::Error;
pub use self::rect::Rect;
pub use self::string_parse_error::StringParseError;

use self::char::Char;
use self::kerning_value::KerningValue;
use self::page::Page;
use self::sections::Sections;
use std::io::Read;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _with_ the `parse-error` feature.
#[cfg(feature = "parse-error")]
pub type Parse<'a> = Result<Vec<CharPosition>, StringParseError>;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _without_ the `parse-error` feature.
#[cfg(not(feature = "parse-error"))]
pub type Parse<'a> = Vec<CharPosition>;

#[cfg(feature = "parse-error")]
type ParseLines<'a> = Result<Vec<Vec<&'a Char>>, StringParseError>;

#[cfg(not(feature = "parse-error"))]
type ParseLines<'a> = Vec<Vec<&'a Char>>;

#[derive(Clone, Debug)]
pub struct CharPosition {
    pub page_rect: Rect,
    pub screen_rect: Rect,
    pub page_index: u32,
}

#[derive(Clone, Debug)]
pub enum OrdinateOrientation {
    BottomToTop,
    TopToBottom,
}

/// Holds a decoded bitmap font defintion, including all character advance and kerning values.
#[derive(Clone, Debug)]
pub struct BMFont {
    base_height: u32,
    line_height: u32,
    characters: Vec<Char>,
    kerning_values: Vec<KerningValue>,
    pages: Vec<Page>,
    ordinate_orientation: OrdinateOrientation,
}

impl BMFont {
    /// Constructs a new [BMFont].
    ///
    /// ## Examples
    ///
    /// From a file:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// From a slice of bytes:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// # let my_font_bytes = std::fs::read("font.fnt")?;
    /// let data = std::io::Cursor::new(my_font_bytes);
    /// let font = BMFont::new(data, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    pub fn new<R>(source: R, ordinate_orientation: OrdinateOrientation) -> Result<BMFont, Error>
    where
        R: Read,
    {
        let sections = Sections::new(source)?;

        let base_height;
        let line_height;
        {
            let mut components = sections.common_section.split_whitespace();
            components.next();
            line_height =
                utils::extract_component_value(components.next(), "common", "lineHeight")?;
            base_height = utils::extract_component_value(components.next(), "common", "base")?;
        }

        let mut pages = Vec::with_capacity(sections.page_sections.len());
        for page_section in &sections.page_sections {
            pages.push(Page::new(page_section)?);
        }

        // Sort the characters while loading them so that lookup can be faster during parse
        let mut characters: Vec<Char> = Vec::with_capacity(sections.char_sections.len());
        for char_section in &sections.char_sections {
            let char = Char::new(char_section)?;
            if let Err(idx) = characters.binary_search_by(|probe| probe.id.cmp(&char.id)) {
                characters.insert(idx, char);
            }
        }

        // Also sort kerning values for the same reason, but we allow duplicates
        let mut kerning_values: Vec<KerningValue> =
            Vec::with_capacity(sections.kerning_sections.len());
        for kerning_section in &sections.kerning_sections {
            let kerning = KerningValue::new(kerning_section)?;

            match kerning_values
                .binary_search_by(|probe| probe.first_char_id.cmp(&kerning.first_char_id))
            {
                Err(idx) | Ok(idx) => kerning_values.insert(idx, kerning),
            }
        }

        Ok(BMFont {
            base_height,
            line_height,
            characters,
            kerning_values,
            pages,
            ordinate_orientation,
        })
    }

    /// Returns the height of a `EM` in pixels.
    pub fn base_height(&self) -> u32 {
        self.base_height
    }

    pub fn line_height(&self) -> u32 {
        self.line_height
    }

    /// Returns an `Iterator` of font page bitmap filenames.
    ///
    /// ## Examples
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.pages().next(), Some("font.png"));
    /// #     Ok(())
    /// # }
    /// ```
    pub fn pages(&self) -> PageIter {
        PageIter::new(&self.pages)
    }

    pub fn parse(&self, s: &str) -> Parse {
        let lines = self.parse_lines(s);

        #[cfg(feature = "parse-error")]
        let lines = lines?;

        let mut char_positions = Vec::new();
        let mut y: i32 = 0;
        for line in lines {
            let mut x: i32 = 0;
            let mut kerning_values = KerningIter::empty(&self.kerning_values);
            for character in line {
                let kerning_value = kerning_values
                    .into_iter()
                    .find(|k| k.second_char_id == character.id)
                    .map(|k| k.value)
                    .unwrap_or(0);
                let page_rect = Rect {
                    x: character.x as i32,
                    y: character.y as i32,
                    width: character.width,
                    height: character.height,
                };
                let screen_x = x + character.xoffset + kerning_value;
                let screen_y = match self.ordinate_orientation {
                    OrdinateOrientation::BottomToTop => {
                        y + self.base_height as i32 - character.yoffset - character.height as i32
                    }
                    OrdinateOrientation::TopToBottom => y + character.yoffset,
                };
                let screen_rect = Rect {
                    x: screen_x,
                    y: screen_y,
                    width: character.width,
                    height: character.height,
                };
                let char_position = CharPosition {
                    page_rect,
                    screen_rect,
                    page_index: character.page_index,
                };
                char_positions.push(char_position);
                x += character.xadvance + kerning_value;
                kerning_values = self.find_kerning_values(character.id);
            }
            match self.ordinate_orientation {
                OrdinateOrientation::TopToBottom => y += self.line_height as i32,
                OrdinateOrientation::BottomToTop => y -= self.line_height as i32,
            }
        }

        #[cfg(feature = "parse-error")]
        {
            Ok(char_positions)
        }

        #[cfg(not(feature = "parse-error"))]
        {
            char_positions
        }
    }

    fn find_kerning_values(&self, first_char_id: u32) -> KerningIter {
        let needle = (first_char_id << 1) - 1;
        let idx = self
            .kerning_values
            .binary_search_by(|probe| (probe.first_char_id << 1).cmp(&needle))
            .unwrap_err();

        KerningIter {
            first_char_id,
            idx,
            values: &self.kerning_values,
        }
    }

    fn parse_lines(&self, s: &str) -> ParseLines {
        let mut lines = Vec::new();
        let mut line = Vec::new();
        let mut temp = [0u16; 2];

        #[cfg(feature = "parse-error")]
        {
            let mut missing_characters: Option<Vec<char>> = None;
            let mut unsupported_characters: Option<Vec<char>> = None;

            for c in s.chars() {
                if c.len_utf16() != 1 {
                    if let Some(vec) = unsupported_characters.as_mut() {
                        vec.push(c);
                    } else {
                        unsupported_characters = Some(vec![c]);
                    }

                    continue;
                }

                c.encode_utf16(&mut temp);
                let char_id = temp[0] as u32;

                if self
                    .characters
                    .binary_search_by(|probe| probe.id.cmp(&char_id))
                    .is_ok()
                {
                    continue;
                }

                if let Some(vec) = missing_characters.as_mut() {
                    vec.push(c);
                } else {
                    missing_characters = Some(vec![c]);
                }
            }

            if missing_characters.is_some() || unsupported_characters.is_some() {
                return Err(StringParseError {
                    missing_characters: missing_characters.unwrap_or_default(),
                    unsupported_characters: unsupported_characters.unwrap_or_default(),
                });
            }
        }

        for c in s.chars() {
            #[cfg(not(feature = "parse-error"))]
            if c.len_utf16() != 1 {
                continue;
            }

            if c == '\n' {
                lines.push(line);
                line = Vec::new();
                continue;
            }

            c.encode_utf16(&mut temp);
            let char_id = temp[0] as u32;

            let char_idx = self
                .characters
                .binary_search_by(|probe| probe.id.cmp(&char_id));

            #[cfg(not(feature = "parse-error"))]
            if char_idx.is_err() {
                continue;
            }

            let char_idx = char_idx.unwrap();
            line.push(&self.characters[char_idx]);
        }

        if !line.is_empty() {
            lines.push(line);
        }

        #[cfg(feature = "parse-error")]
        {
            Ok(lines)
        }

        #[cfg(not(feature = "parse-error"))]
        lines
    }
}

struct KerningIter<'a> {
    first_char_id: u32,
    idx: usize,
    values: &'a Vec<KerningValue>,
}

impl<'a> KerningIter<'a> {
    fn empty(values: &'a Vec<KerningValue>) -> Self {
        Self {
            first_char_id: 0,
            idx: values.len(),
            values,
        }
    }
}

impl<'a> Iterator for KerningIter<'a> {
    type Item = &'a KerningValue;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(value) = self.values.get(self.idx) {
            if value.first_char_id == self.first_char_id {
                self.idx += 1;

                return Some(value);
            }
        }
        None
    }
}

#[derive(Clone, Debug)]
pub struct PageIter<'a> {
    idx: usize,
    pages: &'a Vec<Page>,
}

impl<'a> PageIter<'a> {
    fn new(pages: &'a Vec<Page>) -> Self {
        Self { idx: 0, pages }
    }
}

impl<'a> Iterator for PageIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(page) = self.pages.get(self.idx) {
            self.idx += 1;
            Some(page.file.as_str())
        } else {
            None
        }
    }
}
<commit_msg>Internal performance improvements, no api change (more!)<commit_after>//! Parser for bitmap fonts

mod char;
mod config_parse_error;
mod error;
mod kerning_value;
mod page;
mod rect;
mod sections;
mod string_parse_error;
mod utils;

pub use self::config_parse_error::ConfigParseError;
pub use self::error::Error;
pub use self::rect::Rect;
pub use self::string_parse_error::StringParseError;

use self::char::Char;
use self::kerning_value::KerningValue;
use self::page::Page;
use self::sections::Sections;
use std::io::Read;
use std::iter::Peekable;
use std::str::Chars;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _with_ the `parse-error` feature.
#[cfg(feature = "parse-error")]
pub type Parse<'a> = Result<Vec<CharPosition>, StringParseError>;

/// Alias of either [`Result<Vec<CharPosition>, StringParseError>`] _or_ [`Vec<CharPosition>`],
/// returned by [`BMFont::parse()`].
///
/// The output type depends on the value of the `parse-error` package feature.
///
/// **_NOTE:_** This documentation was generated _without_ the `parse-error` feature.
#[cfg(not(feature = "parse-error"))]
pub type Parse<'a> = Vec<CharPosition>;

#[cfg(feature = "parse-error")]
type ParseLines<'a> = Result<LineIter<'a>, StringParseError>;

#[cfg(not(feature = "parse-error"))]
type ParseLines<'a> = LineIter<'a>;

#[derive(Clone, Debug)]
pub struct CharPosition {
    pub page_rect: Rect,
    pub screen_rect: Rect,
    pub page_index: u32,
}

#[derive(Clone, Debug)]
pub enum OrdinateOrientation {
    BottomToTop,
    TopToBottom,
}

/// Holds a decoded bitmap font defintion, including all character advance and kerning values.
#[derive(Clone, Debug)]
pub struct BMFont {
    base_height: u32,
    line_height: u32,
    characters: Vec<Char>,
    kerning_values: Vec<KerningValue>,
    pages: Vec<Page>,
    ordinate_orientation: OrdinateOrientation,
}

impl BMFont {
    /// Constructs a new [BMFont].
    ///
    /// ## Examples
    ///
    /// From a file:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    ///
    /// From a slice of bytes:
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// # let my_font_bytes = std::fs::read("font.fnt")?;
    /// let data = std::io::Cursor::new(my_font_bytes);
    /// let font = BMFont::new(data, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.line_height(), 80);
    /// #     Ok(())
    /// # }
    /// ```
    pub fn new<R>(source: R, ordinate_orientation: OrdinateOrientation) -> Result<BMFont, Error>
    where
        R: Read,
    {
        let sections = Sections::new(source)?;

        let base_height;
        let line_height;
        {
            let mut components = sections.common_section.split_whitespace();
            components.next();
            line_height =
                utils::extract_component_value(components.next(), "common", "lineHeight")?;
            base_height = utils::extract_component_value(components.next(), "common", "base")?;
        }

        let mut pages = Vec::with_capacity(sections.page_sections.len());
        for page_section in &sections.page_sections {
            pages.push(Page::new(page_section)?);
        }

        // Sort the characters while loading them so that lookup can be faster during parse
        let mut characters: Vec<Char> = Vec::with_capacity(sections.char_sections.len());
        for char_section in &sections.char_sections {
            let char = Char::new(char_section)?;
            if let Err(idx) = characters.binary_search_by(|probe| probe.id.cmp(&char.id)) {
                characters.insert(idx, char);
            }
        }

        // Also sort kerning values for the same reason, but we allow duplicates
        let mut kerning_values: Vec<KerningValue> =
            Vec::with_capacity(sections.kerning_sections.len());
        for kerning_section in &sections.kerning_sections {
            let kerning = KerningValue::new(kerning_section)?;

            match kerning_values
                .binary_search_by(|probe| probe.first_char_id.cmp(&kerning.first_char_id))
            {
                Err(idx) | Ok(idx) => kerning_values.insert(idx, kerning),
            }
        }

        Ok(BMFont {
            base_height,
            line_height,
            characters,
            kerning_values,
            pages,
            ordinate_orientation,
        })
    }

    /// Returns the height of a `EM` in pixels.
    pub fn base_height(&self) -> u32 {
        self.base_height
    }

    pub fn line_height(&self) -> u32 {
        self.line_height
    }

    /// Returns an `Iterator` of font page bitmap filenames.
    ///
    /// ## Examples
    ///
    /// ```rust
    /// # use bmfont::*;
    /// # fn main() -> Result<(), Error> {
    /// let file = std::fs::File::open("font.fnt")?;
    /// let font = BMFont::new(file, OrdinateOrientation::TopToBottom)?;
    /// assert_eq!(font.pages().next(), Some("font.png"));
    /// #     Ok(())
    /// # }
    /// ```
    pub fn pages(&self) -> PageIter {
        PageIter::new(&self.pages)
    }

    pub fn parse(&self, s: &str) -> Parse {
        let lines = self.parse_lines(s);

        #[cfg(feature = "parse-error")]
        let lines = lines?;

        let mut char_positions = Vec::new();
        let mut y: i32 = 0;
        for line in lines {
            let mut x: i32 = 0;
            let mut kerning_values = KerningIter::empty(&self.kerning_values);
            for character in line {
                let kerning_value = kerning_values
                    .into_iter()
                    .find(|k| k.second_char_id == character.id)
                    .map(|k| k.value)
                    .unwrap_or(0);
                let page_rect = Rect {
                    x: character.x as i32,
                    y: character.y as i32,
                    width: character.width,
                    height: character.height,
                };
                let screen_x = x + character.xoffset + kerning_value;
                let screen_y = match self.ordinate_orientation {
                    OrdinateOrientation::BottomToTop => {
                        y + self.base_height as i32 - character.yoffset - character.height as i32
                    }
                    OrdinateOrientation::TopToBottom => y + character.yoffset,
                };
                let screen_rect = Rect {
                    x: screen_x,
                    y: screen_y,
                    width: character.width,
                    height: character.height,
                };
                let char_position = CharPosition {
                    page_rect,
                    screen_rect,
                    page_index: character.page_index,
                };
                char_positions.push(char_position);
                x += character.xadvance + kerning_value;
                kerning_values = self.find_kerning_values(character.id);
            }
            match self.ordinate_orientation {
                OrdinateOrientation::TopToBottom => y += self.line_height as i32,
                OrdinateOrientation::BottomToTop => y -= self.line_height as i32,
            }
        }

        #[cfg(feature = "parse-error")]
        {
            Ok(char_positions)
        }

        #[cfg(not(feature = "parse-error"))]
        {
            char_positions
        }
    }

    fn find_kerning_values(&self, first_char_id: u32) -> KerningIter {
        let needle = (first_char_id << 1) - 1;
        let idx = self
            .kerning_values
            .binary_search_by(|probe| (probe.first_char_id << 1).cmp(&needle))
            .unwrap_err();

        KerningIter {
            first_char_id,
            idx,
            values: &self.kerning_values,
        }
    }

    fn parse_lines<'a>(&'a self, s: &'a str) -> ParseLines<'a> {
        let mut temp = [0u16; 2];

        #[cfg(feature = "parse-error")]
        {
            let mut missing_characters: Option<Vec<char>> = None;
            let mut unsupported_characters: Option<Vec<char>> = None;

            for c in s.chars() {
                if c.len_utf16() != 1 {
                    if let Some(vec) = unsupported_characters.as_mut() {
                        vec.push(c);
                    } else {
                        unsupported_characters = Some(vec![c]);
                    }

                    continue;
                }

                c.encode_utf16(&mut temp);
                let char_id = temp[0] as u32;

                if self
                    .characters
                    .binary_search_by(|probe| probe.id.cmp(&char_id))
                    .is_ok()
                {
                    continue;
                }

                if let Some(vec) = missing_characters.as_mut() {
                    vec.push(c);
                } else {
                    missing_characters = Some(vec![c]);
                }
            }

            if missing_characters.is_some() || unsupported_characters.is_some() {
                return Err(StringParseError {
                    missing_characters: missing_characters.unwrap_or_default(),
                    unsupported_characters: unsupported_characters.unwrap_or_default(),
                });
            }
        }

        let lines = LineIter {
            characters: &self.characters,
            text: s.chars().peekable(),
        };

        #[cfg(feature = "parse-error")]
        {
            Ok(lines)
        }

        #[cfg(not(feature = "parse-error"))]
        lines
    }
}

struct CharIter<'a>(*mut LineIter<'a>);

impl<'a> Iterator for CharIter<'a> {
    type Item = &'a Char;

    fn next(&mut self) -> Option<Self::Item> {
        let lines = unsafe { self.0.as_mut().unwrap() };

        loop {
            return match lines.text.peek() {
                None => None,
                Some('\n') => None,
                Some(chr) if chr.len_utf16() != 1 => {
                    lines.text.next().unwrap_or_default();

                    continue;
                }
                Some(chr) => {
                    let mut temp = [0u16; 2];
                    chr.encode_utf16(&mut temp);
                    let char_id = temp[0] as u32;
                    let char_idx = lines
                        .characters
                        .binary_search_by(|probe| probe.id.cmp(&char_id));

                    lines.text.next().unwrap_or_default();

                    #[cfg(not(feature = "parse-error"))]
                    if char_idx.is_err() {
                        continue;
                    }

                    let char_idx = char_idx.unwrap();
                    Some(&lines.characters[char_idx])
                }
            };
        }
    }
}

struct KerningIter<'a> {
    first_char_id: u32,
    idx: usize,
    values: &'a Vec<KerningValue>,
}

impl<'a> KerningIter<'a> {
    fn empty(values: &'a Vec<KerningValue>) -> Self {
        Self {
            first_char_id: 0,
            idx: values.len(),
            values,
        }
    }
}

impl<'a> Iterator for KerningIter<'a> {
    type Item = &'a KerningValue;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(value) = self.values.get(self.idx) {
            if value.first_char_id == self.first_char_id {
                self.idx += 1;

                return Some(value);
            }
        }
        None
    }
}

struct LineIter<'a> {
    characters: &'a Vec<Char>,
    text: Peekable<Chars<'a>>,
}

impl<'a> Iterator for LineIter<'a> {
    type Item = CharIter<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.text.peek() {
            Some(_) => Some(CharIter(self)),
            _ => None,
        }

        // if let Some(value) = self.values.get(self.idx) {
        //     if value.first_char_id == self.first_char_id {
        //         self.idx += 1;

        //         return Some(value);
        //     }
        // }
    }
}

#[derive(Clone, Debug)]
pub struct PageIter<'a> {
    idx: usize,
    pages: &'a Vec<Page>,
}

impl<'a> PageIter<'a> {
    fn new(pages: &'a Vec<Page>) -> Self {
        Self { idx: 0, pages }
    }
}

impl<'a> Iterator for PageIter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(page) = self.pages.get(self.idx) {
            self.idx += 1;
            Some(page.file.as_str())
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>//! [![logo](http://i.imgur.com/dnpEXyh.jpg)](http://i.imgur.com/RUEw8EW.png)
//!
//! bspline
//! ===
//! A library for computing B-spline interpolating curves on generic control points. bspline can
//! be used to evaluate B-splines of varying orders on any type that can be linearly interpolated,
//! ranging from floats, positions, RGB colors to transformation matrices and so on.
//!
//! The bspline logo was generated using this library with a cubic B-spline in 2D for the positioning
//! of the curve and a quadratic B-spline in RGB space to color it (check out the
//! [logo](https://github.com/Twinklebear/bspline/blob/master/examples/logo.rs) example!). Other
//! much simpler examples of 1D and 2D quadratic, cubic and quartic B-splines can also be found in
//! the [examples](https://github.com/Twinklebear/bspline/tree/master/examples).
//!
//! # 1D Example
//!
//! This example shows how to create the 1D cardinal cubic B-spline example shown on [Wikipedia's
//! B-splines page](https://en.wikipedia.org/wiki/B-spline). For examples of evaluating the spline
//! to an image and saving the output see the [examples](https://github.com/Twinklebear/bspline/tree/master/examples).
//!
//! ```rust
//! let points = vec![0.0, 0.0, 0.0, 6.0, 0.0, 0.0, 0.0];
//! let knots = vec![-2.0, -2.0, -2.0, -2.0, -1.0, 0.0, 1.0, 2.0, 2.0, 2.0, 2.0];
//! let degree = 3;
//! let spline = bspline::BSpline::new(degree, points, knots);
//! ```
//!
//! # Readings on B-splines
//!
//! The library assumes you are familiar at some level with how B-splines work, e.g. how
//! control points and knots and effect the curve produced. No interactive
//! editor is provided (at least currently). Some good places to start reading about B-splines to
//! effectively use this library can be found below.
//!
//! - [Wikipedia page on B-splines](https://en.wikipedia.org/wiki/B-spline)
//! - [Fundamentals of Computer Graphics](http://www.amazon.com/Fundamentals-Computer-Graphics-Peter-Shirley/dp/1568814690)
//! (has a good chapter on curves)
//! - [Splines and B-splines: An Introduction](http://www.uio.no/studier/emner/matnat/ifi/INF-MAT5340/v07/undervisningsmateriale/kap1.pdf)
//! - [Geometric Modeling](http://atrey.karlin.mff.cuni.cz/projekty/vrr/doc/grafika/geometric%20modelling.pdf)
//! - [A nice set of interactive examples](https://www.ibiblio.org/e-notes/Splines/Intro.htm)
//!

use std::ops::{Mul, Add};
use std::fmt::Debug;
use std::slice::Iter;

/// The interpolate trait is used to linearly interpolate between two types (or in the
/// case of Quaternions, spherically linearly interpolate). The B-spline curve uses this
/// trait to compute points on the curve for the given parameter value.
///
/// A default implementation of this trait is provided for all `T` that are `Mul<f32, Output = T>
/// + Add<Output = T> + Copy` since the interpolation provided by the trait is expected to be
/// a simple linear interpolation.
pub trait Interpolate {
    /// Linearly interpolate between `self` and `other` using `t`, for example with floats:
    ///
    /// ```text
    /// self * (1.0 - t) + other * t
    /// ```
    ///
    /// If the result returned is not a correct linear interpolation of the values the
    /// curve produced using the value may not be correct.
    fn interpolate(&self, other: &Self, t: f32) -> Self;
}

impl<T: Mul<f32, Output = T> + Add<Output = T> + Copy> Interpolate for T {
    fn interpolate(&self, other: &Self, t: f32) -> Self {
        *self * (1.0 - t) + *other * t
    }
}

/// Represents a B-spline that will use polynomials of the specified degree to interpolate
/// between the control points given the knots.
pub struct BSpline<T: Interpolate + Copy + Debug> {
    /// Degree of the polynomial that we use to make the curve segments
    degree: usize,
    /// Control points for the curve
    control_points: Vec<T>,
    /// The knot vector
    knots: Vec<f32>,
}

impl<T: Interpolate + Copy + Debug> BSpline<T> {
    /// Create a new B-spline curve of the desired `degree` that will interpolate
    /// the `control_points` using the `knots`. The knots should be sorted in non-decreasing
    /// order, otherwise they will be sorted for you which may lead to undesired knots
    /// for control points. Note that this is in terms of the interpolating polynomial degree,
    /// if you are familiar with the convention of "B-spline curve order" the degree is `curve_order - 1`.
    ///
    /// Your curve must have a valid number of control points and knots or the function will panic. A B-spline
    /// curve requires at least as many control points as the degree (`control_points.len() >=
    /// degree`) and the number of knots should be equal to `control_points.len() + degree + 1`.
    pub fn new(degree: usize, control_points: Vec<T>, mut knots: Vec<f32>) -> BSpline<T> {
        if control_points.len() < degree {
            panic!("Too few control points for curve");
        }
        if knots.len() != control_points.len() + degree + 1 {
            panic!(format!("Invalid number of knots, got {}, expected {}", knots.len(),
                control_points.len() + degree + 1));
        }
        knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
        BSpline { degree: degree, control_points: control_points, knots: knots }
    }
    /// Compute a point on the curve at `t`, the parameter **must** be in the inclusive range
    /// of values returned by `knot_domain`. If `t` is out of bounds this function will assert
    /// on debug builds and on release builds you'll likely get an out of bounds crash.
    pub fn point(&self, t: f32) -> T {
        debug_assert!(t >= self.knot_domain().0 && t <= self.knot_domain().1);
        // Find the first index with a knot value greater than the t we're searching for. We want
        // to find i such that: knot[i] <= t < knot[i + 1]
        let i = match upper_bounds(&self.knots[..], t) {
            Some(x) if x == 0 => self.degree,
            Some(x) => x,
            None => self.knots.len() - self.degree - 1,
        };
        self.de_boor_iterative(t, i)
    }
    /// Get an iterator over the control points.
    pub fn control_points(&self) -> Iter<T> {
        self.control_points.iter()
    }
    /// Get an iterator over the knots.
    pub fn knots(&self) -> Iter<f32> {
        self.knots.iter()
    }
    /// Get the min and max knot domain values for finding the `t` range to compute
    /// the curve over. The curve is only defined over this (inclusive) range, passing
    /// a `t` value out of this range will assert on debug builds and likely result in
    /// a crash on release builds.
    pub fn knot_domain(&self) -> (f32, f32) {
        (self.knots[self.degree], self.knots[self.knots.len() - 1 - self.degree])
    }
    /// Iteratively compute de Boor's B-spline algorithm, this computes the recursive
    /// de Boor algorithm tree from the bottom up. At each level we use the results
    /// from the previous one to compute this level and store the results in the
    /// array indices we no longer need to compute the current level (the left one
    /// used computing node j).
    fn de_boor_iterative(&self, t: f32, i_start: usize) -> T {
        let mut tmp = Vec::with_capacity(self.degree + 1);
        for j in 0..self.degree + 1 {
            let p = j + i_start - self.degree - 1;
            tmp.push(self.control_points[p]);
        }
        for lvl in 0..self.degree {
            let k = lvl + 1;
            for j in 0..self.degree - lvl {
                let i = j + k + i_start - self.degree;
                let alpha = (t - self.knots[i - 1]) / (self.knots[i + self.degree - k] - self.knots[i - 1]);
                tmp[j] = tmp[j].interpolate(&tmp[j + 1], alpha);
            }
        }
        tmp[0]
    }
}

/// Return the index of the first element greater than the value passed.
/// The data **must** be sorted.
/// If no element greater than the value passed is found the function returns None.
fn upper_bounds(data: &[f32], value: f32) -> Option<usize> {
    let mut first = 0usize;
    let mut step;
    let mut count = data.len() as isize;
    while count > 0 {
        step = count / 2;
        let it = first + step as usize;
        if !value.lt(&data[it]) {
            first = it + 1;
            count -= step + 1;
        } else {
            count = step;
        }
    }
    // If we didn't find an element greater than value
    if first == data.len() {
        None
    } else {
        Some(first)
    }
}

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

    /// Check that the bspline returns the values we expect it to at various t values
    fn check_bspline(spline: &BSpline<f32>, expect: &Vec<(f32, f32)>) -> bool {
        expect.iter().fold(true, |ac, &(t, x)| ac && spline.point(t) == x)
    }

    #[test]
    fn linear_bspline() {
        let expect = vec![(0.0, 0.0), (0.2, 0.2), (0.4, 0.4), (0.6, 0.6),
                          (0.8, 0.8), (1.0, 1.0)];
        let points = vec![0.0, 1.0];
        let knots = vec![0.0, 0.0, 1.0, 1.0];
        let degree = 1;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn quadratic_bspline() {
        let expect = vec![(0.0, 0.0), (0.5, 0.125), (1.0, 0.5), (1.4, 0.74), (1.5, 0.75),
                          (1.6, 0.74), (2.0, 0.5), (2.5, 0.125), (3.0, 0.0)];
        let points = vec![0.0, 0.0, 1.0, 0.0, 0.0];
        let knots = vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0];
        let degree = 2;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn cubic_bspline() {
        let expect = vec![(-2.0, 0.0), (-1.5, 0.125), (-1.0, 1.0), (-0.6, 2.488),
                           (0.0, 4.0), (0.5, 2.875), (1.5, 0.12500001), (2.0, 0.0)];
        let points = vec![0.0, 0.0, 0.0, 6.0, 0.0, 0.0, 0.0];
        let knots = vec![-2.0, -2.0, -2.0, -2.0, -1.0, 0.0, 1.0, 2.0, 2.0, 2.0, 2.0];
        let degree = 3;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn quartic_bspline() {
        let expect = vec![(0.0, 0.0), (0.4, 0.0010666668), (1.0, 0.041666668),
                          (1.5, 0.19791667), (2.0, 0.4583333), (2.5, 0.5989583),
                          (3.0, 0.4583333), (3.2, 0.35206667), (4.1, 0.02733751),
                          (4.5, 0.002604167), (5.0, 0.0)];
        let points = vec![0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0];
        let knots = vec![0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0, 5.0];
        let degree = 4;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
}

<commit_msg>Debug trait is not required<commit_after>//! [![logo](http://i.imgur.com/dnpEXyh.jpg)](http://i.imgur.com/RUEw8EW.png)
//!
//! bspline
//! ===
//! A library for computing B-spline interpolating curves on generic control points. bspline can
//! be used to evaluate B-splines of varying orders on any type that can be linearly interpolated,
//! ranging from floats, positions, RGB colors to transformation matrices and so on.
//!
//! The bspline logo was generated using this library with a cubic B-spline in 2D for the positioning
//! of the curve and a quadratic B-spline in RGB space to color it (check out the
//! [logo](https://github.com/Twinklebear/bspline/blob/master/examples/logo.rs) example!). Other
//! much simpler examples of 1D and 2D quadratic, cubic and quartic B-splines can also be found in
//! the [examples](https://github.com/Twinklebear/bspline/tree/master/examples).
//!
//! # 1D Example
//!
//! This example shows how to create the 1D cardinal cubic B-spline example shown on [Wikipedia's
//! B-splines page](https://en.wikipedia.org/wiki/B-spline). For examples of evaluating the spline
//! to an image and saving the output see the [examples](https://github.com/Twinklebear/bspline/tree/master/examples).
//!
//! ```rust
//! let points = vec![0.0, 0.0, 0.0, 6.0, 0.0, 0.0, 0.0];
//! let knots = vec![-2.0, -2.0, -2.0, -2.0, -1.0, 0.0, 1.0, 2.0, 2.0, 2.0, 2.0];
//! let degree = 3;
//! let spline = bspline::BSpline::new(degree, points, knots);
//! ```
//!
//! # Readings on B-splines
//!
//! The library assumes you are familiar at some level with how B-splines work, e.g. how
//! control points and knots and effect the curve produced. No interactive
//! editor is provided (at least currently). Some good places to start reading about B-splines to
//! effectively use this library can be found below.
//!
//! - [Wikipedia page on B-splines](https://en.wikipedia.org/wiki/B-spline)
//! - [Fundamentals of Computer Graphics](http://www.amazon.com/Fundamentals-Computer-Graphics-Peter-Shirley/dp/1568814690)
//! (has a good chapter on curves)
//! - [Splines and B-splines: An Introduction](http://www.uio.no/studier/emner/matnat/ifi/INF-MAT5340/v07/undervisningsmateriale/kap1.pdf)
//! - [Geometric Modeling](http://atrey.karlin.mff.cuni.cz/projekty/vrr/doc/grafika/geometric%20modelling.pdf)
//! - [A nice set of interactive examples](https://www.ibiblio.org/e-notes/Splines/Intro.htm)
//!

use std::ops::{Mul, Add};
use std::slice::Iter;

/// The interpolate trait is used to linearly interpolate between two types (or in the
/// case of Quaternions, spherically linearly interpolate). The B-spline curve uses this
/// trait to compute points on the curve for the given parameter value.
///
/// A default implementation of this trait is provided for all `T` that are `Mul<f32, Output = T>
/// + Add<Output = T> + Copy` since the interpolation provided by the trait is expected to be
/// a simple linear interpolation.
pub trait Interpolate {
    /// Linearly interpolate between `self` and `other` using `t`, for example with floats:
    ///
    /// ```text
    /// self * (1.0 - t) + other * t
    /// ```
    ///
    /// If the result returned is not a correct linear interpolation of the values the
    /// curve produced using the value may not be correct.
    fn interpolate(&self, other: &Self, t: f32) -> Self;
}

impl<T: Mul<f32, Output = T> + Add<Output = T> + Copy> Interpolate for T {
    fn interpolate(&self, other: &Self, t: f32) -> Self {
        *self * (1.0 - t) + *other * t
    }
}

/// Represents a B-spline that will use polynomials of the specified degree to interpolate
/// between the control points given the knots.
pub struct BSpline<T: Interpolate + Copy> {
    /// Degree of the polynomial that we use to make the curve segments
    degree: usize,
    /// Control points for the curve
    control_points: Vec<T>,
    /// The knot vector
    knots: Vec<f32>,
}

impl<T: Interpolate + Copy> BSpline<T> {
    /// Create a new B-spline curve of the desired `degree` that will interpolate
    /// the `control_points` using the `knots`. The knots should be sorted in non-decreasing
    /// order, otherwise they will be sorted for you which may lead to undesired knots
    /// for control points. Note that this is in terms of the interpolating polynomial degree,
    /// if you are familiar with the convention of "B-spline curve order" the degree is `curve_order - 1`.
    ///
    /// Your curve must have a valid number of control points and knots or the function will panic. A B-spline
    /// curve requires at least as many control points as the degree (`control_points.len() >=
    /// degree`) and the number of knots should be equal to `control_points.len() + degree + 1`.
    pub fn new(degree: usize, control_points: Vec<T>, mut knots: Vec<f32>) -> BSpline<T> {
        if control_points.len() < degree {
            panic!("Too few control points for curve");
        }
        if knots.len() != control_points.len() + degree + 1 {
            panic!(format!("Invalid number of knots, got {}, expected {}", knots.len(),
                control_points.len() + degree + 1));
        }
        knots.sort_by(|a, b| a.partial_cmp(b).unwrap());
        BSpline { degree: degree, control_points: control_points, knots: knots }
    }
    /// Compute a point on the curve at `t`, the parameter **must** be in the inclusive range
    /// of values returned by `knot_domain`. If `t` is out of bounds this function will assert
    /// on debug builds and on release builds you'll likely get an out of bounds crash.
    pub fn point(&self, t: f32) -> T {
        debug_assert!(t >= self.knot_domain().0 && t <= self.knot_domain().1);
        // Find the first index with a knot value greater than the t we're searching for. We want
        // to find i such that: knot[i] <= t < knot[i + 1]
        let i = match upper_bounds(&self.knots[..], t) {
            Some(x) if x == 0 => self.degree,
            Some(x) => x,
            None => self.knots.len() - self.degree - 1,
        };
        self.de_boor_iterative(t, i)
    }
    /// Get an iterator over the control points.
    pub fn control_points(&self) -> Iter<T> {
        self.control_points.iter()
    }
    /// Get an iterator over the knots.
    pub fn knots(&self) -> Iter<f32> {
        self.knots.iter()
    }
    /// Get the min and max knot domain values for finding the `t` range to compute
    /// the curve over. The curve is only defined over this (inclusive) range, passing
    /// a `t` value out of this range will assert on debug builds and likely result in
    /// a crash on release builds.
    pub fn knot_domain(&self) -> (f32, f32) {
        (self.knots[self.degree], self.knots[self.knots.len() - 1 - self.degree])
    }
    /// Iteratively compute de Boor's B-spline algorithm, this computes the recursive
    /// de Boor algorithm tree from the bottom up. At each level we use the results
    /// from the previous one to compute this level and store the results in the
    /// array indices we no longer need to compute the current level (the left one
    /// used computing node j).
    fn de_boor_iterative(&self, t: f32, i_start: usize) -> T {
        let mut tmp = Vec::with_capacity(self.degree + 1);
        for j in 0..self.degree + 1 {
            let p = j + i_start - self.degree - 1;
            tmp.push(self.control_points[p]);
        }
        for lvl in 0..self.degree {
            let k = lvl + 1;
            for j in 0..self.degree - lvl {
                let i = j + k + i_start - self.degree;
                let alpha = (t - self.knots[i - 1]) / (self.knots[i + self.degree - k] - self.knots[i - 1]);
                tmp[j] = tmp[j].interpolate(&tmp[j + 1], alpha);
            }
        }
        tmp[0]
    }
}

/// Return the index of the first element greater than the value passed.
/// The data **must** be sorted.
/// If no element greater than the value passed is found the function returns None.
fn upper_bounds(data: &[f32], value: f32) -> Option<usize> {
    let mut first = 0usize;
    let mut step;
    let mut count = data.len() as isize;
    while count > 0 {
        step = count / 2;
        let it = first + step as usize;
        if !value.lt(&data[it]) {
            first = it + 1;
            count -= step + 1;
        } else {
            count = step;
        }
    }
    // If we didn't find an element greater than value
    if first == data.len() {
        None
    } else {
        Some(first)
    }
}

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

    /// Check that the bspline returns the values we expect it to at various t values
    fn check_bspline(spline: &BSpline<f32>, expect: &Vec<(f32, f32)>) -> bool {
        expect.iter().fold(true, |ac, &(t, x)| ac && spline.point(t) == x)
    }

    #[test]
    fn linear_bspline() {
        let expect = vec![(0.0, 0.0), (0.2, 0.2), (0.4, 0.4), (0.6, 0.6),
                          (0.8, 0.8), (1.0, 1.0)];
        let points = vec![0.0, 1.0];
        let knots = vec![0.0, 0.0, 1.0, 1.0];
        let degree = 1;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn quadratic_bspline() {
        let expect = vec![(0.0, 0.0), (0.5, 0.125), (1.0, 0.5), (1.4, 0.74), (1.5, 0.75),
                          (1.6, 0.74), (2.0, 0.5), (2.5, 0.125), (3.0, 0.0)];
        let points = vec![0.0, 0.0, 1.0, 0.0, 0.0];
        let knots = vec![0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 3.0];
        let degree = 2;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn cubic_bspline() {
        let expect = vec![(-2.0, 0.0), (-1.5, 0.125), (-1.0, 1.0), (-0.6, 2.488),
                           (0.0, 4.0), (0.5, 2.875), (1.5, 0.12500001), (2.0, 0.0)];
        let points = vec![0.0, 0.0, 0.0, 6.0, 0.0, 0.0, 0.0];
        let knots = vec![-2.0, -2.0, -2.0, -2.0, -1.0, 0.0, 1.0, 2.0, 2.0, 2.0, 2.0];
        let degree = 3;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
    #[test]
    fn quartic_bspline() {
        let expect = vec![(0.0, 0.0), (0.4, 0.0010666668), (1.0, 0.041666668),
                          (1.5, 0.19791667), (2.0, 0.4583333), (2.5, 0.5989583),
                          (3.0, 0.4583333), (3.2, 0.35206667), (4.1, 0.02733751),
                          (4.5, 0.002604167), (5.0, 0.0)];
        let points = vec![0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0];
        let knots = vec![0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 5.0, 5.0, 5.0];
        let degree = 4;
        let spline = BSpline::new(degree, points, knots);
        assert!(check_bspline(&spline, &expect));
    }
}

<|endoftext|>


<commit_before>#![feature(core)]

#[cfg(test)] extern crate test;

pub use blake2b::Blake2b;
pub use blake2s::Blake2s;

mod blake2b;
mod blake2s;
#[cfg(test)] mod kat;
<commit_msg>fix warnings<commit_after>#![feature(core)]
#![cfg_attr(test, feature(test))]

#[cfg(test)] extern crate test;

pub use blake2b::Blake2b;
pub use blake2s::Blake2s;

mod blake2b;
mod blake2s;
#[cfg(test)] mod kat;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

sealed class Object
data class Entity(val identifier: Long): Object()
sealed class Literal: Object()
data class LangLiteral(val value: String, val langTag: String): Literal() {
init {
require(validLangTag(langTag)) {
"Invalid lang tag: $langTag"
}
}
}
data class StringLiteral(val value: String): Literal()
data class BooleanLiteral(val value: Boolean): Literal()
data class LongLiteral(val value: Long): Literal()
data class DoubleLiteral(val value: Double): Literal()

data class Predicate(val identifier: String) {
init {
require(validPredicate(identifier)) {
"Invalid Predicate: $identifier"
}
}
}

val a = Predicate("_a")
val default = Entity(0)

data class Statement(val subject: Entity, val predicate: Predicate, val `object`: Object, val context: Entity = default)

sealed class Range<T>(open val start: T, open val end: T)
data class LangLiteralRange(override val start: LangLiteral, override val end: LangLiteral): Range<LangLiteral>(start, end)
data class StringLiteralRange(override val start: String, override val end: String): Range<String>(start, end)
data class LongLiteralRange(override val start: Long, override val end: Long): Range<Long>(start, end)
data class DoubleLiteralRange(override val start: Double, override val end: Double): Range<Double>(start, end)

data class CollectionName(val name: String) {
init {
require(validPredicate(name)) {
"Invalid Collection Name: $name"
}
}
}

interface LigatureStore {
suspend fun readTx(): ReadTx
suspend fun writeTx(): WriteTx
suspend fun <T>compute(fn: suspend (ReadTx) -> T): T {
val readTx = this.readTx()
try {
return fn(readTx)
} finally {
if (readTx.isOpen()) {
readTx.cancel()
}
}
}

suspend fun write(fn: suspend (WriteTx) -> Unit) {
val writeTx = this.writeTx()
try {
return fn(writeTx)
} finally {
if (writeTx.isOpen()) {
writeTx.commit()
}
}
}

/**
 * Close connection with the Store.
 */
suspend fun close()

suspend fun isOpen(): Boolean
}

interface ReadTx {
/**
 * Returns a Flow of all existing collections.
 */
suspend fun collections(): Flow<CollectionName>

/**
 * Returns a Flow of all existing collections that start with the given prefix.
 */
suspend fun collections(prefix: CollectionName): Flow<CollectionName>

/**
 * Returns a Flow of all existing collections that are within the given range.
 * `from` is inclusive and `to` is exclusive.
 */
suspend fun collections(from: CollectionName, to: CollectionName): Flow<CollectionName>

/**
 * Accepts nothing but returns a Flow of all Statements in the Collection.
 */
suspend fun allStatements(collection: CollectionName): Flow<Statement>

/**
 * Is passed a pattern and returns a seq with all matching Statements.
 */
suspend fun matchStatements(collection: CollectionName, subject: Entity? = null, predicate: Predicate? = null, `object`: Object? = null, context: Entity? = null): Flow<Statement>

/**
 * Is passed a pattern and returns a seq with all matching Statements.
 */
suspend fun matchStatements(collection: CollectionName, subject: Entity? = null, predicate: Predicate? = null, range: Range<*>, context: Entity? = null): Flow<Statement>

/**
 * Cancels this transaction.
 */
suspend fun cancel()

suspend fun isOpen(): Boolean
}

interface WriteTx {
/**
 * Creates a collection with the given name or does nothing if the collection already exists.
 * Only useful for creating an empty collection.
 */
suspend fun createCollection(collection: CollectionName)

/**
 * Deletes the collection of the name given and does nothing if the collection doesn't exist.
 */
suspend fun deleteCollection(collection: CollectionName)

/**
 * Returns a new, unique to this collection identifier in the form _:NUMBER
 */
suspend fun newEntity(collection: CollectionName): Entity
suspend fun addStatement(collection: CollectionName, statement: Statement)
suspend fun removeStatement(collection: CollectionName, statement: Statement)

/**
 * Commits this transaction.
 */
suspend fun commit()

/**
 * Cancels this transaction.
 */
suspend fun cancel()

suspend fun isOpen(): Boolean
}

/**
 * Accepts a String representing an identifier and returns true or false depending on if it is valid.
 */
fun validPredicate(identifier: String): Boolean {
return "[a-zA-Z_][^\\s\\(\\)\\[\\]\\{\\}'\"`<>\\\\]*".toRegex().matches(identifier)
}

/**
 * Accepts a String representing a lang tag and returns true or false depending on if it is valid.
 */
fun validLangTag(langTag: String): Boolean {
return "[a-zA-Z]+(-[a-zA-Z0-9]+)*".toRegex().matches(langTag)
}

///////TESTS

class LigatureSpec : StringSpec({
"validIdentifier tests" {
validPredicate("") shouldBe false
validPredicate("http://localhost/people/7") shouldBe true
validPredicate("http://localhost(/people/7") shouldBe false
validPredicate("http://localhost /people/7") shouldBe false
validPredicate("hello") shouldBe true
validPredicate("_:") shouldBe true
validPredicate("_:valid") shouldBe true
validPredicate("_:1") shouldBe true
validPredicate("_:1344") shouldBe true
}

"validLangTag tests" {
validLangTag("") shouldBe false
validLangTag("en") shouldBe true
validLangTag("en-") shouldBe false
validLangTag("en-fr") shouldBe true
validLangTag("en-fr-") shouldBe false
validLangTag("en-fr-sp") shouldBe true
validLangTag("ennnenefnk-dkfjkjfl-dfakjelfkjalkf-fakjeflkajlkfj") shouldBe true
validLangTag("en-fr-ef ") shouldBe false
}
})
<commit_msg>starting to rewrite in Rust, #100<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

enum Object<'a> {
    Entity(u64),
    Literal(Literal<'a>)
}

enum Literal<'a> {
    LangLiteral(&'a str, LangTag<'a>)
    // data class LangLiteral(val value: String, val langTag: String): Literal() {
    // init {
    // require(validLangTag(langTag)) {
    // "Invalid lang tag: $langTag"
    // }
    // }
    // }
    // data class StringLiteral(val value: String): Literal()
    // data class BooleanLiteral(val value: Boolean): Literal()
    // data class LongLiteral(val value: Long): Literal()
    // data class DoubleLiteral(val value: Double): Literal()
}

struct LangTag<'a> {
    langTag: &'a str
}

struct Predicate<'a> {
    predicate: &'a str,

    // data class Predicate(val identifier: String) {
    // init {
    // require(validPredicate(identifier)) {
    // "Invalid Predicate: $identifier"
    // }
    // }
    // }

}

enum Range {
    // sealed class Range<T>(open val start: T, open val end: T)
    // data class LangLiteralRange(override val start: LangLiteral, override val end: LangLiteral): Range<LangLiteral>(start, end)
    // data class StringLiteralRange(override val start: String, override val end: String): Range<String>(start, end)
    // data class LongLiteralRange(override val start: Long, override val end: Long): Range<Long>(start, end)
    // data class DoubleLiteralRange(override val start: Double, override val end: Double): Range<Double>(start, end)
}

struct Statement<'a> {
    subject: Entity,
    predicate: Predicate<'a>,
    object: Object<'a>,
    context: Entity,
}

const a: Predicate = Predicate("_a");
const default: Entity = Object::Entity(0);

struct CollectionName<'a> {
    name: &'a str
// (val name: String) {
// init {
// require(validPredicate(name)) {
// "Invalid Collection Name: $name"
// }
// }
// }
}

trait LigatureStore {
    fn readTx() -> ReadTx;
    fn writeTx() -> WriteTx;
//     fn <T>compute(fun: suspend (ReadTx) -> T): T {
// val readTx = this.readTx()
// try {
// return fn(readTx)
// } finally {
// if (readTx.isOpen()) {
// readTx.cancel()
// }
// }
//}

// suspend fun write(fn: suspend (WriteTx) -> Unit) {
// val writeTx = this.writeTx()
// try {
// return fn(writeTx)
// } finally {
// if (writeTx.isOpen()) {
// writeTx.commit()
// }
// }
// }

    /**
     * Close connection with the Store.
     */
    fn close();

    fn isOpen() -> Boolean;
}

trait ReadTx {
    /**
     * Returns a Flow of all existing collections.
     */
    suspend fun collections(): Flow<CollectionName>

    /**
     * Returns a Flow of all existing collections that start with the given prefix.
     */
    suspend fun collections(prefix: CollectionName): Flow<CollectionName>

    /**
     * Returns a Flow of all existing collections that are within the given range.
     * `from` is inclusive and `to` is exclusive.
     */
    suspend fun collections(from: CollectionName, to: CollectionName): Flow<CollectionName>

    /**
     * Accepts nothing but returns a Flow of all Statements in the Collection.
     */
    suspend fun allStatements(collection: CollectionName): Flow<Statement>

    /**
     * Is passed a pattern and returns a seq with all matching Statements.
     */
    suspend fun matchStatements(collection: CollectionName, subject: Entity? = null, predicate: Predicate? = null, `object`: Object? = null, context: Entity? = null): Flow<Statement>

    /**
     * Is passed a pattern and returns a seq with all matching Statements.
     */
    suspend fun matchStatements(collection: CollectionName, subject: Entity? = null, predicate: Predicate? = null, range: Range<*>, context: Entity? = null): Flow<Statement>

    /**
     * Cancels this transaction.
     */
    suspend fun cancel()

    suspend fun isOpen(): Boolean
}

trait WriteTx {
    /**
     * Creates a collection with the given name or does nothing if the collection already exists.
     * Only useful for creating an empty collection.
     */
    suspend fun createCollection(collection: CollectionName)

    /**
     * Deletes the collection of the name given and does nothing if the collection doesn't exist.
     */
    suspend fun deleteCollection(collection: CollectionName)

    /**
     * Returns a new, unique to this collection identifier in the form _:NUMBER
     */
    suspend fun newEntity(collection: CollectionName): Entity
    suspend fun addStatement(collection: CollectionName, statement: Statement)
    suspend fun removeStatement(collection: CollectionName, statement: Statement)

    /**
     * Commits this transaction.
     */
    suspend fun commit()

    /**
     * Cancels this transaction.
     */
    suspend fun cancel()

    suspend fun isOpen(): Boolean
}

/**
 * Accepts a String representing an identifier and returns true or false depending on if it is valid.
 */
fun validPredicate(identifier: String): Boolean {
    return "[a-zA-Z_][^\\s\\(\\)\\[\\]\\{\\}'\"`<>\\\\]*".toRegex().matches(identifier)
}

/**
 * Accepts a String representing a lang tag and returns true or false depending on if it is valid.
 */
fun validLangTag(langTag: String): Boolean {
    return "[a-zA-Z]+(-[a-zA-Z0-9]+)*".toRegex().matches(langTag)
}

///////TESTS

class LigatureSpec : StringSpec({
"validIdentifier tests" {
validPredicate("") shouldBe false
validPredicate("http://localhost/people/7") shouldBe true
validPredicate("http://localhost(/people/7") shouldBe false
validPredicate("http://localhost /people/7") shouldBe false
validPredicate("hello") shouldBe true
validPredicate("_:") shouldBe true
validPredicate("_:valid") shouldBe true
validPredicate("_:1") shouldBe true
validPredicate("_:1344") shouldBe true
}

"validLangTag tests" {
validLangTag("") shouldBe false
validLangTag("en") shouldBe true
validLangTag("en-") shouldBe false
validLangTag("en-fr") shouldBe true
validLangTag("en-fr-") shouldBe false
validLangTag("en-fr-sp") shouldBe true
validLangTag("ennnenefnk-dkfjkjfl-dfakjelfkjalkf-fakjeflkajlkfj") shouldBe true
validLangTag("en-fr-ef ") shouldBe false
}
})
<|endoftext|>


<commit_before>//! A minimal implementation of SHA1 for rust.
//!
//! Example:
//!
//! ```rust
//! extern crate "sha1-hasher" as sha1;
//! use std::io::Write;
//!
//! # fn main() {
//!
//! let mut m = sha1::Sha1::new();
//! m.write("Hello World!".as_bytes());
//! assert_eq!(&*m.hexdigest(), "2ef7bde608ce5404e97d5f042f95f89f1c232871");
//! # }
//! ```

#![feature(collections)]
#![feature(core)]
#![feature(hash)]
#![feature(io)]

#![allow(unused_features)]
#![feature(test)]

#[cfg(test)] extern crate test;

use std::io::{Write, BufWriter};
use std::io::Result as IoResult;
use std::num::Int;
use std::num::wrapping::WrappingOps;
use std::default::Default;
use std::mem::transmute;
use std::iter::range;

/// Represents a Sha1 hash object in memory.
#[derive(Clone)]
pub struct Sha1 {
    state: [u32; 5],
    data: Vec<u8>,
    len: u64,
}

const DEFAULT_STATE : [u32; 5] =
    [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];

fn to_hex(input: &[u8]) -> String {
    let mut s = String::new();
    for b in input.iter() {
        s.push_str(&*format!("{:02x}", *b));
    }
    return s;
}

impl Default for Sha1 {
    #[inline]
    fn default() -> Sha1 {
        Sha1::new()
    }
}

impl Write for Sha1 {
    fn write(&mut self, bytes: &[u8]) -> IoResult<usize> {
        let mut d = self.data.clone();
        self.data.clear();

        d.push_all(bytes);

        for chunk in d[..].chunks(64) {
            if chunk.len() == 64 {
                self.len += 64;
                self.process_block(chunk);
            } else {
                self.data.push_all(chunk);
            }
        }

        Ok(bytes.len())
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl Sha1 {

    /// Creates an fresh sha1 hash object.
    pub fn new() -> Sha1 {
        Sha1 {
            state: DEFAULT_STATE,
            data: Vec::new(),
            len: 0,
        }
    }

    pub fn reset(&mut self) {
        self.state = DEFAULT_STATE;
        self.data.clear();
        self.len = 0;
    }

    pub fn finish(&self) -> Vec<u8> {
        let mut buf = [0u8; 20].to_vec();
        self.output(&mut *buf);
        buf
    }

    fn process_block(&mut self, block: &[u8]) {
        assert_eq!(block.len(), 64);

        let mut words = [0u32; 80];
        for (i, chunk) in block.chunks(4).enumerate() {
            words[i] = (chunk[3] as u32) |
                       ((chunk[2] as u32) << 8) |
                       ((chunk[1] as u32) << 16) |
                       ((chunk[0] as u32) << 24);
        }

        fn ff(b: u32, c: u32, d: u32) -> u32 { d ^ (b & (c ^ d)) }
        fn gg(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }
        fn hh(b: u32, c: u32, d: u32) -> u32 { (b & c) | (d & (b | c)) }
        fn ii(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }

        for i in range(16, 80) {
            let n = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16];
            words[i] = n.rotate_left(1);
        }

        let mut a = self.state[0];
        let mut b = self.state[1];
        let mut c = self.state[2];
        let mut d = self.state[3];
        let mut e = self.state[4];

        for i in range(0, 80) {
            let (f, k) = match i {
                0 ... 19 => (ff(b, c, d), 0x5a827999),
                20 ... 39 => (gg(b, c, d), 0x6ed9eba1),
                40 ... 59 => (hh(b, c, d), 0x8f1bbcdc),
                60 ... 79 => (ii(b, c, d), 0xca62c1d6),
                _ => (0, 0),
            };

            let tmp = a.rotate_left(5)
                .wrapping_add(f)
                .wrapping_add(e)
                .wrapping_add(k)
                .wrapping_add(words[i]);

            e = d;
            d = c;
            c = b.rotate_left(30);
            b = a;
            a = tmp;
        }

        self.state[0] = self.state[0].wrapping_add(a);
        self.state[1] = self.state[1].wrapping_add(b);
        self.state[2] = self.state[2].wrapping_add(c);
        self.state[3] = self.state[3].wrapping_add(d);
        self.state[4] = self.state[4].wrapping_add(e);
    }

    /// Retrieve digest result.  The output must be large enough to
    /// contain result (20 bytes).
    pub fn output(&self, out: &mut [u8]) {
        // these are unlikely to fail, since we're writing to memory
        #![allow(unused_must_use)]

        let mut m = Sha1 {
            state: self.state,
            data: Vec::new(),
            len: 0,
        };

        let mut w = Vec::<u8>::with_capacity(137);
        w.push_all(&*self.data);
        w.push_all(&[0x80u8]);
        let padding = 64 - ((self.data.len() + 9) % 64);
        for _ in range(0, padding) {
            w.push(0u8);
        }
        w.push_all(unsafe { &transmute::<_, [u8; 8]>(((self.data.len() as u64 + self.len) * 8).to_be()) });
        for chunk in w[..].chunks(64) {
            m.process_block(chunk);
        }

        let mut w = BufWriter::new(out);
        for &n in m.state.iter() {
            w.write_all(unsafe { &transmute::<_, [u8; 4]>(n.to_be()) });
        }
    }

    pub fn hexdigest(&self) -> String {
        to_hex(&*self.finish())
    }
}

#[cfg(test)]
mod tests {
    use std::io::Write;
    use test::Bencher;
    use super::{Sha1, to_hex};

    #[test]
    fn test_simple() {
        let mut m = Sha1::new();

        let tests = [
            ("The quick brown fox jumps over the lazy dog",
            "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"),
            ("The quick brown fox jumps over the lazy cog",
            "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"),
            ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"),
            ("testing\n", "9801739daae44ec5293d4e1f53d3f4d2d426d91c"),
            ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "025ecbd5d70f8fb3c5457cd96bab13fda305dc59"),
        ];

        for &(s, ref h) in tests.iter() {
            let data = s.as_bytes();

            m.reset();
            m.write(data).unwrap();
            let hh = m.hexdigest();

            assert_eq!(hh.len(), h.len());
            assert_eq!(&*hh, *h);
        }
    }

    #[test]
    fn test_dirty_run() {
        let mut m = Sha1::new();

        m.write(b"123").unwrap();
        let out1 = m.finish();

        m.write_all(b"123").unwrap();
        let out2 = m.finish();

        assert!(out1 != out2);
        assert_eq!(&*to_hex(&*out1), "40bd001563085fc35165329ea1ff5c5ecbdbbeef");
        assert_eq!(&*to_hex(&*out2), "601f1889667efaebb33b8c12572835da3f027f78");
    }

    #[bench]
    fn test_sha1_speed(b: &mut Bencher) {
        let mut m = Sha1::new();
        let s = "The quick brown fox jumps over the lazy dog.";
        let n = 1000u64;

        b.bytes = n * s.len() as u64;
        b.iter(|| {
            m.reset();
            for _ in range(0, n) {
                m.write_all(s.as_bytes()).unwrap();
            }
            assert_eq!(m.hexdigest(), "7ca27655f67fceaa78ed2e645a81c7f1d6e249d2");
        });
    }
}
<commit_msg>use new range syntax<commit_after>//! A minimal implementation of SHA1 for rust.
//!
//! Example:
//!
//! ```rust
//! extern crate "sha1-hasher" as sha1;
//! use std::io::Write;
//!
//! # fn main() {
//!
//! let mut m = sha1::Sha1::new();
//! m.write("Hello World!".as_bytes());
//! assert_eq!(&*m.hexdigest(), "2ef7bde608ce5404e97d5f042f95f89f1c232871");
//! # }
//! ```

#![feature(collections)]
#![feature(core)]
#![feature(hash)]
#![feature(io)]

#![allow(unused_features)]
#![feature(test)]

#[cfg(test)] extern crate test;

use std::io::{Write, BufWriter};
use std::io::Result as IoResult;
use std::num::Int;
use std::num::wrapping::WrappingOps;
use std::default::Default;
use std::mem::transmute;

/// Represents a Sha1 hash object in memory.
#[derive(Clone)]
pub struct Sha1 {
    state: [u32; 5],
    data: Vec<u8>,
    len: u64,
}

const DEFAULT_STATE : [u32; 5] =
    [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];

fn to_hex(input: &[u8]) -> String {
    let mut s = String::new();
    for b in input.iter() {
        s.push_str(&*format!("{:02x}", *b));
    }
    return s;
}

impl Default for Sha1 {
    #[inline]
    fn default() -> Sha1 {
        Sha1::new()
    }
}

impl Write for Sha1 {
    fn write(&mut self, bytes: &[u8]) -> IoResult<usize> {
        let mut d = self.data.clone();
        self.data.clear();

        d.push_all(bytes);

        for chunk in d[..].chunks(64) {
            if chunk.len() == 64 {
                self.len += 64;
                self.process_block(chunk);
            } else {
                self.data.push_all(chunk);
            }
        }

        Ok(bytes.len())
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl Sha1 {

    /// Creates an fresh sha1 hash object.
    pub fn new() -> Sha1 {
        Sha1 {
            state: DEFAULT_STATE,
            data: Vec::new(),
            len: 0,
        }
    }

    pub fn reset(&mut self) {
        self.state = DEFAULT_STATE;
        self.data.clear();
        self.len = 0;
    }

    pub fn finish(&self) -> Vec<u8> {
        let mut buf = [0u8; 20].to_vec();
        self.output(&mut *buf);
        buf
    }

    fn process_block(&mut self, block: &[u8]) {
        assert_eq!(block.len(), 64);

        let mut words = [0u32; 80];
        for (i, chunk) in block.chunks(4).enumerate() {
            words[i] = (chunk[3] as u32) |
                       ((chunk[2] as u32) << 8) |
                       ((chunk[1] as u32) << 16) |
                       ((chunk[0] as u32) << 24);
        }

        fn ff(b: u32, c: u32, d: u32) -> u32 { d ^ (b & (c ^ d)) }
        fn gg(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }
        fn hh(b: u32, c: u32, d: u32) -> u32 { (b & c) | (d & (b | c)) }
        fn ii(b: u32, c: u32, d: u32) -> u32 { b ^ c ^ d }

        for i in (16..80) {
            let n = words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16];
            words[i] = n.rotate_left(1);
        }

        let mut a = self.state[0];
        let mut b = self.state[1];
        let mut c = self.state[2];
        let mut d = self.state[3];
        let mut e = self.state[4];

        for i in (0..80) {
            let (f, k) = match i {
                0 ... 19 => (ff(b, c, d), 0x5a827999),
                20 ... 39 => (gg(b, c, d), 0x6ed9eba1),
                40 ... 59 => (hh(b, c, d), 0x8f1bbcdc),
                60 ... 79 => (ii(b, c, d), 0xca62c1d6),
                _ => (0, 0),
            };

            let tmp = a.rotate_left(5)
                .wrapping_add(f)
                .wrapping_add(e)
                .wrapping_add(k)
                .wrapping_add(words[i]);

            e = d;
            d = c;
            c = b.rotate_left(30);
            b = a;
            a = tmp;
        }

        self.state[0] = self.state[0].wrapping_add(a);
        self.state[1] = self.state[1].wrapping_add(b);
        self.state[2] = self.state[2].wrapping_add(c);
        self.state[3] = self.state[3].wrapping_add(d);
        self.state[4] = self.state[4].wrapping_add(e);
    }

    /// Retrieve digest result.  The output must be large enough to
    /// contain result (20 bytes).
    pub fn output(&self, out: &mut [u8]) {
        // these are unlikely to fail, since we're writing to memory
        #![allow(unused_must_use)]

        let mut m = Sha1 {
            state: self.state,
            data: Vec::new(),
            len: 0,
        };

        let mut w = Vec::<u8>::with_capacity(137);
        w.push_all(&*self.data);
        w.push_all(&[0x80u8]);
        let padding = 64 - ((self.data.len() + 9) % 64);
        for _ in (0..padding) {
            w.push(0u8);
        }
        w.push_all(unsafe { &transmute::<_, [u8; 8]>(((self.data.len() as u64 + self.len) * 8).to_be()) });
        for chunk in w[..].chunks(64) {
            m.process_block(chunk);
        }

        let mut w = BufWriter::new(out);
        for &n in m.state.iter() {
            w.write_all(unsafe { &transmute::<_, [u8; 4]>(n.to_be()) });
        }
    }

    pub fn hexdigest(&self) -> String {
        to_hex(&*self.finish())
    }
}

#[cfg(test)]
mod tests {
    use std::io::Write;
    use test::Bencher;
    use super::{Sha1, to_hex};

    #[test]
    fn test_simple() {
        let mut m = Sha1::new();

        let tests = [
            ("The quick brown fox jumps over the lazy dog",
            "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"),
            ("The quick brown fox jumps over the lazy cog",
            "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"),
            ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709"),
            ("testing\n", "9801739daae44ec5293d4e1f53d3f4d2d426d91c"),
            ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "025ecbd5d70f8fb3c5457cd96bab13fda305dc59"),
        ];

        for &(s, ref h) in tests.iter() {
            let data = s.as_bytes();

            m.reset();
            m.write(data).unwrap();
            let hh = m.hexdigest();

            assert_eq!(hh.len(), h.len());
            assert_eq!(&*hh, *h);
        }
    }

    #[test]
    fn test_dirty_run() {
        let mut m = Sha1::new();

        m.write(b"123").unwrap();
        let out1 = m.finish();

        m.write_all(b"123").unwrap();
        let out2 = m.finish();

        assert!(out1 != out2);
        assert_eq!(&*to_hex(&*out1), "40bd001563085fc35165329ea1ff5c5ecbdbbeef");
        assert_eq!(&*to_hex(&*out2), "601f1889667efaebb33b8c12572835da3f027f78");
    }

    #[bench]
    fn test_sha1_speed(b: &mut Bencher) {
        let mut m = Sha1::new();
        let s = "The quick brown fox jumps over the lazy dog.";
        let n = 1000u64;

        b.bytes = n * s.len() as u64;
        b.iter(|| {
            m.reset();
            for _ in (0..n) {
                m.write_all(s.as_bytes()).unwrap();
            }
            assert_eq!(m.hexdigest(), "7ca27655f67fceaa78ed2e645a81c7f1d6e249d2");
        });
    }
}
<|endoftext|>


<commit_before>#![feature(core)]

use std::num::Float;
use std::collections::binary_heap::BinaryHeap; // pq
use std::cmp::Ordering;

pub type float = f64;
pub type time = u64; // in nano seconds

pub mod timestamp;

fn time_to_ms_float(t: time) -> float {
    (t as float) / 1_000_000.0 as float
}

fn ms_float_to_time(t: float) -> time {
    (t * 1_000_000.0) as time
}

pub fn ms(n: time) -> time { n * 1_000_000 }
pub fn us(n: time) -> time { n * 1000 }
pub fn ns(n: time) -> time { n }

#[derive(Debug, Copy)]
pub struct NeuronConfig {
    pub arp:       time,
    pub tau_m:     time,
    pub tau_r:     float,
    pub weight_r:  float,
    pub threshold: float,
    pub record:    Option<&'static str>,
}

#[derive(Debug, Copy)]
pub struct NeuronConfigId(usize);

#[derive(Debug, Copy)]
pub struct Neuron {
    /// End of absolute refractory period
    arp_end:         time,

    mem_pot:         float,
    mem_pot_last_update: time,

    /// An index into a [NeuronConfig] table.
    config_id:       NeuronConfigId,
}

#[derive(Debug, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct NeuronId(usize);

#[derive(Debug, Copy, PartialEq, Eq)]
pub enum NeuronResult {
    InArp,
    NoFire,
    Fire
}

fn calc_decay(duration: time, tau_m: time) -> float {
    (duration as f64 / tau_m as f64).exp()
}

impl Neuron {
    pub fn new(config_id: NeuronConfigId) -> Neuron {
        Neuron {
            arp_end: 0,
            mem_pot_last_update: ns(0),
            mem_pot: 0.0,
            config_id: config_id,
        }
    }

    // Calculates the current memory potential
    pub fn current_mem_pot(&self, timestamp: time, cfg: &NeuronConfig) -> float {
        assert!(timestamp >= self.mem_pot_last_update);
        if cfg.tau_m > 0 {
            let decay = calc_decay(timestamp - self.mem_pot_last_update, cfg.tau_m);
            self.mem_pot / decay
        }
        else {
            0.0
        }
    }

    pub fn spike(&mut self, timestamp: time, weight: float, cfg: &NeuronConfig) -> NeuronResult {
        assert!(timestamp >= self.mem_pot_last_update);

        // Return early if still in absolute refractory period (arp)
        if timestamp < self.arp_end {
            return NeuronResult::InArp;
        }

        // Time since end of last absolute refractory period (arp)
        assert!(timestamp >= self.arp_end);
        let delta = timestamp - self.arp_end;

        // Convert delta to float (ms)
        let delta = time_to_ms_float(delta);

        // Calculate dynamic threshold
        let dyn_threshold = cfg.threshold +
                            cfg.weight_r * (-delta / cfg.tau_r).exp();

        // Recalculate and update memory potential
        self.mem_pot = weight + self.current_mem_pot(timestamp, cfg);
        self.mem_pot_last_update = timestamp;

        if self.mem_pot >= dyn_threshold {
            self.arp_end = timestamp + cfg.arp;
            NeuronResult::Fire
        }
        else {
            NeuronResult::NoFire
        }
    }
}

macro_rules! assert_in_delta {
    ( $exp:expr, $act:expr, $delta:expr ) => {
        assert!( ($exp - $act).abs() < $delta )
    };
}

#[test]
fn test_decay()
{
    let decay = calc_decay(1, 1);
    assert_in_delta!(2.7182, decay, 0.01);

    let decay = calc_decay(100000000000, 144269504089);
    assert_in_delta!(2.0, decay, 0.01);
}

#[test]
fn test_neuron_firing()
{
    let mut neuron = Neuron::new(NeuronConfigId(0));
    let neuron_cfg = NeuronConfig {
        arp:       0,
        tau_m:     us(0),
        tau_r:     0.0,
        weight_r:  0.0,
        threshold: 1.0,
        record:    None,
    };

    assert_eq!(0, neuron.arp_end);
    assert_eq!(0, neuron.last_spike_time);
    assert_in_delta!(0.0, neuron.mem_pot, 0.0001);

    let res = neuron.spike(ms(1), 0.9, &neuron_cfg);
    assert_eq!(NeuronResult::NoFire, res);
}

#[derive(Debug)]
pub struct Event {
    time:   time,
    weight: float,
    target: NeuronId
}

impl PartialEq for Event {
    fn eq(&self, other: &Self) -> bool {
        self.time == other.time && self.target == other.target
    }
}

impl Eq for Event {}

impl PartialOrd for Event {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let res = if self.time < other.time {
            Ordering::Less
        }
        else if self.time > other.time {
            Ordering::Greater
        }
        else {
            debug_assert!(self.time == other.time);
            self.target.cmp(&other.target)
        };
        Some(res.reverse())
    }
}

impl Ord for Event {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[derive(Debug)]
pub struct Synapse {
    pub delay:  time,
    pub weight: float,
    pub post_neuron: NeuronId,
}

pub trait Recorder {
    fn record_fire(&mut self, timestamp: time, neuron_id: NeuronId);
}

pub struct Net<R:Recorder> {
    neurons: Vec<Neuron>,
    neuron_configs: Vec<NeuronConfig>,
    synapses: Vec<Vec<Synapse>>,
    events: BinaryHeap<Event>,
    recorder: Option<Box<R>>
}

impl<R:Recorder> Net<R> {
    pub fn new() -> Net<R> {
        Net {
            neurons: vec![],
            neuron_configs: vec![],
            synapses: vec![],
            events: BinaryHeap::new(),
            recorder: None,
        }
    }

    pub fn set_recorder(&mut self, opt_recorder: Option<Box<R>>) {
        self.recorder = opt_recorder;
    }

    pub fn get_recorder(&self) -> Option<&Box<R>> {
        self.recorder.as_ref()
    }

    pub fn create_neuron_config(&mut self, config: NeuronConfig) -> NeuronConfigId {
        self.neuron_configs.push(config);
        NeuronConfigId(self.neuron_configs.len() - 1)
    }

    pub fn create_neuron(&mut self, config_id: NeuronConfigId) -> NeuronId {
        self.neurons.push(Neuron::new(config_id));
        self.synapses.push(vec![]);
        NeuronId(self.neurons.len() - 1)
    }

    pub fn create_synapse(&mut self, from_neuron: NeuronId, synapse: Synapse) {
        let mut syn_arr = &mut (self.synapses.as_mut_slice())[from_neuron.0];
        syn_arr.push(synapse);
    }

    pub fn add_event(&mut self, event: Event) {
        self.events.push(event);
    }

    // values are in ms
    pub fn add_spike_train_float_ms(&mut self, target: NeuronId, weight: float, spikes: &[float]) {
        for &t in spikes {
            self.add_event(Event {
                time: ms_float_to_time(t),
                weight: weight,
                target: target
            });
        }
    }

    fn fire(&mut self, timestamp: time, neuron_id: NeuronId) {
        for syn in &self.synapses[neuron_id.0] {
            println!("{:?}", syn);
            self.events.push(Event {
                time: timestamp + syn.delay,
                weight: syn.weight,
                target: syn.post_neuron
            });
        }

        if let Some(ref mut recorder) = self.recorder {
            recorder.record_fire(timestamp, neuron_id);
        }

        if let Some(ident) = self.get_config_for_neuron_id(neuron_id).record {
            println!("RECORD\t{}\t{}\t{}", ident, neuron_id.0, timestamp);
        }
    }

    fn get_neuron(&self, neuron_id: NeuronId) -> &Neuron {
        &self.neurons[neuron_id.0]
    }

    fn get_config_for_neuron<'a>(&'a self, neuron: &Neuron) -> &'a NeuronConfig {
        &(self.neuron_configs.as_slice())[neuron.config_id.0]
    }

    fn get_config_for_neuron_id(&self, neuron_id: NeuronId) -> &NeuronConfig {
        self.get_config_for_neuron(self.get_neuron(neuron_id))
    }

    pub fn simulate(&mut self) {
	loop {
	    println!("-------------------------------------");

	    if let Some(mut ev) = self.events.pop() {

                // consume all elements with same timestamp and same target
                loop {
                    match self.events.peek() {
                        Some(ev2) if ev2.time == ev.time && ev2.target == ev.target => {
                            println!("consume additional event: {:?}", ev2);
                            ev.weight += ev2.weight;
                        }
                        _ => break
                    }
                    let _ = self.events.pop();
                }

		println!("{:?}", ev);
                let neuron_id = ev.target;
                let fire = {
		    let neuron = &mut (self.neurons.as_mut_slice())[neuron_id.0];
                    let cfg = &(self.neuron_configs.as_slice())[neuron.config_id.0];
		    let fire = neuron.spike(ev.time, ev.weight, cfg);
		    println!("{:?}", fire);
		    println!("{:?}", neuron);
                    fire
                };
                match fire {
                    NeuronResult::Fire => {
                        // Post a new event to all synapses
                        self.fire(ev.time, neuron_id);
                    }
                    _ => {
                    }
                }
	    }
	    else {
		break;
	    }
	}
    }
}
<commit_msg>Bring up-to-date with latest Rust<commit_after>#![feature(convert)]

use std::collections::binary_heap::BinaryHeap; // pq
use std::cmp::Ordering;

pub type float = f64;
pub type time = u64; // in nano seconds

pub mod timestamp;

fn time_to_ms_float(t: time) -> float {
    (t as float) / 1_000_000.0 as float
}

fn ms_float_to_time(t: float) -> time {
    (t * 1_000_000.0) as time
}

pub fn ms(n: time) -> time { n * 1_000_000 }
pub fn us(n: time) -> time { n * 1000 }
pub fn ns(n: time) -> time { n }

#[derive(Debug, Copy, Clone)]
pub struct NeuronConfig {
    pub arp:       time,
    pub tau_m:     time,
    pub tau_r:     float,
    pub weight_r:  float,
    pub threshold: float,
    pub record:    Option<&'static str>,
}

#[derive(Debug, Copy, Clone)]
pub struct NeuronConfigId(usize);

#[derive(Debug, Copy, Clone)]
pub struct Neuron {
    /// End of absolute refractory period
    arp_end:         time,

    mem_pot:         float,
    mem_pot_last_update: time,

    /// An index into a [NeuronConfig] table.
    config_id:       NeuronConfigId,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct NeuronId(usize);

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum NeuronResult {
    InArp,
    NoFire,
    Fire
}

fn calc_decay(duration: time, tau_m: time) -> float {
    (duration as f64 / tau_m as f64).exp()
}

impl Neuron {
    pub fn new(config_id: NeuronConfigId) -> Neuron {
        Neuron {
            arp_end: 0,
            mem_pot_last_update: ns(0),
            mem_pot: 0.0,
            config_id: config_id,
        }
    }

    // Calculates the current memory potential
    pub fn current_mem_pot(&self, timestamp: time, cfg: &NeuronConfig) -> float {
        assert!(timestamp >= self.mem_pot_last_update);
        if cfg.tau_m > 0 {
            let decay = calc_decay(timestamp - self.mem_pot_last_update, cfg.tau_m);
            self.mem_pot / decay
        }
        else {
            0.0
        }
    }

    pub fn spike(&mut self, timestamp: time, weight: float, cfg: &NeuronConfig) -> NeuronResult {
        assert!(timestamp >= self.mem_pot_last_update);

        // Return early if still in absolute refractory period (arp)
        if timestamp < self.arp_end {
            return NeuronResult::InArp;
        }

        // Time since end of last absolute refractory period (arp)
        assert!(timestamp >= self.arp_end);
        let delta = timestamp - self.arp_end;

        // Convert delta to float (ms)
        let delta = time_to_ms_float(delta);

        // Calculate dynamic threshold
        let dyn_threshold = cfg.threshold +
                            cfg.weight_r * (-delta / cfg.tau_r).exp();

        // Recalculate and update memory potential
        self.mem_pot = weight + self.current_mem_pot(timestamp, cfg);
        self.mem_pot_last_update = timestamp;

        if self.mem_pot >= dyn_threshold {
            self.arp_end = timestamp + cfg.arp;
            NeuronResult::Fire
        }
        else {
            NeuronResult::NoFire
        }
    }
}

macro_rules! assert_in_delta {
    ( $exp:expr, $act:expr, $delta:expr ) => {
        assert!( ($exp - $act).abs() < $delta )
    };
}

#[test]
fn test_decay()
{
    let decay = calc_decay(1, 1);
    assert_in_delta!(2.7182, decay, 0.01);

    let decay = calc_decay(100000000000, 144269504089);
    assert_in_delta!(2.0, decay, 0.01);
}

#[test]
fn test_neuron_firing()
{
    let mut neuron = Neuron::new(NeuronConfigId(0));
    let neuron_cfg = NeuronConfig {
        arp:       0,
        tau_m:     us(0),
        tau_r:     0.0,
        weight_r:  0.0,
        threshold: 1.0,
        record:    None,
    };

    assert_eq!(0, neuron.arp_end);
    assert_eq!(0, neuron.last_spike_time);
    assert_in_delta!(0.0, neuron.mem_pot, 0.0001);

    let res = neuron.spike(ms(1), 0.9, &neuron_cfg);
    assert_eq!(NeuronResult::NoFire, res);
}

#[derive(Debug)]
pub struct Event {
    time:   time,
    weight: float,
    target: NeuronId
}

impl PartialEq for Event {
    fn eq(&self, other: &Self) -> bool {
        self.time == other.time && self.target == other.target
    }
}

impl Eq for Event {}

impl PartialOrd for Event {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let res = if self.time < other.time {
            Ordering::Less
        }
        else if self.time > other.time {
            Ordering::Greater
        }
        else {
            debug_assert!(self.time == other.time);
            self.target.cmp(&other.target)
        };
        Some(res.reverse())
    }
}

impl Ord for Event {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[derive(Debug)]
pub struct Synapse {
    pub delay:  time,
    pub weight: float,
    pub post_neuron: NeuronId,
}

pub trait Recorder {
    fn record_fire(&mut self, timestamp: time, neuron_id: NeuronId);
}

pub struct Net<R:Recorder> {
    neurons: Vec<Neuron>,
    neuron_configs: Vec<NeuronConfig>,
    synapses: Vec<Vec<Synapse>>,
    events: BinaryHeap<Event>,
    recorder: Option<Box<R>>
}

impl<R:Recorder> Net<R> {
    pub fn new() -> Net<R> {
        Net {
            neurons: vec![],
            neuron_configs: vec![],
            synapses: vec![],
            events: BinaryHeap::new(),
            recorder: None,
        }
    }

    pub fn set_recorder(&mut self, opt_recorder: Option<Box<R>>) {
        self.recorder = opt_recorder;
    }

    pub fn get_recorder(&self) -> Option<&Box<R>> {
        self.recorder.as_ref()
    }

    pub fn create_neuron_config(&mut self, config: NeuronConfig) -> NeuronConfigId {
        self.neuron_configs.push(config);
        NeuronConfigId(self.neuron_configs.len() - 1)
    }

    pub fn create_neuron(&mut self, config_id: NeuronConfigId) -> NeuronId {
        self.neurons.push(Neuron::new(config_id));
        self.synapses.push(vec![]);
        NeuronId(self.neurons.len() - 1)
    }

    pub fn create_synapse(&mut self, from_neuron: NeuronId, synapse: Synapse) {
        let mut syn_arr = &mut (self.synapses.as_mut_slice())[from_neuron.0];
        syn_arr.push(synapse);
    }

    pub fn add_event(&mut self, event: Event) {
        self.events.push(event);
    }

    // values are in ms
    pub fn add_spike_train_float_ms(&mut self, target: NeuronId, weight: float, spikes: &[float]) {
        for &t in spikes {
            self.add_event(Event {
                time: ms_float_to_time(t),
                weight: weight,
                target: target
            });
        }
    }

    fn fire(&mut self, timestamp: time, neuron_id: NeuronId) {
        for syn in &self.synapses[neuron_id.0] {
            println!("{:?}", syn);
            self.events.push(Event {
                time: timestamp + syn.delay,
                weight: syn.weight,
                target: syn.post_neuron
            });
        }

        if let Some(ref mut recorder) = self.recorder {
            recorder.record_fire(timestamp, neuron_id);
        }

        if let Some(ident) = self.get_config_for_neuron_id(neuron_id).record {
            println!("RECORD\t{}\t{}\t{}", ident, neuron_id.0, timestamp);
        }
    }

    fn get_neuron(&self, neuron_id: NeuronId) -> &Neuron {
        &self.neurons[neuron_id.0]
    }

    fn get_config_for_neuron<'a>(&'a self, neuron: &Neuron) -> &'a NeuronConfig {
        &(self.neuron_configs.as_slice())[neuron.config_id.0]
    }

    fn get_config_for_neuron_id(&self, neuron_id: NeuronId) -> &NeuronConfig {
        self.get_config_for_neuron(self.get_neuron(neuron_id))
    }

    pub fn simulate(&mut self) {
	loop {
	    println!("-------------------------------------");

	    if let Some(mut ev) = self.events.pop() {

                // consume all elements with same timestamp and same target
                loop {
                    match self.events.peek() {
                        Some(ev2) if ev2.time == ev.time && ev2.target == ev.target => {
                            println!("consume additional event: {:?}", ev2);
                            ev.weight += ev2.weight;
                        }
                        _ => break
                    }
                    let _ = self.events.pop();
                }

		println!("{:?}", ev);
                let neuron_id = ev.target;
                let fire = {
		    let neuron = &mut (self.neurons.as_mut_slice())[neuron_id.0];
                    let cfg = &(self.neuron_configs.as_slice())[neuron.config_id.0];
		    let fire = neuron.spike(ev.time, ev.weight, cfg);
		    println!("{:?}", fire);
		    println!("{:?}", neuron);
                    fire
                };
                match fire {
                    NeuronResult::Fire => {
                        // Post a new event to all synapses
                        self.fire(ev.time, neuron_id);
                    }
                    _ => {
                    }
                }
	    }
	    else {
		break;
	    }
	}
    }
}
<|endoftext|>


<commit_before>//!
//! ```
//! use document::Package;
//! let package = Package::new();
//! let doc = package.as_document();
//!
//! let hello = doc.create_element("hello");
//! hello.set_attribute_value("planet", "Earth");
//! let comment = doc.create_comment("What about other planets?");
//! let text = doc.create_text("Greetings, Earthlings!");
//!
//! hello.append_child(comment);
//! hello.append_child(text);
//! doc.root().append_child(hello);
//! ```
//!
//! ### Design decisions
//!
//! Try to leverage the type system as much as possible.

#![crate_name = "document"]
#![experimental]
#![feature(macro_rules)]
#![feature(default_type_params)]
#![feature(globs)]

extern crate arena;
extern crate test;
extern crate xxhash;

use std::fmt;

mod string_pool;
mod raw;
mod peresil;
pub mod thindom4;
pub mod dom4;
pub mod parser;
pub mod writer;

#[deriving(Show,PartialEq,Eq,PartialOrd)]
pub struct QName<'s> {
    namespace_uri: Option<&'s str>,
    local_part: &'s str,
}

impl<'s> QName<'s> {
    pub fn new(local_part: &'s str) -> QName<'s> {
        QName::with_namespace_uri(None, local_part)
    }

    pub fn with_namespace_uri(namespace_uri: Option<&'s str>, local_part: &'s str) -> QName<'s> {
        QName {
            namespace_uri: namespace_uri,
            local_part: local_part,
        }
    }

    pub fn namespace_uri(&self) -> Option<&'s str> { self.namespace_uri }
    pub fn local_part(&self) -> &'s str { self.local_part }
}

impl<'s> Ord for QName<'s> {
    fn cmp(&self, other: &QName<'s>) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

pub trait ToQName<'s> {
    fn to_qname(self) -> QName<'s>;
}

impl<'s> ToQName<'s> for QName<'s> {
    fn to_qname(self) -> QName<'s> { self }
}

impl<'s> ToQName<'s> for &'s str {
    fn to_qname(self) -> QName<'s> { QName { namespace_uri: None, local_part: self } }
}

pub struct Package {
    storage: raw::Storage,
    connections: raw::Connections,
}

impl Package {
    pub fn new() -> Package {
        let s = raw::Storage::new();
        let root = s.create_root();
        Package {
            storage: s,
            connections: raw::Connections::new(root),
        }
    }

    pub fn as_document(&self) -> dom4::Document {
        dom4::Document::new(&self.storage, &self.connections)
    }

    pub fn as_thin_document(&self) -> (thindom4::Storage, thindom4::Connections) {
        let s = thindom4::Storage::new(&self.storage);
        let c = thindom4::Connections::new(&self.connections);
        (s, c)
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self as *const Package == other as *const Package
    }
}

impl fmt::Show for Package {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Package")
    }
}

#[doc(hidden)]
mod document {
    pub use peresil;
}
<commit_msg>Make peresil public<commit_after>//!
//! ```
//! use document::Package;
//! let package = Package::new();
//! let doc = package.as_document();
//!
//! let hello = doc.create_element("hello");
//! hello.set_attribute_value("planet", "Earth");
//! let comment = doc.create_comment("What about other planets?");
//! let text = doc.create_text("Greetings, Earthlings!");
//!
//! hello.append_child(comment);
//! hello.append_child(text);
//! doc.root().append_child(hello);
//! ```
//!
//! ### Design decisions
//!
//! Try to leverage the type system as much as possible.

#![crate_name = "document"]
#![experimental]
#![feature(macro_rules)]
#![feature(default_type_params)]
#![feature(globs)]

extern crate arena;
extern crate test;
extern crate xxhash;

use std::fmt;

mod string_pool;
mod raw;
pub mod peresil;
pub mod thindom4;
pub mod dom4;
pub mod parser;
pub mod writer;

#[deriving(Show,PartialEq,Eq,PartialOrd)]
pub struct QName<'s> {
    namespace_uri: Option<&'s str>,
    local_part: &'s str,
}

impl<'s> QName<'s> {
    pub fn new(local_part: &'s str) -> QName<'s> {
        QName::with_namespace_uri(None, local_part)
    }

    pub fn with_namespace_uri(namespace_uri: Option<&'s str>, local_part: &'s str) -> QName<'s> {
        QName {
            namespace_uri: namespace_uri,
            local_part: local_part,
        }
    }

    pub fn namespace_uri(&self) -> Option<&'s str> { self.namespace_uri }
    pub fn local_part(&self) -> &'s str { self.local_part }
}

impl<'s> Ord for QName<'s> {
    fn cmp(&self, other: &QName<'s>) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

pub trait ToQName<'s> {
    fn to_qname(self) -> QName<'s>;
}

impl<'s> ToQName<'s> for QName<'s> {
    fn to_qname(self) -> QName<'s> { self }
}

impl<'s> ToQName<'s> for &'s str {
    fn to_qname(self) -> QName<'s> { QName { namespace_uri: None, local_part: self } }
}

pub struct Package {
    storage: raw::Storage,
    connections: raw::Connections,
}

impl Package {
    pub fn new() -> Package {
        let s = raw::Storage::new();
        let root = s.create_root();
        Package {
            storage: s,
            connections: raw::Connections::new(root),
        }
    }

    pub fn as_document(&self) -> dom4::Document {
        dom4::Document::new(&self.storage, &self.connections)
    }

    pub fn as_thin_document(&self) -> (thindom4::Storage, thindom4::Connections) {
        let s = thindom4::Storage::new(&self.storage);
        let c = thindom4::Connections::new(&self.connections);
        (s, c)
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Package) -> bool {
        self as *const Package == other as *const Package
    }
}

impl fmt::Show for Package {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Package")
    }
}

#[doc(hidden)]
mod document {
    pub use peresil;
}
<|endoftext|>