<commit_before>use error::*;

use buffer::Buffered;
use std::io::SeekFrom;
use std::any::Any;
use std::sync::Arc;

use common::*;

use stream::Stream;
use data::packet::Packet;

#[derive(Clone, Debug)]
pub enum Event {
    NewPacket(Packet),
    NewStream(Stream),
    MoreDataNeeded(usize),
    Eof,
}

pub trait Demuxer : Send {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom>;
    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)>;
}

#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    pub name: &'static str,
    pub demuxer: &'static str,
    pub description: &'static str,
    pub extensions: &'static [&'static str],
    pub mime: &'static [&'static str],
}

pub trait Descriptor {
    fn create(&self) -> Box<Demuxer>;
    fn describe<'a>(&'a self) -> &'a Descr;

    fn probe(&self, data: &[u8]) -> u8;
}

pub struct Context {
    demuxer: Box<Demuxer>,
    reader: Box<Buffered>,
    pub info: GlobalInfo,
    pub user_private: Option<Arc<Any + Send + Sync>>,
}

impl Context {
    pub fn new<R: Buffered + 'static>(demuxer: Box<Demuxer>, reader: Box<R>) -> Self {
        Context {
            demuxer: demuxer,
            reader: reader,
            info: GlobalInfo {
                duration: None,
                timebase: None,
                streams: Vec::with_capacity(2),
            },
            user_private: None,
        }
    }

    fn read_headers_internal(&mut self) -> Result<()> {
        let ref mut demux = self.demuxer;
        let res = demux.read_headers(&self.reader, &mut self.info);
        match res {
            Err(e) => Err(e),
            Ok(seek) => {
                //TODO: handle seeking here
                let res = self.reader.seek(seek);
                println!("stream now at index: {:?}", res);
                Ok(())
            }
        }
    }

    pub fn read_headers(&mut self) -> Result<()> {
        loop {
            // TODO: wrap fill_buf() with a check for Eof
            self.reader.fill_buf()?;
            match self.read_headers_internal() {
                Err(e) => match e {
                    Error::MoreDataNeeded(needed) => {
                        self.reader.grow(needed);
                    },
                    _ => return Err(e)
                },
                Ok(_) => return Ok(()),
            }
        }
    }

    fn read_event_internal(&mut self) -> Result<Event> {
        let ref mut demux = self.demuxer;

        let res = demux.read_event(&self.reader);
        match res {
            Err(e) => Err(e),
            Ok((seek, mut event)) => {
                //TODO: handle seeking here
                let _ = self.reader.seek(seek)?;
                if let Event::NewStream(ref st) = event {
                    self.info.streams.push(st.clone());
                }
                if let Event::MoreDataNeeded(size) = event {
                    return Err(Error::MoreDataNeeded(size));
                }
                if let Event::NewPacket(ref mut pkt) = event {
                    if pkt.t.timebase.is_none() {
                        if let Some(ref st) = self.info.streams.iter().find(|s| {
                            s.index as isize == pkt.stream_index
                        }) {
                            pkt.t.timebase = Some(st.timebase);
                        }
                    }
                }
                Ok(event)
            }
        }
    }

    pub fn read_event(&mut self) -> Result<Event> {
        use std::io::ErrorKind as Eio;
        // TODO: guard against infiniloops and maybe factor the loop.
        loop {
            match self.read_event_internal() {
                Err(e) => match e {
                    Error::MoreDataNeeded(needed) => {
                        let len = self.reader.data().len();
                        self.reader.grow(needed);
                        self.reader.fill_buf()?;
                        if self.reader.data().len() <= len {
                            return Err(Error::Io(Eio::UnexpectedEof.into()));
                        }
                    },
                    _ => return Err(e)
                },
                Ok(ev) => return Ok(ev),
            }
        }
    }
}

pub const PROBE_DATA: usize = 4 * 1024;
pub const PROBE_SCORE_EXTENSION: u8 = 50;

// TODO:
// IntoIterator<Item = &'static Descriptor> is confusing

pub trait Probe {
    fn probe(&self, data: &[u8]) -> Option<&'static Descriptor>;
}

impl<'a> Probe for [&'static Descriptor] {
    fn probe(&self, data: &[u8]) -> Option<&'static Descriptor> {
        let mut max = u8::min_value();
        let mut candidate: Option<&'static Descriptor> = None;
        for desc in self {
            let score = desc.probe(data);

            if score > max {
                max = score;
                candidate = Some(*desc);
            }
        }

        if max > PROBE_SCORE_EXTENSION {
            candidate
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::SeekFrom;
    use data::packet::Packet;

    struct DummyDes {
        d: Descr,
    }

    struct DummyDemuxer {}

    impl Demuxer for DummyDemuxer {
        fn read_headers(&mut self, buf: &Box<Buffered>, _info: &mut GlobalInfo) -> Result<SeekFrom> {
            let len = buf.data().len();
            if 9 > len {
                let needed = 9 - len;
                Err(Error::MoreDataNeeded(needed))
            } else {
                Ok(SeekFrom::Current(9))
            }
        }
        fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
            let size = 2;
            let len = buf.data().len();
            if size > len {
                Err(Error::MoreDataNeeded(size - len))
            } else {
                println!("{:?}", buf.data());
                match &buf.data()[..2] {
                    b"p1" => {
                        Ok((SeekFrom::Current(3), Event::NewPacket(Packet::new())))
                    },
                    b"e1" => {
                        Ok((SeekFrom::Current(3), Event::MoreDataNeeded(0)))
                    }
                    _ => Err(Error::InvalidData.into())
                }
            }
        }
    }

    impl Descriptor for DummyDes {
        fn create(&self) -> Box<Demuxer> {
            Box::new(DummyDemuxer {})
        }
        fn describe<'a>(&'a self) -> &'a Descr {
            &self.d
        }
        fn probe(&self, data: &[u8]) -> u8 {
            match data {
                b"dummy" => 100,
                _ => 0,
            }
        }
    }

    const DUMMY_DES: &Descriptor = &DummyDes {
        d: Descr {
            name: "dummy",
            demuxer: "dummy",
            description: "Dummy dem",
            extensions: &["dm", "dum"],
            mime: &["application/dummy"],
        },
    };

    #[test]
    fn probe() {
        let demuxers: &[&'static Descriptor] = &[DUMMY_DES];

        demuxers.probe(b"dummy").unwrap();
    }

    use std::io::Cursor;
    use buffer::*;

    #[test]
    fn read_headers() {
        let buf = b"dummy header";
        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();
    }

    #[test]
    fn read_event() {
        let buf = b"dummy header p1 e1 p1 ";

        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();

        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
    }
}
<commit_msg>send the EOF event from Context<commit_after>use error::*;

use buffer::Buffered;
use std::io::SeekFrom;
use std::any::Any;
use std::sync::Arc;

use common::*;

use stream::Stream;
use data::packet::Packet;

#[derive(Clone, Debug)]
pub enum Event {
    NewPacket(Packet),
    NewStream(Stream),
    MoreDataNeeded(usize),
    Eof,
}

pub trait Demuxer : Send {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom>;
    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)>;
}

#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    pub name: &'static str,
    pub demuxer: &'static str,
    pub description: &'static str,
    pub extensions: &'static [&'static str],
    pub mime: &'static [&'static str],
}

pub trait Descriptor {
    fn create(&self) -> Box<Demuxer>;
    fn describe<'a>(&'a self) -> &'a Descr;

    fn probe(&self, data: &[u8]) -> u8;
}

pub struct Context {
    demuxer: Box<Demuxer>,
    reader: Box<Buffered>,
    pub info: GlobalInfo,
    pub user_private: Option<Arc<Any + Send + Sync>>,
}

impl Context {
    pub fn new<R: Buffered + 'static>(demuxer: Box<Demuxer>, reader: Box<R>) -> Self {
        Context {
            demuxer: demuxer,
            reader: reader,
            info: GlobalInfo {
                duration: None,
                timebase: None,
                streams: Vec::with_capacity(2),
            },
            user_private: None,
        }
    }

    fn read_headers_internal(&mut self) -> Result<()> {
        let ref mut demux = self.demuxer;
        let res = demux.read_headers(&self.reader, &mut self.info);
        match res {
            Err(e) => Err(e),
            Ok(seek) => {
                //TODO: handle seeking here
                let res = self.reader.seek(seek);
                println!("stream now at index: {:?}", res);
                Ok(())
            }
        }
    }

    pub fn read_headers(&mut self) -> Result<()> {
        loop {
            // TODO: wrap fill_buf() with a check for Eof
            self.reader.fill_buf()?;
            match self.read_headers_internal() {
                Err(e) => match e {
                    Error::MoreDataNeeded(needed) => {
                        self.reader.grow(needed);
                    },
                    _ => return Err(e)
                },
                Ok(_) => return Ok(()),
            }
        }
    }

    fn read_event_internal(&mut self) -> Result<Event> {
        let ref mut demux = self.demuxer;

        let res = demux.read_event(&self.reader);
        match res {
            Err(e) => Err(e),
            Ok((seek, mut event)) => {
                //TODO: handle seeking here
                let _ = self.reader.seek(seek)?;
                if let Event::NewStream(ref st) = event {
                    self.info.streams.push(st.clone());
                }
                if let Event::MoreDataNeeded(size) = event {
                    return Err(Error::MoreDataNeeded(size));
                }
                if let Event::NewPacket(ref mut pkt) = event {
                    if pkt.t.timebase.is_none() {
                        if let Some(ref st) = self.info.streams.iter().find(|s| {
                            s.index as isize == pkt.stream_index
                        }) {
                            pkt.t.timebase = Some(st.timebase);
                        }
                    }
                }
                Ok(event)
            }
        }
    }

    pub fn read_event(&mut self) -> Result<Event> {
        use std::io::ErrorKind as Eio;
        // TODO: guard against infiniloops and maybe factor the loop.
        loop {
            match self.read_event_internal() {
                Err(e) => match e {
                    Error::MoreDataNeeded(needed) => {
                        let len = self.reader.data().len();
                        self.reader.grow(needed);
                        self.reader.fill_buf()?;
                        if self.reader.data().len() <= len {
                            return Ok(Event::Eof);
                        }
                    },
                    _ => return Err(e)
                },
                Ok(ev) => return Ok(ev),
            }
        }
    }
}

pub const PROBE_DATA: usize = 4 * 1024;
pub const PROBE_SCORE_EXTENSION: u8 = 50;

// TODO:
// IntoIterator<Item = &'static Descriptor> is confusing

pub trait Probe {
    fn probe(&self, data: &[u8]) -> Option<&'static Descriptor>;
}

impl<'a> Probe for [&'static Descriptor] {
    fn probe(&self, data: &[u8]) -> Option<&'static Descriptor> {
        let mut max = u8::min_value();
        let mut candidate: Option<&'static Descriptor> = None;
        for desc in self {
            let score = desc.probe(data);

            if score > max {
                max = score;
                candidate = Some(*desc);
            }
        }

        if max > PROBE_SCORE_EXTENSION {
            candidate
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::SeekFrom;
    use data::packet::Packet;

    struct DummyDes {
        d: Descr,
    }

    struct DummyDemuxer {}

    impl Demuxer for DummyDemuxer {
        fn read_headers(&mut self, buf: &Box<Buffered>, _info: &mut GlobalInfo) -> Result<SeekFrom> {
            let len = buf.data().len();
            if 9 > len {
                let needed = 9 - len;
                Err(Error::MoreDataNeeded(needed))
            } else {
                Ok(SeekFrom::Current(9))
            }
        }
        fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
            let size = 2;
            let len = buf.data().len();
            if size > len {
                Err(Error::MoreDataNeeded(size - len))
            } else {
                println!("{:?}", buf.data());
                match &buf.data()[..2] {
                    b"p1" => {
                        Ok((SeekFrom::Current(3), Event::NewPacket(Packet::new())))
                    },
                    b"e1" => {
                        Ok((SeekFrom::Current(3), Event::MoreDataNeeded(0)))
                    }
                    _ => Err(Error::InvalidData.into())
                }
            }
        }
    }

    impl Descriptor for DummyDes {
        fn create(&self) -> Box<Demuxer> {
            Box::new(DummyDemuxer {})
        }
        fn describe<'a>(&'a self) -> &'a Descr {
            &self.d
        }
        fn probe(&self, data: &[u8]) -> u8 {
            match data {
                b"dummy" => 100,
                _ => 0,
            }
        }
    }

    const DUMMY_DES: &Descriptor = &DummyDes {
        d: Descr {
            name: "dummy",
            demuxer: "dummy",
            description: "Dummy dem",
            extensions: &["dm", "dum"],
            mime: &["application/dummy"],
        },
    };

    #[test]
    fn probe() {
        let demuxers: &[&'static Descriptor] = &[DUMMY_DES];

        demuxers.probe(b"dummy").unwrap();
    }

    use std::io::Cursor;
    use buffer::*;

    #[test]
    fn read_headers() {
        let buf = b"dummy header";
        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();
    }

    #[test]
    fn read_event() {
        let buf = b"dummy header p1 e1 p1 ";

        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();

        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
    }
}
<|endoftext|>


<commit_before>use crate::constants::*;
use itertools::Itertools;

// Highlight lines starting with "commit: "

pub fn format_commit_line(line: &str) -> String {
    let parts = line.split('(').collect::<Vec<_>>();
    if parts.len() == 1 {
        // Just "commit: 123abc", color it all yellow
        return format!("{}{}{}", YELLOW, line, NORMAL);
    }

    let commit_part = parts[0].trim();
    let without_trailing_parenthesis = parts[1].strip_suffix(')');
    if without_trailing_parenthesis == None {
        // No final parenthesis, this is weird, fall back to showing everything
        // in yellow
        return format!("{}{}{}", YELLOW, line, NORMAL);
    }

    let parenthesis_parts = without_trailing_parenthesis
        .unwrap()
        .split(", ")
        .collect_vec();
    let current_branch = compute_current_branch(&parenthesis_parts);

    let comma = format!("{}, {}", YELLOW, NORMAL);
    return format!(
        "{}{} ({}{}){}",
        YELLOW,
        commit_part,
        parenthesis_parts
            .iter()
            .map(|part| format_commit_part(part, &current_branch))
            .join(&comma),
        YELLOW,
        NORMAL
    );
}

fn format_commit_part(part: &str, current_branch: &Option<String>) -> String {
    if part.starts_with("tag: ") {
        return format!("{}{}{}{}", BOLD, YELLOW, part, NORMAL);
    }

    // FIXME: Can we do this with one readable if-statement instead?
    if let Some(current_branch_4_realz) = current_branch {
        if current_branch_4_realz == part {
            return format!("{}{}{}{}", BOLD, GREEN, part, NORMAL);
        }
    }

    // Handle "HEAD -> current_branch"
    if let Some(head_branch) = part.strip_prefix("HEAD -> ") {
        return format!("{}{}HEAD -> {}{}{}", BOLD, CYAN, GREEN, head_branch, NORMAL);
    }

    // Assume this is a branch, but not the current one
    return format!("{}{}{}{}", BOLD, RED, part, NORMAL);
}

fn compute_current_branch(candidates: &Vec<&str>) -> Option<String> {
    // If we find multiple options, pick the one with the lowest number of
    // slashes
    let mut fewest_slashes: Vec<&str> = vec![];
    let mut lowest_slash_count = usize::MAX;
    for candidate in candidates {
        if candidate.starts_with("tag: ") {
            // This is not a branch name
            continue;
        }

        if let Some(headless) = candidate.strip_prefix("HEAD -> ") {
            // Found it, this is conclusive!
            return Some(headless.to_owned());
        }

        let candidate_slash_count = candidate.matches('/').count();
        if candidate_slash_count > lowest_slash_count {
            // This one is worse than what we already have, never mind
            continue;
        }

        if candidate_slash_count < lowest_slash_count {
            // This one is better, replace the others
            fewest_slashes.clear();
        }

        lowest_slash_count = candidate_slash_count;
        fewest_slashes.push(candidate);
    }

    if fewest_slashes.is_empty() {
        return None;
    }

    if fewest_slashes.len() == 1 {
        return Some(fewest_slashes[0].to_owned());
    }

    // Give up, we don't know
    return None;
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_compute_current_branch() {
        // git show 686f3d7aefe9597395020ff0219eebc90e363d47
        assert_eq!(
            None,
            compute_current_branch(&"tag: 2.15".split(", ").collect_vec())
        );

        assert_eq!(
            Some(String::from("master")),
            compute_current_branch(
                &"HEAD -> master, tag: 2.20.0, origin/master, origin/HEAD"
                    .split(", ")
                    .collect_vec()
            )
        );

        assert_eq!(
            Some(String::from("master")),
            compute_current_branch(
                &"tag: 2.20.0, origin/master, origin/HEAD, master"
                    .split(", ")
                    .collect_vec()
            )
        );

        assert_eq!(
            Some(String::from("walles/threaded")),
            compute_current_branch(
                &"origin/walles/threaded, walles/threaded"
                    .split(", ")
                    .collect_vec()
            )
        );

        assert_eq!(
            Some(String::from("xeago-master")),
            compute_current_branch(&"xeago/master, xeago-master".split(", ").collect_vec())
        );
    }

    FIXME: Add a test for adding blue background to a commit line with some tags and branches
}
<commit_msg>Test that the blue background goes all the way<commit_after>use crate::constants::*;
use itertools::Itertools;

// Highlight lines starting with "commit: "

pub fn format_commit_line(line: &str) -> String {
    let parts = line.split('(').collect::<Vec<_>>();
    if parts.len() == 1 {
        // Just "commit: 123abc", color it all yellow
        return format!("{}{}{}", YELLOW, line, NORMAL);
    }

    let commit_part = parts[0].trim();
    let without_trailing_parenthesis = parts[1].strip_suffix(')');
    if without_trailing_parenthesis == None {
        // No final parenthesis, this is weird, fall back to showing everything
        // in yellow
        return format!("{}{}{}", YELLOW, line, NORMAL);
    }

    let parenthesis_parts = without_trailing_parenthesis
        .unwrap()
        .split(", ")
        .collect_vec();
    let current_branch = compute_current_branch(&parenthesis_parts);

    let comma = format!("{}, {}", YELLOW, NORMAL);
    return format!(
        "{}{} ({}{}){}",
        YELLOW,
        commit_part,
        parenthesis_parts
            .iter()
            .map(|part| format_commit_part(part, &current_branch))
            .join(&comma),
        YELLOW,
        NORMAL
    );
}

fn format_commit_part(part: &str, current_branch: &Option<String>) -> String {
    if part.starts_with("tag: ") {
        return format!("{}{}{}{}", BOLD, YELLOW, part, NORMAL);
    }

    // FIXME: Can we do this with one readable if-statement instead?
    if let Some(current_branch_4_realz) = current_branch {
        if current_branch_4_realz == part {
            return format!("{}{}{}{}", BOLD, GREEN, part, NORMAL);
        }
    }

    // Handle "HEAD -> current_branch"
    if let Some(head_branch) = part.strip_prefix("HEAD -> ") {
        return format!("{}{}HEAD -> {}{}{}", BOLD, CYAN, GREEN, head_branch, NORMAL);
    }

    // Assume this is a branch, but not the current one
    return format!("{}{}{}{}", BOLD, RED, part, NORMAL);
}

fn compute_current_branch(candidates: &Vec<&str>) -> Option<String> {
    // If we find multiple options, pick the one with the lowest number of
    // slashes
    let mut fewest_slashes: Vec<&str> = vec![];
    let mut lowest_slash_count = usize::MAX;
    for candidate in candidates {
        if candidate.starts_with("tag: ") {
            // This is not a branch name
            continue;
        }

        if let Some(headless) = candidate.strip_prefix("HEAD -> ") {
            // Found it, this is conclusive!
            return Some(headless.to_owned());
        }

        let candidate_slash_count = candidate.matches('/').count();
        if candidate_slash_count > lowest_slash_count {
            // This one is worse than what we already have, never mind
            continue;
        }

        if candidate_slash_count < lowest_slash_count {
            // This one is better, replace the others
            fewest_slashes.clear();
        }

        lowest_slash_count = candidate_slash_count;
        fewest_slashes.push(candidate);
    }

    if fewest_slashes.is_empty() {
        return None;
    }

    if fewest_slashes.len() == 1 {
        return Some(fewest_slashes[0].to_owned());
    }

    // Give up, we don't know
    return None;
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_compute_current_branch() {
        // git show 686f3d7aefe9597395020ff0219eebc90e363d47
        assert_eq!(
            None,
            compute_current_branch(&"tag: 2.15".split(", ").collect_vec())
        );

        assert_eq!(
            Some(String::from("master")),
            compute_current_branch(
                &"HEAD -> master, tag: 2.20.0, origin/master, origin/HEAD"
                    .split(", ")
                    .collect_vec()
            )
        );

        assert_eq!(
            Some(String::from("master")),
            compute_current_branch(
                &"tag: 2.20.0, origin/master, origin/HEAD, master"
                    .split(", ")
                    .collect_vec()
            )
        );

        assert_eq!(
            Some(String::from("walles/threaded")),
            compute_current_branch(
                &"origin/walles/threaded, walles/threaded"
                    .split(", ")
                    .collect_vec()
            )
        );

        assert_eq!(
            Some(String::from("xeago-master")),
            compute_current_branch(&"xeago/master, xeago-master".split(", ").collect_vec())
        );
    }

    const NORMAL_INTENSITY: &str = "\x1b[22m";

    #[test]
    // Verify that the blue background goes all the way from the start of the
    // string to its end
    fn test_format_commit_line_tags_branches() {
        assert_eq!(
            "".to_owned() +
            YELLOW +
            BLUE_TO_END_OF_LINE +
            "commit 62da46c7b300321119d399bdc69bfb2d56d5da57 (" +
            BOLD +
            "tag: 2.21.0"+
            NORMAL_INTENSITY+
            ", "+
            BOLD + RED +
            "origin/master" +
            NORMAL_INTENSITY + YELLOW +
            ", " +
            BOLD + RED +
            "origin/HEAD" +
            NORMAL_INTENSITY + YELLOW +
            ", " +
            BOLD + GREEN +
            "master" +
            NORMAL_INTENSITY + YELLOW +
            ")" +
            NORMAL,
        // This commit is from the master branch
        format_commit_line("commit 62da46c7b300321119d399bdc69bfb2d56d5da57 (tag: 2.21.0, origin/master, origin/HEAD, master)"));
    }
}
<|endoftext|>


<commit_before>use luminance::{Depth32F, Dim2, Flat, Framebuffer, Mode, RGBA32F, Tess, Texture, Uniform, Unit};
use luminance::pipeline::{Pipe, Pipeline, RenderCommand, ShadingCommand};
use luminance::tess::TessRender;
use std::ops::{Add, Mul, Sub};

pub use luminance::{Equation, Factor};

use color::RGBA;
use resource::{Res, ResCache};
use shader::Program;

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(RGBA),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, RGBA, Equation, Factor, Factor)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, rhs: Self, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(rhs), clear_color, eq, src_fct, dst_fct)
  }

  /// Compose this node over the other. In effect, the resulting node will replace any pixels covered
  /// by the right node by the ones of the left node unless the alpha value is different than `1`.
  /// In that case, an additive blending based on the alpha value of the left node will be performed.
  ///
  /// If you set the alpha value to `0` at a pixel in the left node, then the resulting pixel will be
  /// the one from the right node.
  pub fn over(self, rhs: Self) -> Self {
    rhs.compose_with(self, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> From<RGBA> for Node<'a> {
  fn from(color: RGBA) -> Self {
    Node::Color(color)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  compose_program: Res<Program>,
  // program used to render textures scaled
  texture_program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);
const TEXTURE_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      compose_program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      texture_program: cache.get("spectra/compositing/texture.glsl", vec![TEXTURE_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];

      let screen = Framebuffer::default((self.w, self.h));

      let black = [0., 0., 0., 1.];
      let compose_program = self.compose_program.borrow();
      let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
      let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&compose_program, render_cmd))];
      let texture_set = &[&*fb.color_slot];

      Pipeline::new(&screen, black, texture_set, &[], shd_cmd).run();
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let black = [0., 0., 0., 1.];
    let texture_program = self.texture_program.borrow();
    let uniforms_tex = [TEXTURE_SOURCE.alter(Unit::new(0))];
    let tess_render = TessRender::from(&self.quad);
    let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
    let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
    let shd_cmd = &[Pipe::new(ShadingCommand::new(&texture_program, render_cmd))];
    let texture_set = &[&**texture];

    Pipeline::new(fb, black, texture_set, &[], shd_cmd).run();

    fb_index
  }

  fn colorize(&mut self, color: RGBA) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[], &[]).run();

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      // compose
      let compose_program = self.compose_program.borrow();
      let uniforms_left = [FORWARD_SOURCE.alter(Unit::new(0))];
      let uniforms_right = [FORWARD_SOURCE.alter(Unit::new(1))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[
        Pipe::empty().uniforms(&uniforms_left).unwrap(tess_render.clone()),
        Pipe::empty().uniforms(&uniforms_right).unwrap(tess_render)
      ];
      let render_cmd = &[Pipe::new(RenderCommand::new((eq, src_fct, dst_fct), false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&compose_program, render_cmd))];
      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[], shd_cmd).run();
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }
}
<commit_msg>Duhuhuhu!<commit_after>use luminance::framebuffer::Framebuffer;
use luminance::pixel::{Depth32F, RGBA32F};
use luminance::tess::{Mode, Tess};
use luminance::texture::{Dim2, Flat, Texture, Unit};
use luminance::pipeline::{Pipeline, RenderCommand, ShadingCommand};
use luminance::tess::TessRender;
use std::ops::{Add, Mul, Sub};

pub use luminance::{Equation, Factor};

use color::RGBA;
use resource::{Res, ResCache};
use shader::{Program, Uniform};

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(RGBA),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, RGBA, Equation, Factor, Factor)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, rhs: Self, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(rhs), clear_color, eq, src_fct, dst_fct)
  }

  /// Compose this node over the other. In effect, the resulting node will replace any pixels covered
  /// by the right node by the ones of the left node unless the alpha value is different than `1`.
  /// In that case, an additive blending based on the alpha value of the left node will be performed.
  ///
  /// If you set the alpha value to `0` at a pixel in the left node, then the resulting pixel will be
  /// the one from the right node.
  pub fn over(self, rhs: Self) -> Self {
    rhs.compose_with(self, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> From<RGBA> for Node<'a> {
  fn from(color: RGBA) -> Self {
    Node::Color(color)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  compose_program: Res<Program>,
  // program used to render textures scaled
  texture_program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);
const TEXTURE_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      compose_program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      texture_program: cache.get("spectra/compositing/texture.glsl", vec![TEXTURE_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];
      let screen = Framebuffer::default((self.w, self.h));
      let compose_program = self.compose_program.borrow();
      let tess_render = TessRender::from(&self.quad);

      Pipeline::new(&screen, [0., 0., 0., 1.], &[&*fb.color_slot], &[]).enter(|shd_gate| {
        shd_gate.new(&compose_program, &[], &[], &[]).enter(|rdr_gate| {
          rdr_gate.new(None, false, &[], &[], &[]).enter(|tess_gate| {
            tess_gate.render(tess_render, &[FORWARD_SOURCE.alter(Unit::new(0))], &[], &[])
          });
        });
      });
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let black = [0., 0., 0., 1.];
    let texture_program = self.texture_program.borrow();
    let uniforms_tex = [TEXTURE_SOURCE.alter(Unit::new(0))];
    let tess_render = TessRender::from(&self.quad);
    let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
    let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
    let shd_cmd = &[Pipe::new(ShadingCommand::new(&texture_program, render_cmd))];
    let texture_set = &[&**texture];

    Pipeline::new(fb, black, texture_set, &[], shd_cmd).run();

    fb_index
  }

  fn colorize(&mut self, color: RGBA) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[]).enter(|_| {});

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      // compose
      let compose_program = self.compose_program.borrow();
      let uniforms_left = [FORWARD_SOURCE.alter(Unit::new(0))];
      let uniforms_right = [FORWARD_SOURCE.alter(Unit::new(1))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[
        Pipe::empty().uniforms(&uniforms_left).unwrap(tess_render.clone()),
        Pipe::empty().uniforms(&uniforms_right).unwrap(tess_render)
      ];
      let render_cmd = &[Pipe::new(RenderCommand::new((eq, src_fct, dst_fct), false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&compose_program, render_cmd))];
      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[], shd_cmd).run();
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;

use middle;

pub mod types;
use self::types::*;

macro_rules! declare_cif {
    ( $typename:ident $( $param:ident )*) => {
        pub struct $typename<$( $param, )* R> {
            untyped: middle::Cif,
            _marker: PhantomData<fn($( $param, )*) -> R>,
        }

        impl<$( $param, )* R> $typename<$( $param, )* R> {
            #[allow(non_snake_case)]
            pub fn new($( $param: Type<$param>, )* result: Type<R>) -> Self {
                let cif = middle::Cif::new(vec![$( $param.into_untyped() ),*],
                                           result.into_untyped());
                $typename { untyped: cif, _marker: PhantomData }
            }
        }
    }
}

declare_cif!(Cif0);
declare_cif!(Cif1 A);
declare_cif!(Cif2 A B);
declare_cif!(Cif3 A B C);
declare_cif!(Cif4 A B C D);
declare_cif!(Cif5 A B C D E);
declare_cif!(Cif6 A B C D E F);
declare_cif!(Cif7 A B C D E F G);
declare_cif!(Cif8 A B C D E F G H);
declare_cif!(Cif9 A B C D E F G H I);
declare_cif!(Cif10 A B C D E F G H I J);

macro_rules! declare_callback {
    ( $typename:ident $( $param:ident )* ) => {
        pub type $typename<U, $( $param, )* R>
            = extern "C" fn(cif:      &::low::ffi_cif,
                            result:   &mut R,
                            args:     &($( &$param, )*),
                            userdata: &U);
    }
}

declare_callback!( Callback0 );
declare_callback!( Callback1 A );
declare_callback!( Callback2 A B );
declare_callback!( Callback3 A B C );
declare_callback!( Callback4 A B C D );
declare_callback!( Callback5 A B C D E );
declare_callback!( Callback6 A B C D E F );
declare_callback!( Callback7 A B C D E F G );
declare_callback!( Callback8 A B C D E F G H );
declare_callback!( Callback9 A B C D E F G H I );
declare_callback!( Callback10 A B C D E F G H I J );

macro_rules! declare_closure {
    ( $closure:ident $cif:ident $callback:ident $( $param:ident )*) => {
        pub struct $closure<$( $param, )* R> {
            untyped: middle::Closure,
            _marker: PhantomData<fn($( $param, )*) -> R>,
        }

        impl<$( $param, )* R> $closure<$( $param, )* R> {
            pub fn new<U>(cif: $cif<$( $param, )* R>,
                          callback: $callback<U, $( $param, )* R>,
                          userdata: &U) -> Self
            {
                let callback: middle::Callback<U, R>
                    = unsafe { ::std::mem::transmute(callback) };
                let closure
                    = middle::Closure::new(cif.untyped,
                                           callback,
                                           userdata);
                $closure {
                    untyped: closure,
                    _marker: PhantomData,
                }
            }

            pub fn code_ptr(&self) -> extern "C" fn($( $param, )*) -> R {
                unsafe {
                    ::std::mem::transmute(self.untyped.code_ptr())
                }
            }
        }

        impl<$( $param: Copy, )* R> $closure<$( $param, )* R> {
            pub fn wrap<Callback>(cif: $cif<$( $param, )* R>,
                                  callback: Callback) -> Self
                where Callback: Fn($( $param, )*) -> R
            {
                Self::new(cif,
                          Self::static_callback,
                          &callback)
            }

            #[allow(non_snake_case)]
            extern "C" fn static_callback<Callback>
                (_cif:     &::low::ffi_cif,
                 result:   &mut R,
                 &($( &$param, )*):
                           &($( &$param, )*),
                 userdata: &Callback)
              where Callback: Fn($( $param, )*) -> R
            {
                *result = userdata($( $param, )*);
            }
        }
    }
}

declare_closure!(Closure0 Cif0 Callback0);
declare_closure!(Closure1 Cif1 Callback1 A);
declare_closure!(Closure2 Cif2 Callback2 A B);
declare_closure!(Closure3 Cif3 Callback3 A B C);
declare_closure!(Closure4 Cif4 Callback4 A B C D);
declare_closure!(Closure5 Cif5 Callback5 A B C D E);
declare_closure!(Closure6 Cif6 Callback6 A B C D E F);
declare_closure!(Closure7 Cif7 Callback7 A B C D E F G);
declare_closure!(Closure8 Cif8 Callback8 A B C D E F G H);
declare_closure!(Closure9 Cif9 Callback9 A B C D E F G H I);
declare_closure!(Closure10 Cif10 Callback10 A B C D E F G H I J);

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

    #[test]
    fn wrap() {
        let x: u64 = 1;
        let f = |y: u64, z: u64| x + y + z;

        let type_   = u64::get_type();
        let cif     = Cif2::new(type_.clone(), type_.clone(), type_.clone());
        let closure = Closure2::wrap(cif, f);

        assert_eq!(12, closure.code_ptr()(5, 6));
    }
}
<commit_msg>Type-driven CIF construction!<commit_after>use std::marker::PhantomData;

use middle;

pub mod types;
use self::types::*;

macro_rules! declare_cif {
    ( $typename:ident $( $param:ident )*) => {
        pub struct $typename<$( $param, )* R> {
            untyped: middle::Cif,
            _marker: PhantomData<fn($( $param, )*) -> R>,
        }

        impl<$( $param, )* R> $typename<$( $param, )* R> {
            #[allow(non_snake_case)]
            pub fn new($( $param: Type<$param>, )* result: Type<R>) -> Self {
                let cif = middle::Cif::new(vec![$( $param.into_untyped() ),*],
                                           result.into_untyped());
                $typename { untyped: cif, _marker: PhantomData }
            }
        }
    }
}

declare_cif!(Cif0);
declare_cif!(Cif1 A);
declare_cif!(Cif2 A B);
declare_cif!(Cif3 A B C);
declare_cif!(Cif4 A B C D);
declare_cif!(Cif5 A B C D E);
declare_cif!(Cif6 A B C D E F);
declare_cif!(Cif7 A B C D E F G);
declare_cif!(Cif8 A B C D E F G H);
declare_cif!(Cif9 A B C D E F G H I);
declare_cif!(Cif10 A B C D E F G H I J);

macro_rules! declare_callback {
    ( $typename:ident $( $param:ident )* ) => {
        pub type $typename<U, $( $param, )* R>
            = extern "C" fn(cif:      &::low::ffi_cif,
                            result:   &mut R,
                            args:     &($( &$param, )*),
                            userdata: &U);
    }
}

declare_callback!( Callback0 );
declare_callback!( Callback1 A );
declare_callback!( Callback2 A B );
declare_callback!( Callback3 A B C );
declare_callback!( Callback4 A B C D );
declare_callback!( Callback5 A B C D E );
declare_callback!( Callback6 A B C D E F );
declare_callback!( Callback7 A B C D E F G );
declare_callback!( Callback8 A B C D E F G H );
declare_callback!( Callback9 A B C D E F G H I );
declare_callback!( Callback10 A B C D E F G H I J );

macro_rules! declare_callback_mut {
    ( $typename:ident $( $param:ident )* ) => {
        pub type $typename<U, $( $param, )* R>
            = extern "C" fn(cif:      &::low::ffi_cif,
                            result:   &mut R,
                            args:     &($( &$param, )*),
                            userdata: &mut U);
    }
}

declare_callback_mut!( CallbackMut0 );
declare_callback_mut!( CallbackMut1 A );
declare_callback_mut!( CallbackMut2 A B );
declare_callback_mut!( CallbackMut3 A B C );
declare_callback_mut!( CallbackMut4 A B C D );
declare_callback_mut!( CallbackMut5 A B C D E );
declare_callback_mut!( CallbackMut6 A B C D E F );
declare_callback_mut!( CallbackMut7 A B C D E F G );
declare_callback_mut!( CallbackMut8 A B C D E F G H );
declare_callback_mut!( CallbackMut9 A B C D E F G H I );
declare_callback_mut!( CallbackMut10 A B C D E F G H I J );

macro_rules! declare_closure {
    ( $closure:ident $cif:ident $callback:ident $( $param:ident )*) => {
        pub struct $closure<$( $param, )* R> {
            untyped: middle::Closure,
            _marker: PhantomData<fn($( $param, )*) -> R>,
        }

        impl<$( $param, )* R> $closure<$( $param, )* R> {
            pub fn from_parts<U>(cif: $cif<$( $param, )* R>,
                                 callback: $callback<U, $( $param, )* R>,
                                 userdata: &U) -> Self
            {
                let callback: middle::Callback<U, R>
                    = unsafe { ::std::mem::transmute(callback) };
                let closure
                    = middle::Closure::new(cif.untyped,
                                           callback,
                                           userdata);
                $closure {
                    untyped: closure,
                    _marker: PhantomData,
                }
            }

            pub fn code_ptr(&self) -> extern "C" fn($( $param, )*) -> R {
                unsafe {
                    ::std::mem::transmute(self.untyped.code_ptr())
                }
            }
        }

        impl<$( $param: Copy, )* R> $closure<$( $param, )* R> {
            pub fn new<Callback>(cif: $cif<$( $param, )* R>,
                                 callback: Callback) -> Self
                where Callback: Fn($( $param, )*) -> R
            {
                Self::from_parts(cif,
                                 Self::static_callback,
                                 &callback)
            }

            #[allow(non_snake_case)]
            extern "C" fn static_callback<Callback>
                (_cif:     &::low::ffi_cif,
                 result:   &mut R,
                 &($( &$param, )*):
                           &($( &$param, )*),
                 userdata: &Callback)
              where Callback: Fn($( $param, )*) -> R
            {
                *result = userdata($( $param, )*);
            }
        }

        impl<$($param: Copy + FfiType,)* R: FfiType> $closure<$($param,)* R>
        {
            pub fn wrap<Callback>(callback: Callback) -> Self
                where Callback: Fn($( $param, )*) -> R
            {
                let cif = $cif::new($( $param::get_type(), )* R::get_type());
                Self::new(cif, callback)
            }
        }
    }
}

declare_closure!(Closure0 Cif0 Callback0);
declare_closure!(Closure1 Cif1 Callback1 A);
declare_closure!(Closure2 Cif2 Callback2 A B);
declare_closure!(Closure3 Cif3 Callback3 A B C);
declare_closure!(Closure4 Cif4 Callback4 A B C D);
declare_closure!(Closure5 Cif5 Callback5 A B C D E);
declare_closure!(Closure6 Cif6 Callback6 A B C D E F);
declare_closure!(Closure7 Cif7 Callback7 A B C D E F G);
declare_closure!(Closure8 Cif8 Callback8 A B C D E F G H);
declare_closure!(Closure9 Cif9 Callback9 A B C D E F G H I);
declare_closure!(Closure10 Cif10 Callback10 A B C D E F G H I J);

macro_rules! declare_closure_mut {
    ( $closure:ident $cif:ident $callback:ident $( $param:ident )*) => {
        pub struct $closure<$( $param, )* R> {
            untyped: middle::Closure,
            _marker: PhantomData<fn($( $param, )*) -> R>,
        }

        impl<$( $param, )* R> $closure<$( $param, )* R> {
            pub fn from_parts<U>(cif: $cif<$( $param, )* R>,
                                 callback: $callback<U, $( $param, )* R>,
                                 userdata: &mut U) -> Self
            {
                let callback: middle::Callback<U, R>
                    = unsafe { ::std::mem::transmute(callback) };
                let closure
                    = middle::Closure::new(cif.untyped,
                                           callback,
                                           userdata);
                $closure {
                    untyped: closure,
                    _marker: PhantomData,
                }
            }

            pub fn code_ptr(&self) -> extern "C" fn($( $param, )*) -> R {
                unsafe {
                    ::std::mem::transmute(self.untyped.code_ptr())
                }
            }
        }

        impl<$( $param: Copy, )* R> $closure<$( $param, )* R> {
            pub fn new<Callback>(cif: $cif<$( $param, )* R>,
                                 mut callback: Callback) -> Self
                where Callback: FnMut($( $param, )*) -> R
            {
                Self::from_parts(cif,
                                 Self::static_callback,
                                 &mut callback)
            }

            #[allow(non_snake_case)]
            extern "C" fn static_callback<Callback>
                (_cif:     &::low::ffi_cif,
                 result:   &mut R,
                 &($( &$param, )*):
                           &($( &$param, )*),
                 userdata: &mut Callback)
              where Callback: FnMut($( $param, )*) -> R
            {
                *result = userdata($( $param, )*);
            }
        }

        impl<$($param: Copy + FfiType,)* R: FfiType> $closure<$($param,)* R>
        {
            pub fn wrap<Callback>(callback: Callback) -> Self
                where Callback: FnMut($( $param, )*) -> R
            {
                let cif = $cif::new($( $param::get_type(), )* R::get_type());
                Self::new(cif, callback)
            }
        }
    }
}

declare_closure_mut!(ClosureMut0 Cif0 CallbackMut0);
declare_closure_mut!(ClosureMut1 Cif1 CallbackMut1 A);
declare_closure_mut!(ClosureMut2 Cif2 CallbackMut2 A B);
declare_closure_mut!(ClosureMut3 Cif3 CallbackMut3 A B C);
declare_closure_mut!(ClosureMut4 Cif4 CallbackMut4 A B C D);
declare_closure_mut!(ClosureMut5 Cif5 CallbackMut5 A B C D E);
declare_closure_mut!(ClosureMut6 Cif6 CallbackMut6 A B C D E F);
declare_closure_mut!(ClosureMut7 Cif7 CallbackMut7 A B C D E F G);
declare_closure_mut!(ClosureMut8 Cif8 CallbackMut8 A B C D E F G H);
declare_closure_mut!(ClosureMut9 Cif9 CallbackMut9 A B C D E F G H I);
declare_closure_mut!(ClosureMut10 Cif10 CallbackMut10 A B C D E F G H I J);

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

    #[test]
    fn new() {
        let x: u64 = 1;
        let f = |y: u64, z: u64| x + y + z;

        let type_   = u64::get_type();
        let cif     = Cif2::new(type_.clone(), type_.clone(), type_.clone());
        let closure = ClosureMut2::new(cif, f);

        assert_eq!(12, closure.code_ptr()(5, 6));
    }

    #[test]
    fn new_mut() {
        let mut x: u64 = 0;
        let f = |y: u64| { x += y; x };

        let type_   = u64::get_type();
        let cif     = Cif1::new(type_.clone(), type_.clone());
        let closure = ClosureMut1::new(cif, f);

        let counter = closure.code_ptr();
        assert_eq!(5, counter(5));
        assert_eq!(6, counter(1));
        assert_eq!(8, counter(2));
    }

    #[test]
    fn wrap() {
        let x: u64 = 1;
        let f = |y: u64, z: u64| x + y + z;

        let closure = ClosureMut2::wrap(f);

        assert_eq!(12, closure.code_ptr()(5, 6));
    }
}
<|endoftext|>


<commit_before>use platform::time::sleep_secs;
use platform::time::time_now;
use storage::Cache;

use super::Driver;
use super::cmd::Cmd;
use super::cmd::Get;
use super::cmd::Resp;
use super::cmd::Set;
use super::cmd::Stat;
use super::cmd::Value;

// Deconstruct Resp to a Value, panic if unsuccessful
fn get_resp_value(resp: Resp) -> Value {
    match resp {
        Resp::Value(value) => value,
        _ => {
            panic!("Could not match Resp::Value");
        }
    }
}

#[test]
fn test_cmd_set_and_get_a_key() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Try to retrieve a key not set
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Error);

    // Set a key
    let cmd = Cmd::Set(Set::new(key_name, 0, blob.clone()));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, get_resp_value(resp).data);
}

#[test]
fn test_cmd_stats() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    // Set a key
    let cmd = Cmd::Set(Set::new("x", 0, vec![8, 9]));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Run stats
    let cmd = Cmd::Stats;
    let resp = driver.run(cmd);
    let st_bytes = Stat::new("bytes", "3".to_string());
    let st_curr_items = Stat::new("curr_items", "1".to_string());
    let st_total_items = Stat::new("total_items", "1".to_string());
    assert_eq!(resp,
               Resp::Stats(vec![st_bytes, st_curr_items, st_total_items]));
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_cmd_relative_exptime() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Set a key with exptime of 1 second
    let cmd = Cmd::Set(Set::new(key_name, 1, blob.clone()));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it right away - succeeds
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, get_resp_value(resp).data);

    // sleep 1.5 secs - long enough to expire key
    sleep_secs(1.5);

    // Retrieve the key again - it's gone
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Error);
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_cmd_absolute_exptime() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];
    let exptime = time_now().round() as u32 + 1;

    // Set a key with exptime of 1 second
    let cmd = Cmd::Set(Set::new(key_name, exptime, blob.clone()));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it right away - succeeds
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, get_resp_value(resp).data);

    // sleep 2.5 secs - long enough to expire key
    sleep_secs(2.5);

    // Retrieve the key again - it's gone
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Error);
}
<commit_msg>fix stats test<commit_after>use platform::process::get_pid;
use platform::time::sleep_secs;
use platform::time::time_now;
use storage::Cache;

use super::Driver;
use super::cmd::Cmd;
use super::cmd::Get;
use super::cmd::Resp;
use super::cmd::Set;
use super::cmd::Stat;
use super::cmd::Value;

// Deconstruct Resp to a Value, panic if unsuccessful
fn get_resp_value(resp: Resp) -> Value {
    match resp {
        Resp::Value(value) => value,
        _ => {
            panic!("Could not match Resp::Value");
        }
    }
}

#[test]
fn test_cmd_set_and_get_a_key() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Try to retrieve a key not set
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Error);

    // Set a key
    let cmd = Cmd::Set(Set::new(key_name, 0, blob.clone()));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, get_resp_value(resp).data);
}

#[test]
fn test_cmd_stats() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    // Set a key
    let cmd = Cmd::Set(Set::new("x", 0, vec![8, 9]));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Run stats
    let cmd = Cmd::Stats;
    let resp = driver.run(cmd);

    let st_pid = Stat::new("pid", get_pid().to_string());
    let st_bytes = Stat::new("bytes", "3".to_string());
    let st_uptime = Stat::new("uptime", "0".to_string());
    let st_time = Stat::new("time", (time_now() as u64).to_string());
    let st_curr_items = Stat::new("curr_items", "1".to_string());
    let st_total_items = Stat::new("total_items", "1".to_string());

    assert_eq!(resp,
               Resp::Stats(vec![st_pid,
                                st_uptime,
                                st_time,
                                st_bytes,
                                st_curr_items,
                                st_total_items]));
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_cmd_relative_exptime() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Set a key with exptime of 1 second
    let cmd = Cmd::Set(Set::new(key_name, 1, blob.clone()));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it right away - succeeds
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, get_resp_value(resp).data);

    // sleep 1.5 secs - long enough to expire key
    sleep_secs(1.5);

    // Retrieve the key again - it's gone
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Error);
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_cmd_absolute_exptime() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];
    let exptime = time_now().round() as u32 + 1;

    // Set a key with exptime of 1 second
    let cmd = Cmd::Set(Set::new(key_name, exptime, blob.clone()));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it right away - succeeds
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, get_resp_value(resp).data);

    // sleep 2.5 secs - long enough to expire key
    sleep_secs(2.5);

    // Retrieve the key again - it's gone
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Error);
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate futures;

#[macro_use]
extern crate gluon_vm;
extern crate gluon;

use futures::{BoxFuture, Future, IntoFuture};
use futures::future::lazy;

use gluon::base::types::Type;
use gluon::vm::Error;
use gluon::vm::api::{FutureResult, VmType, FunctionRef, Userdata};
use gluon::vm::thread::{RootedThread, Thread, Traverseable, Root, RootStr};
use gluon::vm::types::VmInt;
use gluon::Compiler;
use gluon::import::Import;

fn load_script(vm: &Thread, filename: &str, input: &str) -> ::gluon::Result<()> {
    Compiler::new().load_script_async(vm, filename, input).sync_or_error()
}

fn make_vm() -> RootedThread {
    let vm = ::gluon::new_vm();
    let import = vm.get_macros().get("import");
    import.as_ref()
        .and_then(|import| import.downcast_ref::<Import>())
        .expect("Import macro")
        .add_path("..");
    vm
}

#[test]
fn call_function() {
    let _ = ::env_logger::init();
    let add10 = r"
let add10 : Int -> Int = \x -> x #Int+ 10 in add10
";
    let mul = r"
let mul : Float -> Float -> Float = \x y -> x #Float* y in mul
";
    let mut vm = make_vm();
    load_script(&mut vm, "add10", &add10).unwrap_or_else(|err| panic!("{}", err));
    load_script(&mut vm, "mul", &mul).unwrap_or_else(|err| panic!("{}", err));
    {
        let mut f: FunctionRef<fn(VmInt) -> VmInt> = vm.get_global("add10")
            .unwrap();
        let result = f.call(2).unwrap();
        assert_eq!(result, 12);
    }
    let mut f: FunctionRef<fn(f64, f64) -> f64> = vm.get_global("mul").unwrap();
    let result = f.call(4., 5.).unwrap();
    assert_eq!(result, 20.);
}

#[test]
fn root_data() {
    let _ = ::env_logger::init();

    #[derive(Debug)]
    struct Test(VmInt);
    impl Userdata for Test {}
    impl Traverseable for Test {}
    impl VmType for Test {
        type Type = Test;
    }

    let expr = r#"
\x -> test x 1
"#;
    let vm = make_vm();
    fn test(r: Root<Test>, i: VmInt) -> VmInt {
        r.0 + i
    }
    vm.register_type::<Test>("Test", &[])
        .unwrap_or_else(|_| panic!("Could not add type"));
    vm.define_global("test", primitive!(2 test)).unwrap();
    load_script(&vm, "script_fn", expr).unwrap_or_else(|err| panic!("{}", err));
    let mut script_fn: FunctionRef<fn(Test) -> VmInt> = vm.get_global("script_fn").unwrap();
    let result = script_fn.call(Test(123))
        .unwrap();
    assert_eq!(result, 124);
}

#[test]
fn root_string() {
    let _ = ::env_logger::init();

    let expr = r#"
test "hello"
"#;
    fn test(s: RootStr) -> String {
        let mut result = String::from(&s[..]);
        result.push_str(" world");
        result
    }

    let vm = make_vm();
    vm.define_global("test", primitive!(1 test)).unwrap();

    let result = Compiler::new()
        .run_expr::<String>(&vm, "<top>", expr)
        .unwrap();
    let expected = ("hello world".to_string(), Type::string());

    assert_eq!(result, expected);
}

#[test]
fn array() {
    let _ = ::env_logger::init();

    let expr = r#"
sum_bytes [100b, 42b, 3b, 15b]
"#;
    fn sum_bytes(s: &[u8]) -> u8 {
        s.iter().fold(0, |acc, b| acc + b)
    }

    let vm = make_vm();
    vm.define_global("sum_bytes", primitive!(1 sum_bytes)).unwrap();

    let result = Compiler::new()
        .run_expr::<u8>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    let expected = (160, Type::byte());

    assert_eq!(result, expected);
}

#[test]
fn return_finished_future() {
    let _ = ::env_logger::init();

    fn add(x: i32, y: i32) -> FutureResult<BoxFuture<i32, Error>> {
        FutureResult(Ok(x + y).into_future().boxed())
    }

    let expr = r#"
    add 1 2
"#;

    let vm = make_vm();
    vm.define_global("add", primitive!(2 add)).unwrap();

    let result = Compiler::new()
        .run_expr::<i32>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    let expected = (3, Type::int());

    assert_eq!(result, expected);
}

#[test]
fn return_delayed_future() {
    let _ = ::env_logger::init();

    fn poll_n(i: i32) -> FutureResult<BoxFuture<i32, Error>> {
        use std::thread::spawn;
        use futures::sync::oneshot::channel;

        let (ping_c, ping_p) = channel();
        let (pong_c, pong_p) = channel();
        spawn(move || {
            ping_p.wait().unwrap();
            pong_c.send(i);
        });
        FutureResult(lazy(move || {
                ping_c.send(());
                Ok(())
            })
            .and_then(|_| pong_p.map_err(|err| Error::Message(format!("{}", err))))
            .boxed())
    }

    let expr = r#"
    poll_n 3
"#;

    let vm = make_vm();
    vm.define_global("poll_n", primitive!(1 poll_n)).unwrap();

    let result = Compiler::new()
        .run_expr::<i32>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    let expected = (3, Type::int());

    assert_eq!(result, expected);
}

#[test]
fn io_future() {
    use gluon_vm::api::IO;

    let _ = ::env_logger::init();

    fn test(_: ()) -> FutureResult<BoxFuture<IO<i32>, Error>> {
        FutureResult(Ok(IO::Value(123)).into_future().boxed())
    }

    let expr = r#"
    let { applicative_IO, monad_IO }  = import! "std/prelude.glu"
    monad_IO.flat_map (\x -> applicative_IO.pure (x + 1)) (test ())
"#;

    let vm = make_vm();
    vm.define_global("test", primitive!(1 test)).unwrap();

    let result = Compiler::new()
        .run_io_expr::<IO<i32>>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));

    assert_eq!(result.0, IO::Value(124));
}
<commit_msg>refactor: Supress unused result warnings in tests<commit_after>extern crate env_logger;
extern crate futures;

#[macro_use]
extern crate gluon_vm;
extern crate gluon;

use futures::{BoxFuture, Future, IntoFuture};
use futures::future::lazy;

use gluon::base::types::Type;
use gluon::vm::Error;
use gluon::vm::api::{FutureResult, VmType, FunctionRef, Userdata};
use gluon::vm::thread::{RootedThread, Thread, Traverseable, Root, RootStr};
use gluon::vm::types::VmInt;
use gluon::Compiler;
use gluon::import::Import;

fn load_script(vm: &Thread, filename: &str, input: &str) -> ::gluon::Result<()> {
    Compiler::new().load_script_async(vm, filename, input).sync_or_error()
}

fn make_vm() -> RootedThread {
    let vm = ::gluon::new_vm();
    let import = vm.get_macros().get("import");
    import.as_ref()
        .and_then(|import| import.downcast_ref::<Import>())
        .expect("Import macro")
        .add_path("..");
    vm
}

#[test]
fn call_function() {
    let _ = ::env_logger::init();
    let add10 = r"
let add10 : Int -> Int = \x -> x #Int+ 10 in add10
";
    let mul = r"
let mul : Float -> Float -> Float = \x y -> x #Float* y in mul
";
    let mut vm = make_vm();
    load_script(&mut vm, "add10", &add10).unwrap_or_else(|err| panic!("{}", err));
    load_script(&mut vm, "mul", &mul).unwrap_or_else(|err| panic!("{}", err));
    {
        let mut f: FunctionRef<fn(VmInt) -> VmInt> = vm.get_global("add10")
            .unwrap();
        let result = f.call(2).unwrap();
        assert_eq!(result, 12);
    }
    let mut f: FunctionRef<fn(f64, f64) -> f64> = vm.get_global("mul").unwrap();
    let result = f.call(4., 5.).unwrap();
    assert_eq!(result, 20.);
}

#[test]
fn root_data() {
    let _ = ::env_logger::init();

    #[derive(Debug)]
    struct Test(VmInt);
    impl Userdata for Test {}
    impl Traverseable for Test {}
    impl VmType for Test {
        type Type = Test;
    }

    let expr = r#"
\x -> test x 1
"#;
    let vm = make_vm();
    fn test(r: Root<Test>, i: VmInt) -> VmInt {
        r.0 + i
    }
    vm.register_type::<Test>("Test", &[])
        .unwrap_or_else(|_| panic!("Could not add type"));
    vm.define_global("test", primitive!(2 test)).unwrap();
    load_script(&vm, "script_fn", expr).unwrap_or_else(|err| panic!("{}", err));
    let mut script_fn: FunctionRef<fn(Test) -> VmInt> = vm.get_global("script_fn").unwrap();
    let result = script_fn.call(Test(123))
        .unwrap();
    assert_eq!(result, 124);
}

#[test]
fn root_string() {
    let _ = ::env_logger::init();

    let expr = r#"
test "hello"
"#;
    fn test(s: RootStr) -> String {
        let mut result = String::from(&s[..]);
        result.push_str(" world");
        result
    }

    let vm = make_vm();
    vm.define_global("test", primitive!(1 test)).unwrap();

    let result = Compiler::new()
        .run_expr::<String>(&vm, "<top>", expr)
        .unwrap();
    let expected = ("hello world".to_string(), Type::string());

    assert_eq!(result, expected);
}

#[test]
fn array() {
    let _ = ::env_logger::init();

    let expr = r#"
sum_bytes [100b, 42b, 3b, 15b]
"#;
    fn sum_bytes(s: &[u8]) -> u8 {
        s.iter().fold(0, |acc, b| acc + b)
    }

    let vm = make_vm();
    vm.define_global("sum_bytes", primitive!(1 sum_bytes)).unwrap();

    let result = Compiler::new()
        .run_expr::<u8>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    let expected = (160, Type::byte());

    assert_eq!(result, expected);
}

#[test]
fn return_finished_future() {
    let _ = ::env_logger::init();

    fn add(x: i32, y: i32) -> FutureResult<BoxFuture<i32, Error>> {
        FutureResult(Ok(x + y).into_future().boxed())
    }

    let expr = r#"
    add 1 2
"#;

    let vm = make_vm();
    vm.define_global("add", primitive!(2 add)).unwrap();

    let result = Compiler::new()
        .run_expr::<i32>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    let expected = (3, Type::int());

    assert_eq!(result, expected);
}

#[test]
fn return_delayed_future() {
    let _ = ::env_logger::init();

    fn poll_n(i: i32) -> FutureResult<BoxFuture<i32, Error>> {
        use std::thread::spawn;
        use futures::sync::oneshot::channel;

        let (ping_c, ping_p) = channel();
        let (pong_c, pong_p) = channel();
        spawn(move || {
            ping_p.wait().unwrap();
            pong_c.send(i).unwrap();
        });
        FutureResult(lazy(move || {
                ping_c.send(()).unwrap();
                Ok(())
            })
            .and_then(|_| pong_p.map_err(|err| Error::Message(format!("{}", err))))
            .boxed())
    }

    let expr = r#"
    poll_n 3
"#;

    let vm = make_vm();
    vm.define_global("poll_n", primitive!(1 poll_n)).unwrap();

    let result = Compiler::new()
        .run_expr::<i32>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));
    let expected = (3, Type::int());

    assert_eq!(result, expected);
}

#[test]
fn io_future() {
    use gluon_vm::api::IO;

    let _ = ::env_logger::init();

    fn test(_: ()) -> FutureResult<BoxFuture<IO<i32>, Error>> {
        FutureResult(Ok(IO::Value(123)).into_future().boxed())
    }

    let expr = r#"
    let { applicative_IO, monad_IO }  = import! "std/prelude.glu"
    monad_IO.flat_map (\x -> applicative_IO.pure (x + 1)) (test ())
"#;

    let vm = make_vm();
    vm.define_global("test", primitive!(1 test)).unwrap();

    let result = Compiler::new()
        .run_io_expr::<IO<i32>>(&vm, "<top>", expr)
        .unwrap_or_else(|err| panic!("{}", err));

    assert_eq!(result.0, IO::Value(124));
}
<|endoftext|>


<commit_before>#[test]
#[ignore]
fn fmt() {
    if option_env!("RUSTC_TEST_SUITE").is_some() {
        return;
    }

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let dev_dir = root_dir.join("clippy_dev");
    let output = std::process::Command::new("cargo")
        .current_dir(dev_dir)
        .args(&["+nightly", "run", "--", "fmt", "--check"])
        .output()
        .unwrap();

    println!("status: {}", output.status);
    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(
        output.status.success(),
        "Formatting check failed. Run `./util/dev fmt` to update formatting."
    );
}
<commit_msg>Skip fmt test if rustfmt is unavailble<commit_after>use std::process::Command;

#[test]
#[ignore]
fn fmt() {
    if option_env!("RUSTC_TEST_SUITE").is_some() {
        return;
    }

    // Skip this test if rustup nightly is unavailable
    let rustup_output = Command::new("rustup")
        .args(&["component", "list", "--toolchain", "nightly"])
        .output()
        .unwrap();
    assert!(rustup_output.status.success());
    let component_output = String::from_utf8_lossy(&rustup_output.stdout);
    if !component_output.contains("rustfmt") {
        return;
    }

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let dev_dir = root_dir.join("clippy_dev");
    let output = Command::new("cargo")
        .current_dir(dev_dir)
        .args(&["+nightly", "run", "--", "fmt", "--check"])
        .output()
        .unwrap();

    println!("status: {}", output.status);
    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(
        output.status.success(),
        "Formatting check failed. Run `./util/dev fmt` to update formatting."
    );
}
<|endoftext|>


<commit_before>extern crate tinyexpr;

#[test]
fn check_basics() {
    assert_eq!(tinyexpr::interp("2*2").unwrap(), 4.0);
    assert_eq!(tinyexpr::interp("2+2").unwrap(), 4.0);
    assert_eq!(tinyexpr::interp("3-2").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("5%2").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("2+2*2").unwrap(), 6.0);
    assert_eq!(tinyexpr::interp("(2+2)*2").unwrap(), 8.0);
    assert_eq!(tinyexpr::interp("(2+2)*2/2").unwrap(), 4.0);
    assert_eq!(tinyexpr::interp("abs(-1)").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("sqrt(728*728)").unwrap(), 728.0);
    assert_eq!(tinyexpr::interp("pow(2.0, 3.0)").unwrap(), 8.0);
    assert_eq!(tinyexpr::interp("exp(1)").unwrap(), tinyexpr::interp("e").unwrap());
    assert_eq!(tinyexpr::interp("floor(3.1415)").unwrap(), 3.0);
    assert_eq!(tinyexpr::interp("ceil(3.1415)*floor(3.1415)").unwrap(), 12.0);
}

#[test]
fn check_constants() {
    assert_eq!(tinyexpr::interp("pi").unwrap(), 3.141592653589793);
    assert_eq!(tinyexpr::interp("e").unwrap(), 2.718281828459045);
}

#[test]
fn check_logarithms() {
    assert_eq!(tinyexpr::interp("ln(e)").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("log(10)").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("log10(10)").unwrap(), 1.0);
}

#[test]
fn check_trigs() {
    assert_eq!(tinyexpr::interp("2*1/sin(3.14/2)").unwrap().round(), 2.0);
    assert_eq!(tinyexpr::interp("asin(1)").unwrap(), tinyexpr::interp("pi/2").unwrap());
    assert_eq!(tinyexpr::interp("tan(pi)").unwrap().round(), 0.0);
    assert_eq!(tinyexpr::interp("atan(pi/2)").unwrap().round(), 1.0);
    assert_eq!(tinyexpr::interp("atan2(pi, 2)").unwrap().round(), 1.0);
    assert_eq!(tinyexpr::interp("cos(0)").unwrap().round(), 1.0);
    assert_eq!(tinyexpr::interp("acos(1)").unwrap(), 0.0);
}

#[test]
fn check_hyberbolic_trigs() {
    assert_eq!(tinyexpr::interp("sinh(0)").unwrap(), 0.0);
    assert_eq!(tinyexpr::interp("cosh(0)").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("tanh(10000)").unwrap(), 1.0);
}

#[test]
#[should_panic]
fn parse_error()
{
    tinyexpr::interp("atan(foo)").unwrap();
}
<commit_msg>added comma function to tests<commit_after>extern crate tinyexpr;

#[test]
fn check_basics() {
    assert_eq!(tinyexpr::interp("2*2").unwrap(), 4.0);
    assert_eq!(tinyexpr::interp("2+2").unwrap(), 4.0);
    assert_eq!(tinyexpr::interp("3-2").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("5%2").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("5^2").unwrap(), 25.0);
    assert_eq!(tinyexpr::interp("2+2*2").unwrap(), 6.0);
    assert_eq!(tinyexpr::interp("(2+2)*2").unwrap(), 8.0);
    assert_eq!(tinyexpr::interp("(2+2)*2/2").unwrap(), 4.0);
    assert_eq!(tinyexpr::interp("abs(-1)").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("sqrt(728*728)").unwrap(), 728.0);
    assert_eq!(tinyexpr::interp("pow(2.0, 3.0)").unwrap(), 8.0);
    assert_eq!(tinyexpr::interp("exp(1)").unwrap(), tinyexpr::interp("e").unwrap());
    assert_eq!(tinyexpr::interp("floor(3.1415)").unwrap(), 3.0);
    assert_eq!(tinyexpr::interp("ceil(3.1415)*floor(3.1415)").unwrap(), 12.0);
    assert_eq!(tinyexpr::interp("5,2").unwrap(), 2.0);
}

#[test]
fn check_constants() {
    assert_eq!(tinyexpr::interp("pi").unwrap(), 3.141592653589793);
    assert_eq!(tinyexpr::interp("e").unwrap(), 2.718281828459045);
}

#[test]
fn check_logarithms() {
    assert_eq!(tinyexpr::interp("ln(e)").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("log(10)").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("log10(10)").unwrap(), 1.0);
}

#[test]
fn check_trigs() {
    assert_eq!(tinyexpr::interp("2*1/sin(3.14/2)").unwrap().round(), 2.0);
    assert_eq!(tinyexpr::interp("asin(1)").unwrap(), tinyexpr::interp("pi/2").unwrap());
    assert_eq!(tinyexpr::interp("tan(pi)").unwrap().round(), 0.0);
    assert_eq!(tinyexpr::interp("atan(pi/2)").unwrap().round(), 1.0);
    assert_eq!(tinyexpr::interp("atan2(pi, 2)").unwrap().round(), 1.0);
    assert_eq!(tinyexpr::interp("cos(0)").unwrap().round(), 1.0);
    assert_eq!(tinyexpr::interp("acos(1)").unwrap(), 0.0);
}

#[test]
fn check_hyberbolic_trigs() {
    assert_eq!(tinyexpr::interp("sinh(0)").unwrap(), 0.0);
    assert_eq!(tinyexpr::interp("cosh(0)").unwrap(), 1.0);
    assert_eq!(tinyexpr::interp("tanh(10000)").unwrap(), 1.0);
}

#[test]
#[should_panic]
fn parse_error()
{ tinyexpr::interp("atan(foo)").unwrap(); }
<|endoftext|>


<commit_before>#![deny(warnings)]
extern crate inflector;

use inflector::Inflector;

macro_rules! str_tests {
    ( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => {
        $(
            #[test]
            fn $test_name() {
                assert_eq!($to_cast.$imp_trait(), $casted)
            }
        )*
    }
}

macro_rules! string_tests {
    ( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => {
        $(
            #[test]
            fn $test_name() {
                assert_eq!($to_cast.to_string().$imp_trait(), $casted)
            }
        )*
    }
}

macro_rules! number_tests {
    ( $($test_name:ident => $imp_trait:ident => $typ:ident => $to_cast:expr => $casted:expr), *) => {
        $(
            #[test]
            fn $test_name() {
                let to_cast: $typ = $to_cast;
                assert_eq!(to_cast.to_string().$imp_trait(), $casted)
            }
        )*
    }
}

macro_rules! benchmarks {
    ( $($test_name:ident => $imp_trait:ident => $to_cast:expr), *) => {
        $(
            #[bench]
            fn $test_name(b: &mut Bencher) {
                b.iter(|| {
                    $to_cast.$imp_trait()
                });
            }
        )*
    }
}

#[cfg(all(feature = "unstable", test))]
mod tests {
    extern crate test;
    use self::test::Bencher;

    benchmarks![
        benchmark_str_to_class => to_class_case => "foo",
        benchmark_str_is_class => is_class_case => "Foo",
        benchmark_str_to_camel => to_camel_case => "foo_bar",
        benchmark_str_is_camel => is_camel_case => "fooBar",
        benchmark_str_to_table => to_table_case => "fooBar",
        benchmark_str_is_table => is_table_case => "foo_bars",
        benchmark_str_to_screaming_snake => to_screaming_snake_case => "fooBar",
        benchmark_str_is_screaming_snake => is_screaming_snake_case => "FOO_BAR",
        benchmark_str_to_snake => to_snake_case => "fooBar",
        benchmark_str_is_snake => is_snake_case => "foo_bar",
        benchmark_str_to_kebab => to_kebab_case => "fooBar",
        benchmark_str_is_kebab => is_kebab_case => "foo-bar",
        benchmark_str_to_train => to_train_case => "fooBar",
        benchmark_str_is_train => is_train_case => "Foo-Bar",
        benchmark_str_to_sentence => to_sentence_case => "fooBar",
        benchmark_str_is_sentence => is_sentence_case => "Foo bar",
        benchmark_str_to_title => to_title_case => "fooBar",
        benchmark_str_is_title => is_title_case => "Foo Bar",
        benchmark_str_ordinalize  => ordinalize => "1",
        benchmark_str_deordinalize  => deordinalize => "1st",
        benchmark_str_to_foreign_key => to_foreign_key => "Foo::Bar",
        benchmark_str_is_foreign_key => is_foreign_key => "bar_id",
        benchmark_str_demodulize => demodulize => "Foo::Bar",
        benchmark_str_deconstantize => deconstantize => "Foo::Bar",
        benchmark_str_pluralize => to_plural => "crate",
        benchmark_str_singular => to_singular => "crates",
    ];
}

str_tests![
    str_to_class => to_class_case => "foo" => "Foo".to_string(),
    str_is_class => is_class_case => "Foo" => true,
    str_to_camel => to_camel_case => "foo_bar" => "fooBar".to_string(),
    str_is_camel => is_camel_case => "fooBar" => true,
    str_to_table => to_table_case => "fooBar" => "foo_bars".to_string(),
    str_is_table => is_table_case => "foo_bars" => true,
    str_to_screaming_snake => to_screaming_snake_case => "fooBar" => "FOO_BAR".to_string(),
    str_is_screaming_snake => is_screaming_snake_case => "FOO_BAR" => true,
    str_to_snake => to_snake_case => "fooBar" => "foo_bar".to_string(),
    str_is_snake => is_snake_case => "foo_bar" => true,
    str_to_kebab => to_kebab_case => "fooBar" => "foo-bar".to_string(),
    str_is_kebab => is_kebab_case => "foo-bar" => true,
    str_to_train => to_train_case => "fooBar" => "Foo-Bar".to_string(),
    str_is_train => is_train_case => "Foo-Bar" => true,
    str_to_sentence => to_sentence_case => "fooBar" => "Foo bar".to_string(),
    str_is_sentence => is_sentence_case => "Foo bar" => true,
    str_to_title => to_title_case => "fooBar" => "Foo Bar".to_string(),
    str_is_title => is_title_case => "Foo Bar" => true,
    str_ordinalize  => ordinalize => "1" => "1st".to_string(),
    str_deordinalize  => deordinalize => "1st" => "1".to_string(),
    str_to_foreign_key => to_foreign_key => "Foo::Bar" => "bar_id".to_string(),
    str_is_foreign_key => is_foreign_key => "bar_id" => true,
    str_demodulize => demodulize => "Foo::Bar" => "Bar".to_string(),
    str_deconstantize => deconstantize => "Foo::Bar" => "Foo".to_string(),
    str_pluralize => to_plural => "crate" => "crates".to_string(),
    str_singular => to_singular => "crates" => "crate".to_string()
];

string_tests![
    string_to_class => to_class_case => "foo" => "Foo".to_string(),
    string_is_class => is_class_case => "Foo" => true,
    string_to_camel => to_camel_case => "foo_bar" => "fooBar".to_string(),
    string_is_camel => is_camel_case => "fooBar" => true,
    string_to_table => to_table_case => "fooBar" => "foo_bars".to_string(),
    string_is_table => is_table_case => "foo_bars" => true,
    string_to_screaming_snake => to_screaming_snake_case => "fooBar" => "FOO_BAR".to_string(),
    string_is_screaming_snake => is_screaming_snake_case => "FOO_BAR" => true,
    string_to_snake => to_snake_case => "fooBar" => "foo_bar".to_string(),
    string_is_snake => is_snake_case => "foo_bar" => true,
    string_to_kebab => to_kebab_case => "fooBar" => "foo-bar".to_string(),
    string_is_kebab => is_kebab_case => "foo-bar" => true,
    string_to_train => to_train_case => "fooBar" => "Foo-Bar".to_string(),
    string_is_train => is_train_case => "Foo-Bar" => true,
    string_to_sentence => to_sentence_case => "fooBar" => "Foo bar".to_string(),
    string_is_sentence => is_sentence_case => "Foo bar" => true,
    string_to_title => to_title_case => "fooBar" => "Foo Bar".to_string(),
    string_is_title => is_title_case => "Foo Bar" => true,
    string_ordinalize  => ordinalize => "1" => "1st".to_string(),
    string_deordinalize  => deordinalize => "1st" => "1".to_string(),
    string_to_foreign_key => to_foreign_key => "Foo::Bar" => "bar_id".to_string(),
    string_is_foreign_key => is_foreign_key => "bar_id" => true,
    string_demodulize => demodulize => "Foo::Bar" => "Bar".to_string(),
    string_deconstantize => deconstantize => "Foo::Bar" => "Foo".to_string(),
    string_pluralize => to_plural => "crate" => "crates".to_string(),
    string_singular => to_singular => "crates" => "crate".to_string()
];

number_tests![
    i8_ordinalize   => ordinalize => i8  => 1 => "1st".to_string(),
    i16_ordinalize  => ordinalize => i16 => 1 => "1st".to_string(),
    i32_ordinalize  => ordinalize => i32 => 1 => "1st".to_string(),
    i64_ordinalize  => ordinalize => i64 => 1 => "1st".to_string(),
    u8_ordinalize   => ordinalize => u8  => 1 => "1st".to_string(),
    u16_ordinalize  => ordinalize => u16 => 1 => "1st".to_string(),
    u32_ordinalize  => ordinalize => u32 => 1 => "1st".to_string(),
    u64_ordinalize  => ordinalize => u64 => 1 => "1st".to_string(),
    isize_ordinalize  => ordinalize => isize => 1 => "1st".to_string(),
    usize_ordinalize  => ordinalize => usize => 1 => "1st".to_string(),
    f32_ordinalize  => ordinalize => f32 => 1.0 => "1st".to_string(),
    f64_ordinalize  => ordinalize => f64 => 1.0 => "1st".to_string()
];
<commit_msg>Removed extra benchmark code that was moved out<commit_after>#![deny(warnings)]
extern crate inflector;

use inflector::Inflector;

macro_rules! str_tests {
    ( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => {
        $(
            #[test]
            fn $test_name() {
                assert_eq!($to_cast.$imp_trait(), $casted)
            }
        )*
    }
}

macro_rules! string_tests {
    ( $($test_name:ident => $imp_trait:ident => $to_cast:expr => $casted:expr), *) => {
        $(
            #[test]
            fn $test_name() {
                assert_eq!($to_cast.to_string().$imp_trait(), $casted)
            }
        )*
    }
}

macro_rules! number_tests {
    ( $($test_name:ident => $imp_trait:ident => $typ:ident => $to_cast:expr => $casted:expr), *) => {
        $(
            #[test]
            fn $test_name() {
                let to_cast: $typ = $to_cast;
                assert_eq!(to_cast.to_string().$imp_trait(), $casted)
            }
        )*
    }
}

str_tests![
    str_to_class => to_class_case => "foo" => "Foo".to_string(),
    str_is_class => is_class_case => "Foo" => true,
    str_to_camel => to_camel_case => "foo_bar" => "fooBar".to_string(),
    str_is_camel => is_camel_case => "fooBar" => true,
    str_to_table => to_table_case => "fooBar" => "foo_bars".to_string(),
    str_is_table => is_table_case => "foo_bars" => true,
    str_to_screaming_snake => to_screaming_snake_case => "fooBar" => "FOO_BAR".to_string(),
    str_is_screaming_snake => is_screaming_snake_case => "FOO_BAR" => true,
    str_to_snake => to_snake_case => "fooBar" => "foo_bar".to_string(),
    str_is_snake => is_snake_case => "foo_bar" => true,
    str_to_kebab => to_kebab_case => "fooBar" => "foo-bar".to_string(),
    str_is_kebab => is_kebab_case => "foo-bar" => true,
    str_to_train => to_train_case => "fooBar" => "Foo-Bar".to_string(),
    str_is_train => is_train_case => "Foo-Bar" => true,
    str_to_sentence => to_sentence_case => "fooBar" => "Foo bar".to_string(),
    str_is_sentence => is_sentence_case => "Foo bar" => true,
    str_to_title => to_title_case => "fooBar" => "Foo Bar".to_string(),
    str_is_title => is_title_case => "Foo Bar" => true,
    str_ordinalize  => ordinalize => "1" => "1st".to_string(),
    str_deordinalize  => deordinalize => "1st" => "1".to_string(),
    str_to_foreign_key => to_foreign_key => "Foo::Bar" => "bar_id".to_string(),
    str_is_foreign_key => is_foreign_key => "bar_id" => true,
    str_demodulize => demodulize => "Foo::Bar" => "Bar".to_string(),
    str_deconstantize => deconstantize => "Foo::Bar" => "Foo".to_string(),
    str_pluralize => to_plural => "crate" => "crates".to_string(),
    str_singular => to_singular => "crates" => "crate".to_string()
];

string_tests![
    string_to_class => to_class_case => "foo" => "Foo".to_string(),
    string_is_class => is_class_case => "Foo" => true,
    string_to_camel => to_camel_case => "foo_bar" => "fooBar".to_string(),
    string_is_camel => is_camel_case => "fooBar" => true,
    string_to_table => to_table_case => "fooBar" => "foo_bars".to_string(),
    string_is_table => is_table_case => "foo_bars" => true,
    string_to_screaming_snake => to_screaming_snake_case => "fooBar" => "FOO_BAR".to_string(),
    string_is_screaming_snake => is_screaming_snake_case => "FOO_BAR" => true,
    string_to_snake => to_snake_case => "fooBar" => "foo_bar".to_string(),
    string_is_snake => is_snake_case => "foo_bar" => true,
    string_to_kebab => to_kebab_case => "fooBar" => "foo-bar".to_string(),
    string_is_kebab => is_kebab_case => "foo-bar" => true,
    string_to_train => to_train_case => "fooBar" => "Foo-Bar".to_string(),
    string_is_train => is_train_case => "Foo-Bar" => true,
    string_to_sentence => to_sentence_case => "fooBar" => "Foo bar".to_string(),
    string_is_sentence => is_sentence_case => "Foo bar" => true,
    string_to_title => to_title_case => "fooBar" => "Foo Bar".to_string(),
    string_is_title => is_title_case => "Foo Bar" => true,
    string_ordinalize  => ordinalize => "1" => "1st".to_string(),
    string_deordinalize  => deordinalize => "1st" => "1".to_string(),
    string_to_foreign_key => to_foreign_key => "Foo::Bar" => "bar_id".to_string(),
    string_is_foreign_key => is_foreign_key => "bar_id" => true,
    string_demodulize => demodulize => "Foo::Bar" => "Bar".to_string(),
    string_deconstantize => deconstantize => "Foo::Bar" => "Foo".to_string(),
    string_pluralize => to_plural => "crate" => "crates".to_string(),
    string_singular => to_singular => "crates" => "crate".to_string()
];

number_tests![
    i8_ordinalize   => ordinalize => i8  => 1 => "1st".to_string(),
    i16_ordinalize  => ordinalize => i16 => 1 => "1st".to_string(),
    i32_ordinalize  => ordinalize => i32 => 1 => "1st".to_string(),
    i64_ordinalize  => ordinalize => i64 => 1 => "1st".to_string(),
    u8_ordinalize   => ordinalize => u8  => 1 => "1st".to_string(),
    u16_ordinalize  => ordinalize => u16 => 1 => "1st".to_string(),
    u32_ordinalize  => ordinalize => u32 => 1 => "1st".to_string(),
    u64_ordinalize  => ordinalize => u64 => 1 => "1st".to_string(),
    isize_ordinalize  => ordinalize => isize => 1 => "1st".to_string(),
    usize_ordinalize  => ordinalize => usize => 1 => "1st".to_string(),
    f32_ordinalize  => ordinalize => f32 => 1.0 => "1st".to_string(),
    f64_ordinalize  => ordinalize => f64 => 1.0 => "1st".to_string()
];
<|endoftext|>