<commit_before>#![allow(clippy::borrowed_box)]

use crate::error::*;

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

use crate::common::*;

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

/// Events processed by a demuxer analyzing a source.
#[non_exhaustive]
#[derive(Clone, Debug)]
pub enum Event {
    /// A new packet is found by a demuxer.
    NewPacket(Packet),
    /// A new stream is found by a demuxer.
    NewStream(Stream),
    /// More data are needed by a demuxer to complete its operations.
    MoreDataNeeded(usize),
    /// Event not processable by a demuxer.
    ///
    /// Demux the next event.
    Continue,
    /// End of File.
    ///
    /// Stop demuxing data.
    Eof,
}

/// Used to implement demuxing operations.
pub trait Demuxer: Send + Sync {
    /// Reads stream headers and global information from a data structure
    /// implementing the `Buffered` trait.
    ///
    /// Global information are saved into a `GlobalInfo` structure.
    fn read_headers(&mut self, buf: &mut dyn Buffered, info: &mut GlobalInfo) -> Result<SeekFrom>;
    /// Reads an event from a data structure implementing the `Buffered` trait.
    fn read_event(&mut self, buf: &mut dyn Buffered) -> Result<(SeekFrom, Event)>;
}

/// Auxiliary structure to encapsulate a demuxer object and
/// its additional data.
pub struct Context<D: Demuxer, R: Buffered> {
    demuxer: D,
    reader: R,
    /// Global media file information.
    pub info: GlobalInfo,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Arc<dyn Any + Send + Sync>>,
}

impl<D: Demuxer, R: Buffered> Context<D, R> {
    /// Creates a new `Context` instance.
    pub fn new(demuxer: D, reader: R) -> Self {
        Context {
            demuxer,
            reader,
            info: GlobalInfo {
                duration: None,
                timebase: None,
                streams: Vec::with_capacity(2),
            },
            user_private: None,
        }
    }

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

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

    /// Reads stream headers and global information from a data source.
    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 demux = &mut self.demuxer;

        let res = demux.read_event(&mut 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(st) = self
                            .info
                            .streams
                            .iter()
                            .find(|s| s.index as isize == pkt.stream_index)
                        {
                            pkt.t.timebase = Some(st.timebase);
                        }
                    }
                }
                Ok(event)
            }
        }
    }

    /// Reads an event from a data source.
    pub fn read_event(&mut self) -> Result<Event> {
        // 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();

                        // we might have sent MoreDatNeeded(0) to request a new call
                        if len >= needed {
                            continue;
                        }
                        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),
            }
        }
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own demuxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Demuxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new demuxer.
pub trait Descriptor {
    type OutputDemuxer: Demuxer;

    /// Creates a new demuxer for the requested format.
    fn create(&self) -> Self::OutputDemuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;

    /// Returns a score which represents how much the input data are associated
    /// to a format.
    fn probe(&self, data: &[u8]) -> u8;
}

/// Maximum data size to probe a format.
pub const PROBE_DATA: usize = 4 * 1024;

/// Data whose probe score is equal or greater than the value of this constant
/// surely is associated to the format currently being analyzed.
pub const PROBE_SCORE_EXTENSION: u8 = 50;

/// Used to define different ways to probe a format.
pub trait Probe<T: Descriptor + ?Sized> {
    /// Probes whether the input data is associated to a determined format.
    fn probe(&self, data: &[u8]) -> Option<&'static T>;
}

impl<'a, T: Descriptor + ?Sized> Probe<T> for [&'static T] {
    fn probe(&self, data: &[u8]) -> Option<&'static T> {
        let mut max = u8::min_value();
        let mut candidate: Option<&'static T> = 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 crate::data::packet::Packet;
    use std::io::SeekFrom;

    struct DummyDes {
        d: Descr,
    }

    struct DummyDemuxer {}

    impl Demuxer for DummyDemuxer {
        fn read_headers(
            &mut self,
            buf: &mut dyn 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: &mut dyn Buffered) -> Result<(SeekFrom, Event)> {
            let size = 2;
            let len = buf.data().len();
            if size > len {
                Err(Error::MoreDataNeeded(size - len))
            } else {
                debug!("{:?}", 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),
                }
            }
        }
    }

    impl Descriptor for DummyDes {
        type OutputDemuxer = DummyDemuxer;

        fn create(&self) -> Self::OutputDemuxer {
            DummyDemuxer {}
        }
        fn describe<'a>(&'_ self) -> &'_ Descr {
            &self.d
        }
        fn probe(&self, data: &[u8]) -> u8 {
            match data {
                b"dummy" => 100,
                _ => 0,
            }
        }
    }

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

    #[test]
    fn probe() {
        let demuxers: &[&'static dyn Descriptor<OutputDemuxer = DummyDemuxer>] = &[DUMMY_DES];

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

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

    #[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, 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, r);

        c.read_headers().unwrap();

        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
    }
}
<commit_msg>format: Add an API to get the underlying demuxer<commit_after>#![allow(clippy::borrowed_box)]

use crate::error::*;

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

use crate::common::*;

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

/// Events processed by a demuxer analyzing a source.
#[non_exhaustive]
#[derive(Clone, Debug)]
pub enum Event {
    /// A new packet is found by a demuxer.
    NewPacket(Packet),
    /// A new stream is found by a demuxer.
    NewStream(Stream),
    /// More data are needed by a demuxer to complete its operations.
    MoreDataNeeded(usize),
    /// Event not processable by a demuxer.
    ///
    /// Demux the next event.
    Continue,
    /// End of File.
    ///
    /// Stop demuxing data.
    Eof,
}

/// Used to implement demuxing operations.
pub trait Demuxer: Send + Sync {
    /// Reads stream headers and global information from a data structure
    /// implementing the `Buffered` trait.
    ///
    /// Global information are saved into a `GlobalInfo` structure.
    fn read_headers(&mut self, buf: &mut dyn Buffered, info: &mut GlobalInfo) -> Result<SeekFrom>;
    /// Reads an event from a data structure implementing the `Buffered` trait.
    fn read_event(&mut self, buf: &mut dyn Buffered) -> Result<(SeekFrom, Event)>;
}

/// Auxiliary structure to encapsulate a demuxer object and
/// its additional data.
pub struct Context<D: Demuxer, R: Buffered> {
    demuxer: D,
    reader: R,
    /// Global media file information.
    pub info: GlobalInfo,
    /// User private data.
    ///
    /// This data cannot be cloned.
    pub user_private: Option<Arc<dyn Any + Send + Sync>>,
}

impl<D: Demuxer, R: Buffered> Context<D, R> {
    /// Creates a new `Context` instance.
    pub fn new(demuxer: D, reader: R) -> Self {
        Context {
            demuxer,
            reader,
            info: GlobalInfo {
                duration: None,
                timebase: None,
                streams: Vec::with_capacity(2),
            },
            user_private: None,
        }
    }

    /// Returns the underlying demuxer.
    pub fn demuxer(&self) -> &D {
        &self.demuxer
    }

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

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

    /// Reads stream headers and global information from a data source.
    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 demux = &mut self.demuxer;

        let res = demux.read_event(&mut 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(st) = self
                            .info
                            .streams
                            .iter()
                            .find(|s| s.index as isize == pkt.stream_index)
                        {
                            pkt.t.timebase = Some(st.timebase);
                        }
                    }
                }
                Ok(event)
            }
        }
    }

    /// Reads an event from a data source.
    pub fn read_event(&mut self) -> Result<Event> {
        // 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();

                        // we might have sent MoreDatNeeded(0) to request a new call
                        if len >= needed {
                            continue;
                        }
                        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),
            }
        }
    }
}

/// Format descriptor.
///
/// Contains information on a format and its own demuxer.
#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    /// Format name.
    pub name: &'static str,
    /// Demuxer name.
    pub demuxer: &'static str,
    /// Format description.
    pub description: &'static str,
    /// Format media file extensions.
    pub extensions: &'static [&'static str],
    /// Format MIME.
    pub mime: &'static [&'static str],
}

/// Used to get a format descriptor and create a new demuxer.
pub trait Descriptor {
    type OutputDemuxer: Demuxer;

    /// Creates a new demuxer for the requested format.
    fn create(&self) -> Self::OutputDemuxer;
    /// Returns the descriptor of a format.
    fn describe(&self) -> &Descr;

    /// Returns a score which represents how much the input data are associated
    /// to a format.
    fn probe(&self, data: &[u8]) -> u8;
}

/// Maximum data size to probe a format.
pub const PROBE_DATA: usize = 4 * 1024;

/// Data whose probe score is equal or greater than the value of this constant
/// surely is associated to the format currently being analyzed.
pub const PROBE_SCORE_EXTENSION: u8 = 50;

/// Used to define different ways to probe a format.
pub trait Probe<T: Descriptor + ?Sized> {
    /// Probes whether the input data is associated to a determined format.
    fn probe(&self, data: &[u8]) -> Option<&'static T>;
}

impl<'a, T: Descriptor + ?Sized> Probe<T> for [&'static T] {
    fn probe(&self, data: &[u8]) -> Option<&'static T> {
        let mut max = u8::min_value();
        let mut candidate: Option<&'static T> = 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 crate::data::packet::Packet;
    use std::io::SeekFrom;

    struct DummyDes {
        d: Descr,
    }

    struct DummyDemuxer {}

    impl Demuxer for DummyDemuxer {
        fn read_headers(
            &mut self,
            buf: &mut dyn 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: &mut dyn Buffered) -> Result<(SeekFrom, Event)> {
            let size = 2;
            let len = buf.data().len();
            if size > len {
                Err(Error::MoreDataNeeded(size - len))
            } else {
                debug!("{:?}", 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),
                }
            }
        }
    }

    impl Descriptor for DummyDes {
        type OutputDemuxer = DummyDemuxer;

        fn create(&self) -> Self::OutputDemuxer {
            DummyDemuxer {}
        }
        fn describe<'a>(&'_ self) -> &'_ Descr {
            &self.d
        }
        fn probe(&self, data: &[u8]) -> u8 {
            match data {
                b"dummy" => 100,
                _ => 0,
            }
        }
    }

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

    #[test]
    fn probe() {
        let demuxers: &[&'static dyn Descriptor<OutputDemuxer = DummyDemuxer>] = &[DUMMY_DES];

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

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

    #[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, 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, 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 error::*;

use buffer::Buffered;
use std::io::SeekFrom;

use common::*;

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

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

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,
}

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),
            },
        }
    }

    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 {
            println!("Filling");
            // 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>format: Drop a pointless debug printf<commit_after>use error::*;

use buffer::Buffered;
use std::io::SeekFrom;

use common::*;

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

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

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,
}

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),
            },
        }
    }

    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());
    }
}
<|endoftext|>


<commit_before>use enum_primitive::FromPrimitive;

use platform::random_i32;

// There doesn't seem to be a convenient way to get the "size" or
// "range" of an enum's possible values, so we'll make a trait for
// that here.
//
// Ideally we could populate it automatically through a macro, but
// for now we'll just implement it manually for all our enums.
pub trait SizedEnum : FromPrimitive {
  fn size() -> usize;

  fn random() -> Self {
    loop {
      let r = random_i32(0, Self::size() as i32);
      match Self::from_i32(r) {
        Some(t) => { return t; },
        None => {}
      }
    }
  }
}
<commit_msg>Added SizedEnum::iter().<commit_after>use std::marker::PhantomData;
use enum_primitive::FromPrimitive;

use platform::random_i32;

// There doesn't seem to be a convenient way to get the "size" or
// "range" of an enum's possible values, so we'll make a trait for
// that here.
//
// Ideally we could populate it automatically through a macro, but
// for now we'll just implement it manually for all our enums.
pub trait SizedEnum : FromPrimitive {
  fn size() -> usize;

  fn iter() -> SizedEnumIterator<Self> {
    SizedEnumIterator::new()
  }

  fn random() -> Self {
    loop {
      let r = random_i32(0, Self::size() as i32);
      match Self::from_i32(r) {
        Some(t) => { return t; },
        None => {}
      }
    }
  }
}

pub struct SizedEnumIterator<T: FromPrimitive> {
  current: i32,
  phantom: PhantomData<T>,
}

impl<T: FromPrimitive> SizedEnumIterator<T> {
  fn new() -> Self {
    Self { current: 0, phantom: PhantomData }
  }
}

impl<T: FromPrimitive> Iterator for SizedEnumIterator<T> {
  type Item = T;

  fn next(&mut self) -> Option<T> {
    T::from_i32(self.current)
  }
}
<|endoftext|>


<commit_before>pub mod ffi;
pub mod frame;

use std::mem;
use std::ptr;
use std::ffi::CString;

use error::{RuntimeError, ErrorKind, VoidResult};

use super::utils::fn_ptr::FnPtrLoader;

#[inline]
pub fn load<T: FnPtrLoader>(loader: &T) {
   unsafe {
      ffi::load_functions(loader)
   };
}

#[inline]
fn gl_error<T>(message: &str) -> Result<T, RuntimeError> {
   Err(
      RuntimeError::new(
         ErrorKind::GL,
         message.to_string()
      )
   )
}

#[inline]
fn gl_result<T>(value: T) -> Result<T, RuntimeError> {
   let result = unsafe {
      ffi::glGetError()
   };

   match result {
      ffi::GL_NO_ERROR => Ok(value),
      ffi::GL_INVALID_ENUM => gl_error(
         "An unacceptable value is specified for an enumerated argument"
      ),
      ffi::GL_INVALID_VALUE => gl_error(
         "A numeric argument is out of range"
      ),
      ffi::GL_INVALID_OPERATION => gl_error(
         "The specified operation is not allowed in the current state"
      ),
      ffi::GL_INVALID_FRAMEBUFFER_OPERATION => gl_error(
         "The framebuffer object is not complete"
      ),
      ffi::GL_OUT_OF_MEMORY => gl_error(
         "There is not enough memory left to execute the command"
      ),
      ffi::GL_STACK_UNDERFLOW => gl_error(
         "Performing an operation that would cause an internal stack to underflow"
      ),
      ffi::GL_STACK_OVERFLOW => gl_error(
         "Performing an operation that would cause an internal stack to overflow"
      ),
      _ => gl_error("Unknown OpenGL error")
   }
}

#[inline]
pub fn reset_pixelstore_alignment() -> VoidResult {
   unsafe {
      ffi::glPixelStorei(ffi::GL_UNPACK_ALIGNMENT, 1);
   }

   gl_result(())
}

#[inline]
pub fn enable_framebuffer_srgb() -> VoidResult {
   unsafe {
      ffi::glEnable(ffi::GL_FRAMEBUFFER_SRGB);
   }

   gl_result(())
}

#[inline]
pub fn viewport(width: u32, height: u32) -> VoidResult {
   unsafe {
      ffi::glViewport(0, 0, width as ffi::GLsizei, height as ffi::GLsizei)
   }

   gl_result(())
}

#[inline]
pub fn vertex_attrib_pointer(
   index: ffi::GLuint, size: ffi::GLint, buffer: &[ffi::GLfloat]
) -> VoidResult {

   unsafe {
      ffi::glVertexAttribPointer(
         index,
         size,
         ffi::GL_FLOAT,
         ffi::GL_FALSE,
         0,
         buffer.as_ptr() as *const ffi::GLvoid
      )
   }

   gl_result(())
}

#[inline]
pub fn enable_vertex_attrib_array(index: ffi::GLuint) -> VoidResult {
   unsafe {
      ffi::glEnableVertexAttribArray(index)
   }

   gl_result(())
}

#[inline]
pub fn uniform_value_1i(location: ffi::GLint, value: ffi::GLint) -> VoidResult {
   unsafe {
      ffi::glUniform1i(location, value)
   }

   gl_result(())
}

#[inline]
pub fn draw_arrays(count: ffi::GLsizei) -> VoidResult {
   unsafe {
      ffi::glDrawArrays(ffi::GL_TRIANGLE_STRIP, 0, count)
   }

   gl_result(())
}

pub struct Texture {
   pub name: ffi::GLuint,
}

impl Texture {
   pub fn new(width: u32, height: u32) -> Result<Self, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenTextures(1, &mut name);

         ffi::glBindTexture(ffi::GL_TEXTURE_2D, name);

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_WRAP_S,
            ffi::GL_CLAMP_TO_EDGE as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_WRAP_T,
            ffi::GL_CLAMP_TO_EDGE as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_MIN_FILTER,
            ffi::GL_NEAREST as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_MAG_FILTER,
            ffi::GL_NEAREST as ffi::GLint
         );

         ffi::glTexImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            ffi::GL_RGBA8 as ffi::GLint,
            width as ffi::GLsizei,
            height as ffi::GLsizei,
            0,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result(Texture {
         name: name,
      })
   }

   #[inline]
   pub fn bind(&self) -> VoidResult {
      unsafe {
         ffi::glBindTexture(ffi::GL_TEXTURE_2D, self.name);
      }

      gl_result(())
   }

   #[inline]
   pub fn resize(&self, width: u32, height: u32) -> VoidResult {
      unsafe {
         ffi::glTexImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            ffi::GL_RGBA8 as ffi::GLint,
            width as ffi::GLsizei,
            height as ffi::GLsizei,
            0,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result(())
   }

   #[inline]
   pub fn null_update(&self, width: u32, height: u32) -> VoidResult {
      unsafe {
         ffi::glTexSubImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            0, 0, width as ffi::GLsizei, height as ffi::GLsizei,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result(())
   }

   #[inline]
   pub fn update(&self, width: u32, height: u32, data: &[u8]) -> VoidResult {
      unsafe {
         ffi::glTexSubImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            0, 0, width as ffi::GLsizei, height as ffi::GLsizei,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            data.as_ptr() as *const ffi::GLvoid
         );
      }

      gl_result(())
   }
}

impl Drop for Texture {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteTextures(1, &self.name)
      };
   }
}

pub struct Framebuffer {
   pub name: ffi::GLuint,
}

impl Framebuffer {
   pub fn new(texture: &Texture) -> Result<Self, RuntimeError> {
      let name = try!(Framebuffer::get_framebuffers());

      let framebuffer = Framebuffer {
         name: name,
      };

      try!(framebuffer.bind());
      try!(framebuffer.attach_texture(texture));
      try!(framebuffer.unbind());

      Ok(framebuffer)
   }

   #[inline]
   pub fn get_framebuffers() -> Result<ffi::GLuint, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenFramebuffers(1, &mut name)
      };

      gl_result(name)
   }

   #[inline]
   pub fn bind(&self) -> VoidResult {
      unsafe {
         ffi::glBindFramebuffer(ffi::GL_READ_FRAMEBUFFER, self.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn unbind(&self) -> VoidResult {
      unsafe {
         ffi::glBindFramebuffer(ffi::GL_READ_FRAMEBUFFER, 0)
      };

      gl_result(())
   }

   #[inline]
   pub fn attach_texture(&self, texture: &Texture) -> VoidResult {
      unsafe {
         ffi::glFramebufferTexture2D(
            ffi::GL_READ_FRAMEBUFFER,
            ffi::GL_COLOR_ATTACHMENT0,
            ffi::GL_TEXTURE_2D,
            texture.name,
            0
         )
      };

      gl_result(())
   }

   #[inline]
   pub fn blit(&self, width: u32, height: u32) -> VoidResult {
      unsafe {
         ffi::glBlitFramebuffer(
            0, 0, width as ffi::GLint, height as ffi::GLint,
            0, 0, width as ffi::GLint, height as ffi::GLint,
            ffi::GL_COLOR_BUFFER_BIT,
            ffi::GL_NEAREST
         )
      };

      gl_result(())
   }
}

impl Drop for Framebuffer {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteFramebuffers(1, &self.name)
      };
   }
}

pub struct Buffer {
   pub name: ffi::GLuint,
   pub ptr: *mut ffi::c_void,
   pub size: ffi::GLsizeiptr,
}

impl Buffer {
   pub fn new() -> Result<Self, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenBuffers(1, &mut name)
      };

      gl_result(Buffer {
         name: name,
         ptr: ptr::null_mut(),
         size: 0,
      })
   }

   #[inline]
   pub fn bind(&self) -> VoidResult {
      unsafe {
         ffi::glBindBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, self.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn unbind(&self) -> VoidResult {
      unsafe {
         ffi::glBindBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, 0)
      };

      gl_result(())
   }

   #[inline]
   pub fn init_data(&mut self, size: usize) -> VoidResult {
      self.size = size as ffi::GLsizeiptr;
      unsafe {
         ffi::glBufferData(
            ffi::GL_PIXEL_UNPACK_BUFFER,
            self.size,
            ptr::null(),
            ffi::GL_STREAM_DRAW
         )
      };

      gl_result(())
   }

   #[inline]
   pub fn map(&mut self) -> VoidResult {
      self.ptr = unsafe {
         ffi::glMapBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, ffi::GL_WRITE_ONLY)
      };

      gl_result(())
   }

   #[inline]
   pub fn map_range(&mut self) -> VoidResult {
      self.ptr = unsafe {
         ffi::glMapBufferRange(
            ffi::GL_PIXEL_UNPACK_BUFFER, 0, self.size,
            ffi::GL_MAP_WRITE_BIT// | ffi::GL_MAP_UNSYNCHRONIZED_BIT
         )
      };

      gl_result(())
   }

   #[inline]
   pub fn unmap(&self) -> VoidResult {
      unsafe {
         ffi::glUnmapBuffer(ffi::GL_PIXEL_UNPACK_BUFFER)
      };

      gl_result(())
   }
}

impl Drop for Buffer {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteBuffers(1, &self.name)
      };
   }
}

pub struct Shader {
   pub name: ffi::GLuint,
}

impl Shader {
   pub fn new(shader_type: ffi::GLenum) -> Result<Self, RuntimeError> {
      let name = unsafe {
         ffi::glCreateShader(shader_type)
      };

      gl_result(Shader {
         name: name,
      })
   }

   #[inline]
   pub fn shader_source(&self, string: &str) -> VoidResult {
      let cstring = try!(CString::new(string));

      unsafe {
         ffi::glShaderSource(self.name, 1, [cstring.as_ptr()].as_ptr(), ptr::null())
      };

      gl_result(())
   }

   #[inline]
   pub fn compile(&self) -> VoidResult {
      unsafe {
         ffi::glCompileShader(self.name)
      };

      if !try!(self.is_compiled()) {
         return gl_error("Shader not compiled")
      }

      Ok(())
   }

   #[inline]
   pub fn is_compiled(&self) -> Result<bool, RuntimeError> {
      let mut compiled: ffi::GLint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGetShaderiv(self.name, ffi::GL_COMPILE_STATUS, &mut compiled);
      };

      gl_result(compiled == ffi::GL_TRUE as ffi::GLint)
   }
}

impl Drop for Shader {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteShader(self.name)
      };
   }
}

pub struct Program {
   pub name: ffi::GLuint,
}

impl Program {
   pub fn new() -> Result<Self, RuntimeError> {
      let name = unsafe {
         ffi::glCreateProgram()
      };

      gl_result(Program {
         name: name,
      })
   }

   #[inline]
   pub fn attach_shader(&self, shader: &Shader) -> VoidResult {
      unsafe {
         ffi::glAttachShader(self.name, shader.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn link(&self) -> VoidResult {
      unsafe {
         ffi::glLinkProgram(self.name)
      };

      if !try!(self.is_linked()) {
         return gl_error("Program not linked")
      }

      Ok(())
   }

   #[inline]
   pub fn use_program(&self) -> VoidResult {
      unsafe {
         ffi::glUseProgram(self.name)
      };

      gl_result(())
   }

   #[inline]
   pub fn is_linked(&self) -> Result<bool, RuntimeError> {
      let mut linked: ffi::GLint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGetProgramiv(self.name, ffi::GL_LINK_STATUS, &mut linked);
      };

      gl_result(linked == ffi::GL_TRUE as ffi::GLint)
   }

   #[inline]
   pub fn get_attrib_location(&self, attrib_name: &str) -> Result<ffi::GLint, RuntimeError> {
      let cname = try!(CString::new(attrib_name));

      let result = unsafe {
         ffi::glGetAttribLocation(self.name, cname.as_ptr())
      };

      gl_result(result)
   }

   #[inline]
   pub fn get_uniform_location(&self, variable_name: &str) -> Result<ffi::GLint, RuntimeError> {
      let cname = try!(CString::new(variable_name));

      let result = unsafe {
         ffi::glGetUniformLocation(self.name, cname.as_ptr())
      };

      gl_result(result)
   }
}

impl Drop for Program {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteProgram(self.name)
      };
   }
}
<commit_msg>Expanding the GL error reporting with function names<commit_after>pub mod ffi;
pub mod frame;

use std::mem;
use std::ptr;
use std::ffi::CString;

use error::{RuntimeError, ErrorKind, VoidResult};

use super::utils::fn_ptr::FnPtrLoader;

#[inline]
pub fn load<T: FnPtrLoader>(loader: &T) {
   unsafe {
      ffi::load_functions(loader)
   };
}

#[inline]
fn gl_error<T>(function: &str, message: &str) -> Result<T, RuntimeError> {
   Err(
      RuntimeError::new(
         ErrorKind::GL,
         format!("{}: {}", function, message)
      )
   )
}

#[inline]
fn gl_result<T>(function: &str, value: T) -> Result<T, RuntimeError> {
   let result = unsafe {
      ffi::glGetError()
   };

   match result {
      ffi::GL_NO_ERROR => Ok(value),
      ffi::GL_INVALID_ENUM => gl_error(function,
         "An unacceptable value is specified for an enumerated argument"
      ),
      ffi::GL_INVALID_VALUE => gl_error(function,
         "A numeric argument is out of range"
      ),
      ffi::GL_INVALID_OPERATION => gl_error(function,
         "The specified operation is not allowed in the current state"
      ),
      ffi::GL_INVALID_FRAMEBUFFER_OPERATION => gl_error(function,
         "The framebuffer object is not complete"
      ),
      ffi::GL_OUT_OF_MEMORY => gl_error(function,
         "There is not enough memory left to execute the command"
      ),
      ffi::GL_STACK_UNDERFLOW => gl_error(function,
         "Performing an operation that would cause an internal stack to underflow"
      ),
      ffi::GL_STACK_OVERFLOW => gl_error(function,
         "Performing an operation that would cause an internal stack to overflow"
      ),
      _ => gl_error(function, "Unknown OpenGL error")
   }
}

#[inline]
pub fn reset_pixelstore_alignment() -> VoidResult {
   unsafe {
      ffi::glPixelStorei(ffi::GL_UNPACK_ALIGNMENT, 1);
   }

   gl_result("glPixelStorei(GL_UNPACK_ALIGNMENT)", ())
}

#[inline]
pub fn enable_framebuffer_srgb() -> VoidResult {
   unsafe {
      ffi::glEnable(ffi::GL_FRAMEBUFFER_SRGB);
   }

   gl_result("glEnable(GL_FRAMEBUFFER_SRGB)", ())
}

#[inline]
pub fn viewport(width: u32, height: u32) -> VoidResult {
   unsafe {
      ffi::glViewport(0, 0, width as ffi::GLsizei, height as ffi::GLsizei)
   }

   gl_result("glViewport", ())
}

#[inline]
pub fn vertex_attrib_pointer(
   index: ffi::GLuint, size: ffi::GLint, buffer: &[ffi::GLfloat]
) -> VoidResult {

   unsafe {
      ffi::glVertexAttribPointer(
         index,
         size,
         ffi::GL_FLOAT,
         ffi::GL_FALSE,
         0,
         buffer.as_ptr() as *const ffi::GLvoid
      )
   }

   gl_result("glVertexAttribPointer", ())
}

#[inline]
pub fn enable_vertex_attrib_array(index: ffi::GLuint) -> VoidResult {
   unsafe {
      ffi::glEnableVertexAttribArray(index)
   }

   gl_result("glEnableVertexAttribArray", ())
}

#[inline]
pub fn uniform_value_1i(location: ffi::GLint, value: ffi::GLint) -> VoidResult {
   unsafe {
      ffi::glUniform1i(location, value)
   }

   gl_result("glUniform1i", ())
}

#[inline]
pub fn draw_arrays(count: ffi::GLsizei) -> VoidResult {
   unsafe {
      ffi::glDrawArrays(ffi::GL_TRIANGLE_STRIP, 0, count)
   }

   gl_result("glDrawArrays", ())
}

pub struct Texture {
   pub name: ffi::GLuint,
}

impl Texture {
   pub fn new(width: u32, height: u32) -> Result<Self, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenTextures(1, &mut name);

         ffi::glBindTexture(ffi::GL_TEXTURE_2D, name);

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_WRAP_S,
            ffi::GL_CLAMP_TO_EDGE as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_WRAP_T,
            ffi::GL_CLAMP_TO_EDGE as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_MIN_FILTER,
            ffi::GL_NEAREST as ffi::GLint
         );

         ffi::glTexParameteri(
            ffi::GL_TEXTURE_2D,
            ffi::GL_TEXTURE_MAG_FILTER,
            ffi::GL_NEAREST as ffi::GLint
         );

         ffi::glTexImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            ffi::GL_RGBA8 as ffi::GLint,
            width as ffi::GLsizei,
            height as ffi::GLsizei,
            0,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result("glGenTextures", Texture {
         name: name,
      })
   }

   #[inline]
   pub fn bind(&self) -> VoidResult {
      unsafe {
         ffi::glBindTexture(ffi::GL_TEXTURE_2D, self.name);
      }

      gl_result("glBindTexture", ())
   }

   #[inline]
   pub fn resize(&self, width: u32, height: u32) -> VoidResult {
      unsafe {
         ffi::glTexImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            ffi::GL_RGBA8 as ffi::GLint,
            width as ffi::GLsizei,
            height as ffi::GLsizei,
            0,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result("glTexImage2D", ())
   }

   #[inline]
   pub fn null_update(&self, width: u32, height: u32) -> VoidResult {
      unsafe {
         ffi::glTexSubImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            0, 0, width as ffi::GLsizei, height as ffi::GLsizei,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            ptr::null()
         );
      }

      gl_result("glTexSubImage2D(NULL)", ())
   }

   #[inline]
   pub fn update(&self, width: u32, height: u32, data: &[u8]) -> VoidResult {
      unsafe {
         ffi::glTexSubImage2D(
            ffi::GL_TEXTURE_2D,
            0,
            0, 0, width as ffi::GLsizei, height as ffi::GLsizei,
            ffi::GL_RGBA,
            ffi::GL_UNSIGNED_BYTE,
            data.as_ptr() as *const ffi::GLvoid
         );
      }

      gl_result("glTexSubImage2D", ())
   }
}

impl Drop for Texture {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteTextures(1, &self.name)
      };
   }
}

pub struct Framebuffer {
   pub name: ffi::GLuint,
}

impl Framebuffer {
   pub fn new(texture: &Texture) -> Result<Self, RuntimeError> {
      let name = try!(Framebuffer::get_framebuffers());

      let framebuffer = Framebuffer {
         name: name,
      };

      try!(framebuffer.bind());
      try!(framebuffer.attach_texture(texture));
      try!(framebuffer.unbind());

      Ok(framebuffer)
   }

   #[inline]
   pub fn get_framebuffers() -> Result<ffi::GLuint, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenFramebuffers(1, &mut name)
      };

      gl_result("glGenFramebuffers", name)
   }

   #[inline]
   pub fn bind(&self) -> VoidResult {
      unsafe {
         ffi::glBindFramebuffer(ffi::GL_READ_FRAMEBUFFER, self.name)
      };

      gl_result("glBindFramebuffer(name)", ())
   }

   #[inline]
   pub fn unbind(&self) -> VoidResult {
      unsafe {
         ffi::glBindFramebuffer(ffi::GL_READ_FRAMEBUFFER, 0)
      };

      gl_result("glBindFramebuffer(0)", ())
   }

   #[inline]
   pub fn attach_texture(&self, texture: &Texture) -> VoidResult {
      unsafe {
         ffi::glFramebufferTexture2D(
            ffi::GL_READ_FRAMEBUFFER,
            ffi::GL_COLOR_ATTACHMENT0,
            ffi::GL_TEXTURE_2D,
            texture.name,
            0
         )
      };

      gl_result("glFramebufferTexture2D", ())
   }

   #[inline]
   pub fn blit(&self, width: u32, height: u32) -> VoidResult {
      unsafe {
         ffi::glBlitFramebuffer(
            0, 0, width as ffi::GLint, height as ffi::GLint,
            0, 0, width as ffi::GLint, height as ffi::GLint,
            ffi::GL_COLOR_BUFFER_BIT,
            ffi::GL_NEAREST
         )
      };

      gl_result("glBlitFramebuffer", ())
   }
}

impl Drop for Framebuffer {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteFramebuffers(1, &self.name)
      };
   }
}

pub struct Buffer {
   pub name: ffi::GLuint,
   pub ptr: *mut ffi::c_void,
   pub size: ffi::GLsizeiptr,
}

impl Buffer {
   pub fn new() -> Result<Self, RuntimeError> {
      let mut name: ffi::GLuint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGenBuffers(1, &mut name)
      };

      gl_result("glGenBuffers", Buffer {
         name: name,
         ptr: ptr::null_mut(),
         size: 0,
      })
   }

   #[inline]
   pub fn bind(&self) -> VoidResult {
      unsafe {
         ffi::glBindBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, self.name)
      };

      gl_result("glBindBuffer(name)", ())
   }

   #[inline]
   pub fn unbind(&self) -> VoidResult {
      unsafe {
         ffi::glBindBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, 0)
      };

      gl_result("glBindBuffer(0)", ())
   }

   #[inline]
   pub fn init_data(&mut self, size: usize) -> VoidResult {
      self.size = size as ffi::GLsizeiptr;
      unsafe {
         ffi::glBufferData(
            ffi::GL_PIXEL_UNPACK_BUFFER,
            self.size,
            ptr::null(),
            ffi::GL_STREAM_DRAW
         )
      };

      gl_result("glBufferData", ())
   }

   #[inline]
   pub fn map(&mut self) -> VoidResult {
      self.ptr = unsafe {
         ffi::glMapBuffer(ffi::GL_PIXEL_UNPACK_BUFFER, ffi::GL_WRITE_ONLY)
      };

      gl_result("glMapBuffer", ())
   }

   #[inline]
   pub fn map_range(&mut self) -> VoidResult {
      self.ptr = unsafe {
         ffi::glMapBufferRange(
            ffi::GL_PIXEL_UNPACK_BUFFER, 0, self.size,
            ffi::GL_MAP_WRITE_BIT// | ffi::GL_MAP_UNSYNCHRONIZED_BIT
         )
      };

      gl_result("glMapBufferRange", ())
   }

   #[inline]
   pub fn unmap(&self) -> VoidResult {
      unsafe {
         ffi::glUnmapBuffer(ffi::GL_PIXEL_UNPACK_BUFFER)
      };

      gl_result("glUnmapBuffer", ())
   }
}

impl Drop for Buffer {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteBuffers(1, &self.name)
      };
   }
}

pub struct Shader {
   pub name: ffi::GLuint,
}

impl Shader {
   pub fn new(shader_type: ffi::GLenum) -> Result<Self, RuntimeError> {
      let name = unsafe {
         ffi::glCreateShader(shader_type)
      };

      gl_result("glCreateShader", Shader {
         name: name,
      })
   }

   #[inline]
   pub fn shader_source(&self, string: &str) -> VoidResult {
      let cstring = try!(CString::new(string));

      unsafe {
         ffi::glShaderSource(self.name, 1, [cstring.as_ptr()].as_ptr(), ptr::null())
      };

      gl_result("glShaderSource", ())
   }

   #[inline]
   pub fn compile(&self) -> VoidResult {
      unsafe {
         ffi::glCompileShader(self.name)
      };

      if !try!(self.is_compiled()) {
         return gl_error("glCompileShader", "Shader not compiled")
      }

      Ok(())
   }

   #[inline]
   pub fn is_compiled(&self) -> Result<bool, RuntimeError> {
      let mut compiled: ffi::GLint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGetShaderiv(self.name, ffi::GL_COMPILE_STATUS, &mut compiled);
      };

      gl_result("glGetShaderiv", compiled == ffi::GL_TRUE as ffi::GLint)
   }
}

impl Drop for Shader {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteShader(self.name)
      };
   }
}

pub struct Program {
   pub name: ffi::GLuint,
}

impl Program {
   pub fn new() -> Result<Self, RuntimeError> {
      let name = unsafe {
         ffi::glCreateProgram()
      };

      gl_result("glCreateProgram", Program {
         name: name,
      })
   }

   #[inline]
   pub fn attach_shader(&self, shader: &Shader) -> VoidResult {
      unsafe {
         ffi::glAttachShader(self.name, shader.name)
      };

      gl_result("glAttachShader", ())
   }

   #[inline]
   pub fn link(&self) -> VoidResult {
      unsafe {
         ffi::glLinkProgram(self.name)
      };

      if !try!(self.is_linked()) {
         return gl_error("glLinkProgram", "Program not linked")
      }

      Ok(())
   }

   #[inline]
   pub fn use_program(&self) -> VoidResult {
      unsafe {
         ffi::glUseProgram(self.name)
      };

      gl_result("glUseProgram", ())
   }

   #[inline]
   pub fn is_linked(&self) -> Result<bool, RuntimeError> {
      let mut linked: ffi::GLint = unsafe { mem::uninitialized() };

      unsafe {
         ffi::glGetProgramiv(self.name, ffi::GL_LINK_STATUS, &mut linked);
      };

      gl_result("glGetProgramiv", linked == ffi::GL_TRUE as ffi::GLint)
   }

   #[inline]
   pub fn get_attrib_location(&self, attrib_name: &str) -> Result<ffi::GLint, RuntimeError> {
      let cname = try!(CString::new(attrib_name));

      let result = unsafe {
         ffi::glGetAttribLocation(self.name, cname.as_ptr())
      };

      gl_result("glGetAttribLocation", result)
   }

   #[inline]
   pub fn get_uniform_location(&self, variable_name: &str) -> Result<ffi::GLint, RuntimeError> {
      let cname = try!(CString::new(variable_name));

      let result = unsafe {
         ffi::glGetUniformLocation(self.name, cname.as_ptr())
      };

      gl_result("glGetUniformLocation", result)
   }
}

impl Drop for Program {
   fn drop (&mut self) {
      unsafe {
         ffi::glDeleteProgram(self.name)
      };
   }
}
<|endoftext|>


<commit_before>//! module for finite automation.

use std::collections::HashSet;
use std::hash::Hash;

/// The rule that moves state from one to another.
///
/// `S` - the type parameter of state.
///
/// `T` - the type parameter of input symbol.
#[deriving(PartialEq, Eq, Hash)]
pub struct Rule<S, T> {
  pub state: S,
  pub symbol: Option<T>,
  pub next_state: S
}

impl<S: PartialEq, T: PartialEq> Rule<S, T> {
  /// determine whether the rule applies to the given state and symbol
  pub fn apply_to(&self, state: &S, symbol: &Option<T>) -> bool {
    self.state == *state && self.symbol == *symbol
  }
}

/// The transition relation in DFA,
/// containing all the rules needed by the DFA.
pub struct DFATransitions<S, T> {
  pub rules: HashSet<Rule<S, T>>
}

impl<S: Eq + Hash, T: Eq + Hash> DFATransitions<S, T> {
  /// get the next state for the given state and symbol
  pub fn next_state<'a>(&'a self, state: &S, symbol: &Option<T>) -> Option<&'a S> {
    self.rule_for(state, symbol).map(|rule| &rule.next_state)
  }

  fn rule_for<'a>(&'a self, state: &S, symbol: &Option<T>) -> Option<&'a Rule<S, T>> {
    self.rules.iter().find(|rule| { rule.apply_to(state, symbol) })
  }
}

/// A running dfa instance, constructed from a DFA model
pub struct DFA<'a, S: 'a, T: 'a> {
  state: &'a S, // current state
  accept_states: &'a HashSet<S>, // set of accept states
  transitions: &'a DFATransitions<S, T>
}

impl<'a, S: Eq + Hash, T: Eq + Hash> DFA<'a, S, T> {
  pub fn accepted(&self) -> bool {
    self.accept_states.contains(self.state)
  }

  pub fn read_symbol(&mut self, sym: &Option<T>) {
    self.state = self.transitions.next_state(self.state, sym)
                                 .expect("unknown input symbol")
  }
}

/// DFA template that can generates dfa instance
pub struct DFAModel<S, T> {
  pub start_state: S,
  pub accept_states: HashSet<S>,
  pub transitions: DFATransitions<S, T>
}

impl<S: Eq + Hash, T: Eq + Hash> DFAModel<S, T> {
  /// determine whether the given symbols can be accepted by the model
  pub fn accept<I: Iterator<T>>(&self, mut iter: I) -> bool {
    let mut dfa = self.gen_dfa();
    for sym in iter {
      dfa.read_symbol(&Some(sym));
    }

    dfa.accepted()
  }

  /// generate a dfa instance
  fn gen_dfa(&self) -> DFA<S, T> {
    DFA {
      state: &self.start_state,
      accept_states: &self.accept_states,
      transitions: &self.transitions
    }
  }
}

/// The transition relation in NFA,
/// containing all the rules needed by the NFA.
pub struct NFATransitions<S, T> {
  pub rules: HashSet<Rule<S, T>>
}

impl<S: Eq + Hash + Clone, T: Eq + Hash> NFATransitions<S, T> {
  fn empty_move(&self, states: HashSet<S>) -> HashSet<S> {
    let mut nexts = self.next_states(&states, &None);
    if nexts.is_subset(&states) {
      states
    } else {
      nexts.extend(states.into_iter());
      self.empty_move(nexts)
    }
  }

  pub fn next_states(&self, states: &HashSet<S>, symbol: &Option<T>) -> HashSet<S> {
    states.iter().flat_map(|state| {
      // NOTE: use `move_iter` instead of `iter`
      self.next_states_for(state, symbol).into_iter()
    }).collect()
  }

  /// get the next state for the given state and symbol
  fn next_states_for(&self, state: &S, symbol: &Option<T>) -> HashSet<S> {
    self.rules.iter().filter_map(|rule| {
      if rule.apply_to(state, symbol) { Some(rule.next_state.clone()) } else { None }
    }).collect()
  }

  fn rules_for<'a>(&'a self, state: &S, symbol: &Option<T>) -> HashSet<&'a Rule<S, T>> {
    self.rules.iter()
              .filter(|rule| { rule.apply_to(state, symbol) })
              .collect()
  }
}

struct NFA<'a, S: 'a, T: 'a> {
  states: HashSet<S>,
  accept_states: &'a HashSet<S>,
  transitions: &'a NFATransitions<S, T>
}

impl<'a, S: Eq + Hash + Clone, T: Eq + Hash> NFA<'a, S, T> {
  pub fn read_symbol(&mut self, symbol: &Option<T>) {
    // do empty moves
    self.states = self.transitions.empty_move(self.states.clone());

    self.states = self.transitions.next_states(&self.states, symbol)
                                  .iter()
                                  .map(|state| { state.clone() }).collect();

    self.states = self.transitions.empty_move(self.states.clone());
  }

  pub fn accepted(&self) -> bool {
    !self.states.is_disjoint(self.accept_states)
  }
}

pub struct NFAModel<S, T> {
  pub start_state: S,
  pub accept_states: HashSet<S>,
  pub transitions: NFATransitions<S, T>
}

impl<S: Eq + Hash + Clone, T: Eq + Hash> NFAModel<S, T> {
  /// determine whether the given symbols can be accepted by the model
  pub fn accept<I: Iterator<T>>(&self, mut iter: I) -> bool {
    let mut dfa = self.gen_nfa();
    for sym in iter {
      dfa.read_symbol(&Some(sym));
    }

    dfa.accepted()
  }

  /// generate a nfa instance
  fn gen_nfa(&self) -> NFA<S, T> {
    let mut start_states = HashSet::new();
    start_states.insert(self.start_state.clone());
    NFA {
      states: start_states,
      accept_states: &self.accept_states,
      transitions: &self.transitions
    }
  }
}
<commit_msg>improve code, remove unnecessary clone<commit_after>//! module for finite automation.

use std::collections::HashSet;
use std::hash::Hash;

/// The rule that moves state from one to another.
///
/// `S` - the type parameter of state.
///
/// `T` - the type parameter of input symbol.
#[deriving(PartialEq, Eq, Hash)]
pub struct Rule<S, T> {
  pub state: S,
  pub symbol: Option<T>,
  pub next_state: S
}

impl<S: PartialEq, T: PartialEq> Rule<S, T> {
  /// determine whether the rule applies to the given state and symbol
  pub fn apply_to(&self, state: &S, symbol: &Option<T>) -> bool {
    self.state == *state && self.symbol == *symbol
  }
}

/// The transition relation in DFA,
/// containing all the rules needed by the DFA.
pub struct DFATransitions<S, T> {
  pub rules: HashSet<Rule<S, T>>
}

impl<S: Eq + Hash, T: Eq + Hash> DFATransitions<S, T> {
  /// get the next state for the given state and symbol
  pub fn next_state<'a>(&'a self, state: &S, symbol: &Option<T>) -> Option<&'a S> {
    self.rule_for(state, symbol).map(|rule| &rule.next_state)
  }

  fn rule_for<'a>(&'a self, state: &S, symbol: &Option<T>) -> Option<&'a Rule<S, T>> {
    self.rules.iter().find(|rule| { rule.apply_to(state, symbol) })
  }
}

/// A running dfa instance, constructed from a DFA model
pub struct DFA<'a, S: 'a, T: 'a> {
  state: &'a S, // current state
  accept_states: &'a HashSet<S>, // set of accept states
  transitions: &'a DFATransitions<S, T>
}

impl<'a, S: Eq + Hash, T: Eq + Hash> DFA<'a, S, T> {
  pub fn accepted(&self) -> bool {
    self.accept_states.contains(self.state)
  }

  pub fn read_symbol(&mut self, sym: &Option<T>) {
    self.state = self.transitions.next_state(self.state, sym)
                                 .expect("unknown input symbol")
  }
}

/// DFA template that can generates dfa instance
pub struct DFAModel<S, T> {
  pub start_state: S,
  pub accept_states: HashSet<S>,
  pub transitions: DFATransitions<S, T>
}

impl<S: Eq + Hash, T: Eq + Hash> DFAModel<S, T> {
  /// determine whether the given symbols can be accepted by the model
  pub fn accept<I: Iterator<T>>(&self, mut iter: I) -> bool {
    let mut dfa = self.gen_dfa();
    for sym in iter {
      dfa.read_symbol(&Some(sym));
    }

    dfa.accepted()
  }

  /// generate a dfa instance
  fn gen_dfa(&self) -> DFA<S, T> {
    DFA {
      state: &self.start_state,
      accept_states: &self.accept_states,
      transitions: &self.transitions
    }
  }
}

/// The transition relation in NFA,
/// containing all the rules needed by the NFA.
pub struct NFATransitions<S, T> {
  pub rules: HashSet<Rule<S, T>>
}

impl<S: Eq + Hash, T: Eq + Hash> NFATransitions<S, T> {
  pub fn next_states<'a>(&'a self, states: &HashSet<&'a S>, symbol: &Option<T>) -> HashSet<&'a S> {
    states.iter().flat_map(|&state| {
      // NOTE: use `move_iter` instead of `iter`
      self.next_states_for(state, symbol).into_iter()
    }).collect()
  }

  /// get the next state for the given state and symbol
  fn next_states_for<'a>(&'a self, state: &S, symbol: &Option<T>) -> HashSet<&'a S> {
    self.rules.iter().filter_map(|rule| {
      if rule.apply_to(state, symbol) { Some(&rule.next_state) } else { None }
    }).collect()
  }
}

struct NFA<'a, S: 'a, T: 'a> {
  states: HashSet<&'a S>,
  accept_states: &'a HashSet<S>,
  transitions: &'a NFATransitions<S, T>
}

impl<'a, S: Eq + Hash, T: Eq + Hash> NFA<'a, S, T> {
  fn empty_move(&mut self) {
    let nexts = self.transitions.next_states(&self.states, &None);
    if !nexts.is_subset(&self.states) {
      self.states.extend(nexts.into_iter());
      self.empty_move();
    }
  }

  pub fn read_symbol(&mut self, symbol: &Option<T>) {
    // do empty moves
    self.empty_move();
    self.states = self.transitions.next_states(&self.states, symbol);
    self.empty_move();
  }

  pub fn accepted(&self) -> bool {
    //NOTE: or use `self.accept_states.iter().any(|state| self.states.contains(&state))`
    self.states.iter().any(|&state| self.accept_states.contains(state))
  }
}

pub struct NFAModel<S, T> {
  pub start_state: S,
  pub accept_states: HashSet<S>,
  pub transitions: NFATransitions<S, T>
}

impl<S: Eq + Hash, T: Eq + Hash> NFAModel<S, T> {
  /// determine whether the given symbols can be accepted by the model
  pub fn accept<I: Iterator<T>>(&self, mut iter: I) -> bool {
    let mut dfa = self.gen_nfa();
    for sym in iter {
      dfa.read_symbol(&Some(sym));
    }

    dfa.accepted()
  }

  /// generate a nfa instance
  fn gen_nfa(&self) -> NFA<S, T> {
    let mut start_states = HashSet::new();
    start_states.insert(&self.start_state);
    NFA {
      states: start_states,
      accept_states: &self.accept_states,
      transitions: &self.transitions
    }
  }
}
<|endoftext|>


<commit_before>#![cfg(test)]
use std::cell::RefCell;
use std::rc::Rc;

use alloc_box::AllocBox;
use ast::{Exp, Stmt};
use types::js_fn::JsFnStruct;
use types::js_obj::JsObjStruct;
use types::js_str::JsStrStruct;
use types::js_var::{JsKey, JsPtrEnum, JsPtrTag, JsType, JsVar};

pub fn make_str(s: &str) -> (JsVar, JsPtrEnum) {
    let var = JsVar::new(JsType::JsPtr(JsPtrTag::JsStr));
    (var, JsPtrEnum::JsStr(JsStrStruct::new(s)))
}

pub fn make_num(i: f64) -> JsVar {
    JsVar::new(JsType::JsNum(i))
}

pub fn make_obj(kvs: Vec<(JsKey, JsVar, Option<JsPtrEnum>)>, heap: Rc<RefCell<AllocBox>>) -> (JsVar, JsPtrEnum) {
    let var = JsVar::new(JsType::JsPtr(JsPtrTag::JsObj));
    (var, JsPtrEnum::JsObj(JsObjStruct::new(None, "test", kvs, &mut *heap.borrow_mut())))
}

pub fn make_fn(name: &Option<String>, params: &Vec<String>) -> (JsVar, JsPtrEnum) {
    let var = JsVar::new(JsType::JsPtr(JsPtrTag::JsFn { name: None }));
    (var, JsPtrEnum::JsFn(JsFnStruct::new(name, params, &vec![Stmt::BareExp(Exp::Undefined)])))
}

pub fn make_alloc_box() -> Rc<RefCell<AllocBox>> {
    Rc::new(RefCell::new(AllocBox::new()))
}
<commit_msg>get rid of test configuration because it apparently breaks things<commit_after>use std::cell::RefCell;
use std::rc::Rc;

use alloc_box::AllocBox;
use ast::{Exp, Stmt};
use types::js_fn::JsFnStruct;
use types::js_obj::JsObjStruct;
use types::js_str::JsStrStruct;
use types::js_var::{JsKey, JsPtrEnum, JsPtrTag, JsType, JsVar};

pub fn make_str(s: &str) -> (JsVar, JsPtrEnum) {
    let var = JsVar::new(JsType::JsPtr(JsPtrTag::JsStr));
    (var, JsPtrEnum::JsStr(JsStrStruct::new(s)))
}

pub fn make_num(i: f64) -> JsVar {
    JsVar::new(JsType::JsNum(i))
}

pub fn make_obj(kvs: Vec<(JsKey, JsVar, Option<JsPtrEnum>)>, heap: Rc<RefCell<AllocBox>>) -> (JsVar, JsPtrEnum) {
    let var = JsVar::new(JsType::JsPtr(JsPtrTag::JsObj));
    (var, JsPtrEnum::JsObj(JsObjStruct::new(None, "test", kvs, &mut *heap.borrow_mut())))
}

pub fn make_fn(name: &Option<String>, params: &Vec<String>) -> (JsVar, JsPtrEnum) {
    let var = JsVar::new(JsType::JsPtr(JsPtrTag::JsFn { name: None }));
    (var, JsPtrEnum::JsFn(JsFnStruct::new(name, params, &vec![Stmt::BareExp(Exp::Undefined)])))
}

pub fn make_alloc_box() -> Rc<RefCell<AllocBox>> {
    Rc::new(RefCell::new(AllocBox::new()))
}
<|endoftext|>


<commit_before>// Copyright 2017 Dario Domizioli ("hhexo").
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// These tests are based on the book called "Seven Concurrency Models
// In Seven Weeks". Chapter 5 of the book is about the actor model. I am trying
// to replicate the exercises in the book by writing equivalent tests for the
// mecha library.

#[cfg(test)]
mod chapter5_day1 {

use std::sync::mpsc;
use std::collections::HashMap;

use Actor;
use MessageType;
use MessageDatum;
use Message;
use ActorAddress;
use spawn_link;

// ----------------------------------------------------------------------------

struct Talker;

const GREET: &'static str = ":greet";
const PRAISE: &'static str = ":praise";
const CELEBRATE: &'static str = ":celebrate";

impl Actor for Talker {
    fn process_message(&mut self, message: Message, _: &ActorAddress) {
        match *message.get_type() {
            MessageType::Custom(GREET) => {
                match *message.get_datum() {
                    MessageDatum::Str(ref s) => {
                        println!("Hello {}!", s);
                    },
                    _ => (),
                }
            },
            MessageType::Custom(PRAISE) => {
                match *message.get_datum() {
                    MessageDatum::Str(ref s) => {
                        println!("{}, you're amazing!", s);
                    },
                    _ => (),
                }
            },
            MessageType::Custom(CELEBRATE) => {
                match *message.get_datum() {
                    MessageDatum::Map(ref m) => {
                        let name = m.get("name").unwrap().clone().as_str().unwrap();
                        let age = m.get("age").unwrap().clone().as_u64().unwrap();
                        println!("Here's to another {} years, {}!", age, name);
                    },
                    _ => (),
                }
            },
            _ => (),
        }
    }
}

struct Issuer;

impl Actor for Issuer {
    fn process_message(&mut self, message: Message, myself: &ActorAddress) {
        match *message.get_type() {
            MessageType::Init => {
                let worker = spawn_link(Talker, myself);
                Message::custom(GREET).with_str("Hewey").send_to(&worker);
                Message::custom(PRAISE).with_str("Dewey").send_to(&worker);
                let mut m = HashMap::new();
                m.insert("name".to_string(), MessageDatum::from("Louie"));
                m.insert("age".to_string(), MessageDatum::from(16u64));
                Message::custom(CELEBRATE).with_map(m).send_to(&worker);
                Message::shutdown().send_to(&worker);
            },
            MessageType::Exited => {
                // This means our worker has exited, we can exit too. Send
                // ourselves a Shutdown.
                Message::shutdown().send_to(myself);
            },
            _ => ()
        }
    }
}

#[test]
fn test_talker() {
    let (tx, rx) = mpsc::channel();
    let fake_actor = ActorAddress::new(tx);
    spawn_link(Issuer, &fake_actor);

    // Now let's receive the Exited message.
    let m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Exited);
    match *m.get_datum() {
        MessageDatum::Void => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }
}

// ----------------------------------------------------------------------------

struct Counter {
    count: i64
}
impl Counter {
    pub fn new() -> Counter { Counter { count: 0i64 } }
}

const NEXT : &'static str = ":next";

impl Actor for Counter {
    fn process_message(&mut self, message: Message, _: &ActorAddress) {
        match *message.get_type() {
            MessageType::Custom(NEXT) => {
                println!("Current count: {}", self.count);
                self.count += 1;
            },
            _ => ()
        }
    }
}

#[test]
fn test_counter() {
    let (tx, rx) = mpsc::channel();
    let fake_actor = ActorAddress::new(tx);
    let worker = spawn_link(Counter::new(), &fake_actor);

    Message::custom(NEXT).send_to(&worker);
    Message::custom(NEXT).send_to(&worker);
    Message::custom(NEXT).send_to(&worker);
    Message::shutdown().send_to(&worker);

    // Now let's receive the Exited message.
    let m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Exited);
    match *m.get_datum() {
        MessageDatum::Void => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }
}

struct CounterApi {
    counter_actor: ActorAddress
}
impl CounterApi {
    pub fn start(count: i64, link: &ActorAddress) -> CounterApi {
        CounterApi {
            counter_actor: spawn_link(Counter { count: count }, link)
        }
    }

    pub fn next(&self) {
        Message::custom(NEXT).send_to(&self.counter_actor);
    }

    pub fn shutdown(&self) {
        Message::shutdown().send_to(&self.counter_actor);
    }
}

#[test]
fn test_counter_with_api() {
    let (tx, rx) = mpsc::channel();
    let fake_actor = ActorAddress::new(tx);
    let api = CounterApi::start(0i64, &fake_actor);

    api.next();
    api.next();
    api.next();
    api.shutdown();

    // Now let's receive the Exited message.
    let m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Exited);
    match *m.get_datum() {
        MessageDatum::Void => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }
}

}
<commit_msg>Added bidirectional synchronous example<commit_after>// Copyright 2017 Dario Domizioli ("hhexo").
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// These tests are based on the book called "Seven Concurrency Models
// In Seven Weeks". Chapter 5 of the book is about the actor model. I am trying
// to replicate the exercises in the book by writing equivalent tests for the
// mecha library.

#[cfg(test)]
mod chapter5_day1 {

use std::sync::mpsc;
use std::collections::HashMap;

use Actor;
use MessageType;
use MessageDatum;
use Message;
use ActorAddress;
use spawn_link;
use spawn;

// ----------------------------------------------------------------------------

struct Talker;

const GREET: &'static str = ":greet";
const PRAISE: &'static str = ":praise";
const CELEBRATE: &'static str = ":celebrate";

impl Actor for Talker {
    fn process_message(&mut self, message: Message, _: &ActorAddress) {
        match *message.get_type() {
            MessageType::Custom(GREET) => {
                match *message.get_datum() {
                    MessageDatum::Str(ref s) => {
                        println!("Hello {}!", s);
                    },
                    _ => (),
                }
            },
            MessageType::Custom(PRAISE) => {
                match *message.get_datum() {
                    MessageDatum::Str(ref s) => {
                        println!("{}, you're amazing!", s);
                    },
                    _ => (),
                }
            },
            MessageType::Custom(CELEBRATE) => {
                match *message.get_datum() {
                    MessageDatum::Map(ref m) => {
                        let name = m.get("name").unwrap().clone().as_str().unwrap();
                        let age = m.get("age").unwrap().clone().as_u64().unwrap();
                        println!("Here's to another {} years, {}!", age, name);
                    },
                    _ => (),
                }
            },
            _ => (),
        }
    }
}

struct Issuer;

impl Actor for Issuer {
    fn process_message(&mut self, message: Message, myself: &ActorAddress) {
        match *message.get_type() {
            MessageType::Init => {
                let worker = spawn_link(Talker, myself);
                Message::custom(GREET).with_str("Hewey").send_to(&worker);
                Message::custom(PRAISE).with_str("Dewey").send_to(&worker);
                let mut m = HashMap::new();
                m.insert("name".to_string(), MessageDatum::from("Louie"));
                m.insert("age".to_string(), MessageDatum::from(16u64));
                Message::custom(CELEBRATE).with_map(m).send_to(&worker);
                Message::shutdown().send_to(&worker);
            },
            MessageType::Exited => {
                // This means our worker has exited, we can exit too. Send
                // ourselves a Shutdown.
                Message::shutdown().send_to(myself);
            },
            _ => ()
        }
    }
}

#[test]
fn test_talker() {
    let (tx, rx) = mpsc::channel();
    let fake_actor = ActorAddress::new(tx);
    spawn_link(Issuer, &fake_actor);

    // Now let's receive the Exited message.
    let m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Exited);
    match *m.get_datum() {
        MessageDatum::Void => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }
}

// ----------------------------------------------------------------------------

struct Counter {
    count: i64
}
impl Counter {
    pub fn new() -> Counter { Counter { count: 0i64 } }
}

const NEXT : &'static str = ":next";

impl Actor for Counter {
    fn process_message(&mut self, message: Message, _: &ActorAddress) {
        match *message.get_type() {
            MessageType::Custom(NEXT) => {
                println!("Current count: {}", self.count);
                self.count += 1;
            },
            _ => ()
        }
    }
}

#[test]
fn test_counter() {
    let (tx, rx) = mpsc::channel();
    let fake_actor = ActorAddress::new(tx);
    let worker = spawn_link(Counter::new(), &fake_actor);

    Message::custom(NEXT).send_to(&worker);
    Message::custom(NEXT).send_to(&worker);
    Message::custom(NEXT).send_to(&worker);
    Message::shutdown().send_to(&worker);

    // Now let's receive the Exited message.
    let m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Exited);
    match *m.get_datum() {
        MessageDatum::Void => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }
}

// ----------------------------------------------------------------------------

struct CounterApi {
    counter_actor: ActorAddress
}
impl CounterApi {
    pub fn start(count: i64, link: &ActorAddress) -> CounterApi {
        CounterApi {
            counter_actor: spawn_link(Counter { count: count }, link)
        }
    }

    pub fn next(&self) {
        Message::custom(NEXT).send_to(&self.counter_actor);
    }

    pub fn shutdown(&self) {
        Message::shutdown().send_to(&self.counter_actor);
    }
}

#[test]
fn test_counter_with_api() {
    let (tx, rx) = mpsc::channel();
    let fake_actor = ActorAddress::new(tx);
    let api = CounterApi::start(0i64, &fake_actor);

    api.next();
    api.next();
    api.next();
    api.shutdown();

    // Now let's receive the Exited message.
    let m = rx.recv().unwrap();
    assert_eq!(*m.get_type(), MessageType::Exited);
    match *m.get_datum() {
        MessageDatum::Void => (), // ok
        _ => { assert!(false, "Unexpected message datum"); }
    }
}

// ----------------------------------------------------------------------------

struct CounterBidirectional {
    count: i64
}

const NEXT_ACK : &'static str = ":next-ack";

impl Actor for CounterBidirectional {
    fn process_message(&mut self, message: Message, myself: &ActorAddress) {
        match *message.get_type() {
            MessageType::Custom(NEXT) => {
                Message::custom(NEXT_ACK).with_sender(myself)
                                         .with_i64(self.count)
                                         .send_to(message.get_sender());
                self.count += 1;
            },
            _ => ()
        }
    }
}

struct CounterSynchronousApi {
    counter_actor: ActorAddress
}
impl CounterSynchronousApi {
    pub fn start(count: i64) -> CounterSynchronousApi {
        CounterSynchronousApi {
            counter_actor: spawn(CounterBidirectional { count: count })
        }
    }

    pub fn next(&self) -> i64 {
        let (tx, rx) = mpsc::channel();
        let fake_actor = ActorAddress::new(tx);
        Message::custom(NEXT).with_sender(&fake_actor)
                             .send_to(&self.counter_actor);
        let m = rx.recv().unwrap();
        assert_eq!(*m.get_type(), MessageType::Custom(NEXT_ACK));
        m.get_datum().clone().as_i64().unwrap()
    }

    pub fn shutdown(&self) {
        let (tx, rx) = mpsc::channel();
        let fake_actor = ActorAddress::new(tx);
        Message::link().with_sender(&fake_actor).send_to(&self.counter_actor);
        Message::shutdown().with_sender(&fake_actor)
                           .send_to(&self.counter_actor);
        let m = rx.recv().unwrap();
        assert_eq!(*m.get_type(), MessageType::Exited);
    }
}

#[test]
fn test_counter_bidirectional_synchronous() {
    let api = CounterSynchronousApi::start(0i64);

    let a = api.next();
    let b = api.next();
    let c = api.next();
    api.shutdown();

    assert_eq!(a, 0i64);
    assert_eq!(b, 1i64);
    assert_eq!(c, 2i64);
}

}
<|endoftext|>