<commit_before>use std::borrow::Cow;
use std::cmp::min;
use std::io::Write;

use memchr::memchr;

use crate::formats::buffer::RecParser;
use crate::formats::fasta::check_end;
use crate::seq::Sequence;
use crate::util::{memchr_both, ParseError, ParseErrorType};

#[derive(Debug)]
pub struct Fastq<'a> {
    pub id: &'a [u8],
    pub seq: &'a [u8],
    pub id2: &'a [u8],
    pub qual: &'a [u8],
}

impl<'a> Fastq<'a> {
    pub fn write(&self, writer: &mut dyn Write) -> Result<(), ParseError> {
        writer.write_all(b"@")?;
        writer.write_all(&self.id)?;
        writer.write_all(b"\n")?;
        writer.write_all(&self.seq)?;
        writer.write_all(b"+\n")?;
        if self.seq.len() != self.qual.len() {
            writer.write_all(&vec![b'I'; self.seq.len()])?;
        } else {
            writer.write_all(&self.qual)?;
        }
        writer.write_all(b"\n")?;
        Ok(())
    }
}

impl<'a> From<Fastq<'a>> for Sequence<'a> {
    fn from(fastq: Fastq<'a>) -> Sequence<'a> {
        let qual = if fastq.seq.len() != fastq.qual.len() {
            None
        } else {
            Some(fastq.qual)
        };
        Sequence::new(fastq.id, Cow::from(fastq.seq), qual)
    }
}

impl<'a> From<&'a Sequence<'a>> for Fastq<'a> {
    fn from(seq: &'a Sequence<'a>) -> Fastq<'a> {
        let qual = match &seq.qual {
            None => &b""[..],
            Some(q) => &q,
        };
        Fastq {
            id: &seq.id,
            seq: &seq.seq,
            id2: b"",
            qual,
        }
    }
}

pub struct FastqParser<'a> {
    buf: &'a [u8],
    last: bool,
    pos: usize,
}

impl<'a> FastqParser<'a> {
    pub fn new(buf: &'a [u8], last: bool) -> Result<Self, ParseError> {
        if buf[0] != b'@' {
            // sometimes there are extra returns at the end of a file so we shouldn't blow up
            if !(last && (buf[0] == b'\r' && buf[0] == b'\n')) {
                let context = String::from_utf8_lossy(&buf[..min(32, buf.len())]);
                let e = ParseError::new(
                    "FASTQ record must start with '@'",
                    ParseErrorType::InvalidHeader,
                )
                .context(context);
                return Err(e);
            }
        }

        Ok(FastqParser { buf, last, pos: 0 })
    }
}

impl<'a> Iterator for FastqParser<'a> {
    type Item = Result<Fastq<'a>, ParseError>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        let buf = &self.buf[self.pos..];
        if buf.is_empty() {
            return None;
        }
        if buf[0] == b'\n' {
            // sometimes the last "record" is just newlines
            return None;
        }

        let id_end;
        match memchr(b'\n', &buf) {
            Some(i) => id_end = i + 1,
            None => return None,
        };
        let mut id = &buf[1..id_end - 1];

        let seq_end;
        match memchr_both(b'\n', b'+', &buf[id_end..]) {
            Some(i) => seq_end = id_end + i + 1,
            None => return None,
        };
        let mut seq = &buf[id_end..seq_end - 1];

        let id2_end;
        match memchr(b'\n', &buf[seq_end..]) {
            Some(i) => id2_end = seq_end + i + 1,
            None => return None,
        };
        let id2 = &buf[seq_end..id2_end - 1];

        // we know the qual scores must be the same length as the sequence
        // so we can just do some arithmatic instead of memchr'ing
        let mut qual_end = id2_end + seq.len() + 1;
        let mut buffer_used = qual_end;
        if qual_end > buf.len() {
            if !self.last {
                // we need to pull more into the buffer
                return None;
            }
            // now do some math to figure out if the file doesn't end with a newline
            let windows_ending = if seq.last() == Some(&b'\r') { 1 } else { 0 };
            if qual_end != buf.len() + 1 + windows_ending {
                return None;
            }
            buffer_used -= 1 + windows_ending;
            qual_end -= windows_ending;
        }
        let mut qual = &buf[id2_end..qual_end - 1];

        if (qual_end + 1 < buf.len()
            && buf[qual_end] != b'@'
            && buf[qual_end] != b'\r'
            && buf[qual_end] != b'\n')
            || (qual_end < buf.len() && buf[qual_end - 1] != b'\n')
        {
            let context = String::from_utf8_lossy(id);
            return Some(Err(ParseError::new(
                "Sequence and quality lengths differed",
                ParseErrorType::InvalidRecord,
            )
            .context(context)));
        }

        // clean up any extra '\r' from the id and seq
        if !id.is_empty() && id[id.len() - 1] == b'\r' {
            id = &id[..id.len() - 1];
        }
        if !seq.is_empty() && seq[seq.len() - 1] == b'\r' {
            seq = &seq[..seq.len() - 1];
        }
        // we do qual separately in case this is the end of the file
        if !qual.is_empty() && qual[qual.len() - 1] == b'\r' {
            qual = &qual[..qual.len() - 1];
        }
        if !qual.is_empty() && qual[qual.len() - 1] == b'\n' {
            // special case for FASTQs that are a single character short on the
            // quality line, but still have a terminal newline
            let context = String::from_utf8_lossy(id);
            return Some(Err(ParseError::new(
                "Quality length was shorter than expected",
                ParseErrorType::PrematureEOF,
            )
            .context(context)));
        }

        self.pos += buffer_used;
        Some(Ok(Fastq { id, seq, id2, qual }))
    }
}

impl<'a> RecParser<'a> for FastqParser<'a> {
    type Header = ();

    fn from_buffer(buf: &[u8], last: bool) -> FastqParser {
        FastqParser { buf, last, pos: 0 }
    }

    fn header(&mut self) -> Result<Self::Header, ParseError> {
        Ok(())
    }

    fn eof(&self) -> Result<(), ParseError> {
        check_end(&self.buf[self.pos..], self.last)
    }

    fn used(&self) -> usize {
        self.pos
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use super::FastqParser;
    use crate::formats::buffer::{RecBuffer, RecParser};
    use crate::formats::parse_sequences;
    use crate::util::ParseErrorType;

    fn seq(s: &[u8]) -> Cursor<&[u8]> {
        Cursor::new(&s[..])
    }

    #[test]
    fn test_fastq() {
        let mut i = 0;
        let res = parse_sequences(
            seq(b"@test\nAGCT\n+test\n~~a!\n@test2\nTGCA\n+test\nWUI9"),
            |_| (),
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"test");
                        assert_eq!(&seq.seq[..], b"AGCT");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~a!");
                    }
                    1 => {
                        assert_eq!(&seq.id[..], b"test2");
                        assert_eq!(&seq.seq[..], b"TGCA");
                        assert_eq!(&seq.qual.unwrap()[..], b"WUI9");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(i, 2);
        assert_eq!(res, Ok(()));

        let mut i = 0;
        let res = parse_sequences(
            seq(b"@test\r\nAGCT\r\n+test\r\n~~a!\r\n@test2\r\nTGCA\r\n+test\r\nWUI9"),
            |_| {},
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"test");
                        assert_eq!(&seq.seq[..], b"AGCT");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~a!");
                    }
                    1 => {
                        assert_eq!(&seq.id[..], b"test2");
                        assert_eq!(&seq.seq[..], b"TGCA");
                        assert_eq!(&seq.qual.unwrap()[..], b"WUI9");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(res, Ok(()));
        assert_eq!(i, 2);
    }

    #[test]
    fn test_fastq_endings() {
        //! Check for the absence of a panic. The parser previously assumed
        //! if the ID ended with an `\r\n` then the sequence did also.
        //! (Discovered via fuzzing)
        let res = parse_sequences(seq(b"@\r\n\n+A\n@"), |_| (), |_seq| {});
        assert_eq!(res, Ok(()));
    }

    #[test]
    fn test_premature_endings() {
        let test = b"@test\nACGT\n+\nIII\n";
        let mut fp = FastqParser::new(test, true).unwrap();
        let result = fp.next().unwrap();
        assert!(result.is_err());
        let e = result.unwrap_err();
        assert!(e.error_type == ParseErrorType::PrematureEOF);

        let mut i = 0;
        let res = parse_sequences(
            seq(b"@test\nAGCT\n+test\n~~a!\n@test2\nTGCA"),
            |_| {},
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"test");
                        assert_eq!(&seq.seq[..], b"AGCT");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~a!");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(i, 1);
        let e = res.unwrap_err();
        assert_eq!(e.error_type, ParseErrorType::PrematureEOF);
        assert_eq!(e.record, 2);

        // we allow a few extra newlines at the ends of FASTQs
        let mut i = 0;
        let res = parse_sequences(
            seq(b"@test\nAGCT\n+test\n~~a!\n\n"),
            |_| {},
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"test");
                        assert_eq!(&seq.seq[..], b"AGCT");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~a!");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(i, 1);
        assert_eq!(res, Ok(()));

        // but if there's additional data past the newlines it's an error
        // note this is slightly easier to output than the "Sequence and
        // quality lengths differed" error because the end of the file may
        // normally have multiple newlines
        let mut i = 0;
        let res = parse_sequences(
            seq(b"@test\nAGCT\n+test\n~~a!\n\n@TEST\nA\n+TEST\n~"),
            |_| {},
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"test");
                        assert_eq!(&seq.seq[..], b"AGCT");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~a!");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(i, 1);
        let e = res.unwrap_err();
        assert_eq!(e.error_type, ParseErrorType::PrematureEOF);
        assert_eq!(e.record, 2);
    }

    #[test]
    fn test_empty_records() {
        let mut i = 0;
        let res = parse_sequences(
            seq(b"@\n\n+\n\n@test2\nTGCA\n+test2\n~~~~\n"),
            |stype| {
                assert_eq!(stype, "FASTQ");
            },
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"");
                        assert_eq!(&seq.seq[..], b"");
                        assert_eq!(&seq.qual.unwrap()[..], b"");
                    }
                    1 => {
                        assert_eq!(&seq.id[..], b"test2");
                        assert_eq!(&seq.seq[..], b"TGCA");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~~~");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(res, Ok(()));
        assert_eq!(i, 2);
    }

    #[test]
    fn test_mismatched_lengths() {
        let mut fp = FastqParser::new(b"@test\nAGCT\n+\nIII\n@TEST\nA\n+\nI", true).unwrap();
        let result = fp.next().unwrap();
        assert!(result.is_err());
        let e = result.unwrap_err();
        assert!(e.error_type == ParseErrorType::InvalidRecord);
        assert!(e.msg == "Sequence and quality lengths differed");

        let mut fp = FastqParser::new(b"@test\nAGCT\n+\nIIIII\n@TEST\nA\n+\nI", true).unwrap();
        let result = fp.next().unwrap();
        assert!(result.is_err());
        let e = result.unwrap_err();
        assert!(e.error_type == ParseErrorType::InvalidRecord);
        assert!(e.msg == "Sequence and quality lengths differed");
    }

    #[test]
    fn test_fastq_across_buffer() {
        let test_seq = b"@A\nA\n+A\nA\n@B\nA\n+B\n!";
        let mut cursor = Cursor::new(test_seq);
        // the buffer is aligned to the first record
        let mut rec_reader = RecBuffer::new(&mut cursor, 9, b"").unwrap();

        let used = {
            let mut rec_buffer = FastqParser::from_buffer(&rec_reader.buf, rec_reader.last);
            for _s in rec_buffer.by_ref() {
                // record is incomplete
                panic!("No initial record should be parsed")
            }
            rec_buffer.used()
        };

        // refill the buffer, but we're not done quite yet
        assert_eq!(rec_reader.refill(used).unwrap(), false);

        // now we should see both records
        let mut rec_buffer = FastqParser::from_buffer(&rec_reader.buf, rec_reader.last);

        // there should be a record assuming the parser
        // handled the buffer boundary
        let iterated_seq = rec_buffer.by_ref().next();
        let seq = iterated_seq.unwrap();
        assert_eq!(seq.unwrap().id, b"A");

        // but not another because the buffer's too short
        let iterated_seq = rec_buffer.by_ref().next();
        assert!(iterated_seq.is_none());

        // TODO: refill and check for the last record
    }
}
<commit_msg>Add missing newline to Fastq::write<commit_after>use std::borrow::Cow;
use std::cmp::min;
use std::io::Write;

use memchr::memchr;

use crate::formats::buffer::RecParser;
use crate::formats::fasta::check_end;
use crate::seq::Sequence;
use crate::util::{memchr_both, ParseError, ParseErrorType};

#[derive(Debug)]
pub struct Fastq<'a> {
    pub id: &'a [u8],
    pub seq: &'a [u8],
    pub id2: &'a [u8],
    pub qual: &'a [u8],
}

impl<'a> Fastq<'a> {
    pub fn write(&self, writer: &mut dyn Write) -> Result<(), ParseError> {
        writer.write_all(b"@")?;
        writer.write_all(&self.id)?;
        writer.write_all(b"\n")?;
        writer.write_all(&self.seq)?;
        writer.write_all(b"\n+\n")?;
        if self.seq.len() != self.qual.len() {
            writer.write_all(&vec![b'I'; self.seq.len()])?;
        } else {
            writer.write_all(&self.qual)?;
        }
        writer.write_all(b"\n")?;
        Ok(())
    }
}

impl<'a> From<Fastq<'a>> for Sequence<'a> {
    fn from(fastq: Fastq<'a>) -> Sequence<'a> {
        let qual = if fastq.seq.len() != fastq.qual.len() {
            None
        } else {
            Some(fastq.qual)
        };
        Sequence::new(fastq.id, Cow::from(fastq.seq), qual)
    }
}

impl<'a> From<&'a Sequence<'a>> for Fastq<'a> {
    fn from(seq: &'a Sequence<'a>) -> Fastq<'a> {
        let qual = match &seq.qual {
            None => &b""[..],
            Some(q) => &q,
        };
        Fastq {
            id: &seq.id,
            seq: &seq.seq,
            id2: b"",
            qual,
        }
    }
}

pub struct FastqParser<'a> {
    buf: &'a [u8],
    last: bool,
    pos: usize,
}

impl<'a> FastqParser<'a> {
    pub fn new(buf: &'a [u8], last: bool) -> Result<Self, ParseError> {
        if buf[0] != b'@' {
            // sometimes there are extra returns at the end of a file so we shouldn't blow up
            if !(last && (buf[0] == b'\r' && buf[0] == b'\n')) {
                let context = String::from_utf8_lossy(&buf[..min(32, buf.len())]);
                let e = ParseError::new(
                    "FASTQ record must start with '@'",
                    ParseErrorType::InvalidHeader,
                )
                .context(context);
                return Err(e);
            }
        }

        Ok(FastqParser { buf, last, pos: 0 })
    }
}

impl<'a> Iterator for FastqParser<'a> {
    type Item = Result<Fastq<'a>, ParseError>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        let buf = &self.buf[self.pos..];
        if buf.is_empty() {
            return None;
        }
        if buf[0] == b'\n' {
            // sometimes the last "record" is just newlines
            return None;
        }

        let id_end;
        match memchr(b'\n', &buf) {
            Some(i) => id_end = i + 1,
            None => return None,
        };
        let mut id = &buf[1..id_end - 1];

        let seq_end;
        match memchr_both(b'\n', b'+', &buf[id_end..]) {
            Some(i) => seq_end = id_end + i + 1,
            None => return None,
        };
        let mut seq = &buf[id_end..seq_end - 1];

        let id2_end;
        match memchr(b'\n', &buf[seq_end..]) {
            Some(i) => id2_end = seq_end + i + 1,
            None => return None,
        };
        let id2 = &buf[seq_end..id2_end - 1];

        // we know the qual scores must be the same length as the sequence
        // so we can just do some arithmatic instead of memchr'ing
        let mut qual_end = id2_end + seq.len() + 1;
        let mut buffer_used = qual_end;
        if qual_end > buf.len() {
            if !self.last {
                // we need to pull more into the buffer
                return None;
            }
            // now do some math to figure out if the file doesn't end with a newline
            let windows_ending = if seq.last() == Some(&b'\r') { 1 } else { 0 };
            if qual_end != buf.len() + 1 + windows_ending {
                return None;
            }
            buffer_used -= 1 + windows_ending;
            qual_end -= windows_ending;
        }
        let mut qual = &buf[id2_end..qual_end - 1];

        if (qual_end + 1 < buf.len()
            && buf[qual_end] != b'@'
            && buf[qual_end] != b'\r'
            && buf[qual_end] != b'\n')
            || (qual_end < buf.len() && buf[qual_end - 1] != b'\n')
        {
            let context = String::from_utf8_lossy(id);
            return Some(Err(ParseError::new(
                "Sequence and quality lengths differed",
                ParseErrorType::InvalidRecord,
            )
            .context(context)));
        }

        // clean up any extra '\r' from the id and seq
        if !id.is_empty() && id[id.len() - 1] == b'\r' {
            id = &id[..id.len() - 1];
        }
        if !seq.is_empty() && seq[seq.len() - 1] == b'\r' {
            seq = &seq[..seq.len() - 1];
        }
        // we do qual separately in case this is the end of the file
        if !qual.is_empty() && qual[qual.len() - 1] == b'\r' {
            qual = &qual[..qual.len() - 1];
        }
        if !qual.is_empty() && qual[qual.len() - 1] == b'\n' {
            // special case for FASTQs that are a single character short on the
            // quality line, but still have a terminal newline
            let context = String::from_utf8_lossy(id);
            return Some(Err(ParseError::new(
                "Quality length was shorter than expected",
                ParseErrorType::PrematureEOF,
            )
            .context(context)));
        }

        self.pos += buffer_used;
        Some(Ok(Fastq { id, seq, id2, qual }))
    }
}

impl<'a> RecParser<'a> for FastqParser<'a> {
    type Header = ();

    fn from_buffer(buf: &[u8], last: bool) -> FastqParser {
        FastqParser { buf, last, pos: 0 }
    }

    fn header(&mut self) -> Result<Self::Header, ParseError> {
        Ok(())
    }

    fn eof(&self) -> Result<(), ParseError> {
        check_end(&self.buf[self.pos..], self.last)
    }

    fn used(&self) -> usize {
        self.pos
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use super::FastqParser;
    use crate::formats::buffer::{RecBuffer, RecParser};
    use crate::formats::parse_sequences;
    use crate::util::ParseErrorType;

    fn seq(s: &[u8]) -> Cursor<&[u8]> {
        Cursor::new(&s[..])
    }

    #[test]
    fn test_fastq() {
        let mut i = 0;
        let res = parse_sequences(
            seq(b"@test\nAGCT\n+test\n~~a!\n@test2\nTGCA\n+test\nWUI9"),
            |_| (),
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"test");
                        assert_eq!(&seq.seq[..], b"AGCT");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~a!");
                    }
                    1 => {
                        assert_eq!(&seq.id[..], b"test2");
                        assert_eq!(&seq.seq[..], b"TGCA");
                        assert_eq!(&seq.qual.unwrap()[..], b"WUI9");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(i, 2);
        assert_eq!(res, Ok(()));

        let mut i = 0;
        let res = parse_sequences(
            seq(b"@test\r\nAGCT\r\n+test\r\n~~a!\r\n@test2\r\nTGCA\r\n+test\r\nWUI9"),
            |_| {},
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"test");
                        assert_eq!(&seq.seq[..], b"AGCT");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~a!");
                    }
                    1 => {
                        assert_eq!(&seq.id[..], b"test2");
                        assert_eq!(&seq.seq[..], b"TGCA");
                        assert_eq!(&seq.qual.unwrap()[..], b"WUI9");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(res, Ok(()));
        assert_eq!(i, 2);
    }

    #[test]
    fn test_fastq_endings() {
        //! Check for the absence of a panic. The parser previously assumed
        //! if the ID ended with an `\r\n` then the sequence did also.
        //! (Discovered via fuzzing)
        let res = parse_sequences(seq(b"@\r\n\n+A\n@"), |_| (), |_seq| {});
        assert_eq!(res, Ok(()));
    }

    #[test]
    fn test_premature_endings() {
        let test = b"@test\nACGT\n+\nIII\n";
        let mut fp = FastqParser::new(test, true).unwrap();
        let result = fp.next().unwrap();
        assert!(result.is_err());
        let e = result.unwrap_err();
        assert!(e.error_type == ParseErrorType::PrematureEOF);

        let mut i = 0;
        let res = parse_sequences(
            seq(b"@test\nAGCT\n+test\n~~a!\n@test2\nTGCA"),
            |_| {},
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"test");
                        assert_eq!(&seq.seq[..], b"AGCT");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~a!");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(i, 1);
        let e = res.unwrap_err();
        assert_eq!(e.error_type, ParseErrorType::PrematureEOF);
        assert_eq!(e.record, 2);

        // we allow a few extra newlines at the ends of FASTQs
        let mut i = 0;
        let res = parse_sequences(
            seq(b"@test\nAGCT\n+test\n~~a!\n\n"),
            |_| {},
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"test");
                        assert_eq!(&seq.seq[..], b"AGCT");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~a!");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(i, 1);
        assert_eq!(res, Ok(()));

        // but if there's additional data past the newlines it's an error
        // note this is slightly easier to output than the "Sequence and
        // quality lengths differed" error because the end of the file may
        // normally have multiple newlines
        let mut i = 0;
        let res = parse_sequences(
            seq(b"@test\nAGCT\n+test\n~~a!\n\n@TEST\nA\n+TEST\n~"),
            |_| {},
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"test");
                        assert_eq!(&seq.seq[..], b"AGCT");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~a!");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(i, 1);
        let e = res.unwrap_err();
        assert_eq!(e.error_type, ParseErrorType::PrematureEOF);
        assert_eq!(e.record, 2);
    }

    #[test]
    fn test_empty_records() {
        let mut i = 0;
        let res = parse_sequences(
            seq(b"@\n\n+\n\n@test2\nTGCA\n+test2\n~~~~\n"),
            |stype| {
                assert_eq!(stype, "FASTQ");
            },
            |seq| {
                match i {
                    0 => {
                        assert_eq!(&seq.id[..], b"");
                        assert_eq!(&seq.seq[..], b"");
                        assert_eq!(&seq.qual.unwrap()[..], b"");
                    }
                    1 => {
                        assert_eq!(&seq.id[..], b"test2");
                        assert_eq!(&seq.seq[..], b"TGCA");
                        assert_eq!(&seq.qual.unwrap()[..], b"~~~~");
                    }
                    _ => unreachable!("Too many records"),
                }
                i += 1;
            },
        );
        assert_eq!(res, Ok(()));
        assert_eq!(i, 2);
    }

    #[test]
    fn test_mismatched_lengths() {
        let mut fp = FastqParser::new(b"@test\nAGCT\n+\nIII\n@TEST\nA\n+\nI", true).unwrap();
        let result = fp.next().unwrap();
        assert!(result.is_err());
        let e = result.unwrap_err();
        assert!(e.error_type == ParseErrorType::InvalidRecord);
        assert!(e.msg == "Sequence and quality lengths differed");

        let mut fp = FastqParser::new(b"@test\nAGCT\n+\nIIIII\n@TEST\nA\n+\nI", true).unwrap();
        let result = fp.next().unwrap();
        assert!(result.is_err());
        let e = result.unwrap_err();
        assert!(e.error_type == ParseErrorType::InvalidRecord);
        assert!(e.msg == "Sequence and quality lengths differed");
    }

    #[test]
    fn test_fastq_across_buffer() {
        let test_seq = b"@A\nA\n+A\nA\n@B\nA\n+B\n!";
        let mut cursor = Cursor::new(test_seq);
        // the buffer is aligned to the first record
        let mut rec_reader = RecBuffer::new(&mut cursor, 9, b"").unwrap();

        let used = {
            let mut rec_buffer = FastqParser::from_buffer(&rec_reader.buf, rec_reader.last);
            for _s in rec_buffer.by_ref() {
                // record is incomplete
                panic!("No initial record should be parsed")
            }
            rec_buffer.used()
        };

        // refill the buffer, but we're not done quite yet
        assert_eq!(rec_reader.refill(used).unwrap(), false);

        // now we should see both records
        let mut rec_buffer = FastqParser::from_buffer(&rec_reader.buf, rec_reader.last);

        // there should be a record assuming the parser
        // handled the buffer boundary
        let iterated_seq = rec_buffer.by_ref().next();
        let seq = iterated_seq.unwrap();
        assert_eq!(seq.unwrap().id, b"A");

        // but not another because the buffer's too short
        let iterated_seq = rec_buffer.by_ref().next();
        assert!(iterated_seq.is_none());

        // TODO: refill and check for the last record
    }
}
<|endoftext|>


<commit_before>//! Definition of the Shared combinator, a future that is cloneable,
//! and can be polled in multiple threads.
//!
//! # Examples
//!
//! ```
//! use futures::future::*;
//!
//! let future = ok::<_, bool>(6);
//! let shared1 = future.shared();
//! let shared2 = shared1.clone();
//! assert_eq!(6, *shared1.wait().unwrap());
//! assert_eq!(6, *shared2.wait().unwrap());
//! ```

use std::mem;
use std::sync::{Arc, Mutex, RwLock, TryLockError};
use std::sync::atomic::{AtomicBool, Ordering};
use std::ops::Deref;
use std::collections::HashMap;

use {Future, Poll, Async};
use task;

/// A future that is cloneable and can be polled in multiple threads.
/// Use Future::shared() method to convert any future into a `Shared` future.
#[must_use = "futures do nothing unless polled"]
pub struct Shared<F: Future> {
    id: u64,
    inner: Arc<Inner<F>>,
}

struct Inner<F: Future> {
    next_clone_id: Mutex<u64>,

    /// Only ever `Some` when `state` is `Waiting`. This is not part of the `State`
    /// enum because we want to be able to call `poll()` on the original future
    /// without holding a lock on `state`.
    original_future: Mutex<Option<F>>,

    state: RwLock<State<F>>,
}

enum State<F: Future> {
    Waiting(Arc<Unparker>),
    Done(Result<Arc<F::Item>, Arc<F::Error>>),
}

impl<F> Shared<F>
    where F: Future
{
    /// Creates a new `Shared` from another future.
    pub fn new(future: F) -> Self {
        Shared {
            id: 0,
            inner: Arc::new(
                Inner {
                    next_clone_id: Mutex::new(1),
                    original_future: Mutex::new(Some(future)),
                    state: RwLock::new(State::Waiting(Arc::new(Unparker::new()))),
                }),
        }
    }
}

impl<F> Future for Shared<F>
    where F: Future
{
    type Item = SharedItem<F::Item>;
    type Error = SharedError<F::Error>;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let state = self.inner.state.read().unwrap();
        let (mut original_future, event) = match *state {
            State::Waiting(ref unparker) => {
                match self.inner.original_future.try_lock() {
                    Ok(original_future) => {
                        if unparker.original_future_needs_poll.swap(false, Ordering::SeqCst) {
                            (original_future, task::UnparkEvent::new(unparker.clone(), 0))
                        } else {
                            unparker.insert(self.id, task::park());
                            return Ok(Async::NotReady)
                        }
                    }
                    Err(TryLockError::WouldBlock) => {
                        // This is recursive call to poll()! Try again later.
                        task::park().unpark();
                        return Ok(Async::NotReady)
                    }
                    Err(TryLockError::Poisoned(e)) => {
                        panic!("poisoned mutex: {:?}", e)
                    }
                }
            }
            State::Done(ref r) => {
                match *r {
                    Ok(ref v) => return Ok(SharedItem { item: v.clone() }.into()),
                    Err(ref e) => return Err(SharedError { error: e.clone() }.into()),
                }
            }
        };
        drop(state);

        let done_val = match *original_future {
            Some(ref mut future) => {
                match task::with_unpark_event(event, || future.poll()) {
                    Ok(Async::NotReady) => return Ok(Async::NotReady),
                    Ok(Async::Ready(v)) => Ok(Arc::new(v)),
                    Err(e) => Err(Arc::new(e)),
                }
            }
            None => unreachable!(),
        };

        // We can now drop the original future to free up any resources it holds.
        original_future.take();
        drop(original_future);

        let mut state = self.inner.state.write().unwrap();
        match mem::replace(&mut *state, State::Done(done_val.clone())) {
            State::Waiting(ref unparker) => unparker.unpark(),
            _ => unreachable!(),
        }
        drop(state);

        match done_val {
            Ok(v) => Ok(SharedItem { item: v }.into()),
            Err(e) => Err(SharedError { error: e }.into()),
        }
    }
}

impl<F> Clone for Shared<F>
    where F: Future
{
    fn clone(&self) -> Self {
        let mut next_clone_id = self.inner.next_clone_id.lock().unwrap();
        let clone_id = *next_clone_id;
        *next_clone_id += 1;
        Shared {
            id: clone_id,
            inner: self.inner.clone(),
        }
    }
}

impl<F: Future> Drop for Shared<F> {
    fn drop(&mut self) {
        let state = self.inner.state.read().unwrap();
        match *state {
            State::Waiting(ref unparker) => {
                unparker.remove(self.id);
            }
            State::Done(_) => (),
        }
    }
}

/// A wrapped item of the original future that is clonable and implements Deref
/// for ease of use.
#[derive(Debug)]
pub struct SharedItem<T> {
    item: Arc<T>,
}

impl<T> Deref for SharedItem<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.item.as_ref()
    }
}

/// A wrapped error of the original future that is clonable and implements Deref
/// for ease of use.
#[derive(Debug)]
pub struct SharedError<E> {
    error: Arc<E>,
}

impl<E> Deref for SharedError<E> {
    type Target = E;

    fn deref(&self) -> &E {
        &self.error.as_ref()
    }
}

/// An `EventSet` implementation for passing to `with_unpark_event()` when a `Shared`
/// polls its underlying future. Usually, the purpose of an `EventSet` implementation
/// is to gather precise information about what triggered an unpark, but that is *not*
/// what this implementation does. Instead, it uses `EventSet::insert()` as a hook
/// to unpark a set of waiting tasks.
struct Unparker {
    original_future_needs_poll: AtomicBool,

    /// Tasks that need to be unparked once the original future resolves.
    tasks: Mutex<HashMap<u64, task::Task>>,
}

impl task::EventSet for Unparker {
    fn insert(&self, _id: usize) {
        // The original future is ready to get polled again.
        self.unpark();
    }
}

impl Unparker {
    fn new() -> Unparker {
        Unparker {
            original_future_needs_poll: AtomicBool::new(true),
            tasks: Mutex::new(HashMap::new()),
        }
    }

    fn insert(&self, idx: u64, task: task::Task) {
        self.tasks.lock().unwrap().insert(idx, task);
    }

    fn remove(&self, idx: u64) {
        self.tasks.lock().unwrap().remove(&idx);
    }

    fn unpark(&self) {
        self.original_future_needs_poll.store(true, Ordering::SeqCst);
        let tasks = ::std::mem::replace(&mut *self.tasks.lock().unwrap(), HashMap::new());
        for (_, task) in tasks {
            task.unpark();
        }
    }
}
<commit_msg>improve comments for the TryLockError::WouldBlock case<commit_after>//! Definition of the Shared combinator, a future that is cloneable,
//! and can be polled in multiple threads.
//!
//! # Examples
//!
//! ```
//! use futures::future::*;
//!
//! let future = ok::<_, bool>(6);
//! let shared1 = future.shared();
//! let shared2 = shared1.clone();
//! assert_eq!(6, *shared1.wait().unwrap());
//! assert_eq!(6, *shared2.wait().unwrap());
//! ```

use std::mem;
use std::sync::{Arc, Mutex, RwLock, TryLockError};
use std::sync::atomic::{AtomicBool, Ordering};
use std::ops::Deref;
use std::collections::HashMap;

use {Future, Poll, Async};
use task;

/// A future that is cloneable and can be polled in multiple threads.
/// Use Future::shared() method to convert any future into a `Shared` future.
#[must_use = "futures do nothing unless polled"]
pub struct Shared<F: Future> {
    id: u64,
    inner: Arc<Inner<F>>,
}

struct Inner<F: Future> {
    next_clone_id: Mutex<u64>,

    /// Only ever `Some` when `state` is `Waiting`. This is not part of the `State`
    /// enum because we want to be able to call `poll()` on the original future
    /// without holding a lock on `state`.
    original_future: Mutex<Option<F>>,

    state: RwLock<State<F>>,
}

enum State<F: Future> {
    Waiting(Arc<Unparker>),
    Done(Result<Arc<F::Item>, Arc<F::Error>>),
}

impl<F> Shared<F>
    where F: Future
{
    /// Creates a new `Shared` from another future.
    pub fn new(future: F) -> Self {
        Shared {
            id: 0,
            inner: Arc::new(
                Inner {
                    next_clone_id: Mutex::new(1),
                    original_future: Mutex::new(Some(future)),
                    state: RwLock::new(State::Waiting(Arc::new(Unparker::new()))),
                }),
        }
    }
}

impl<F> Future for Shared<F>
    where F: Future
{
    type Item = SharedItem<F::Item>;
    type Error = SharedError<F::Error>;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let state = self.inner.state.read().unwrap();
        let (mut original_future, event) = match *state {
            State::Waiting(ref unparker) => {
                match self.inner.original_future.try_lock() {
                    Ok(original_future) => {
                        if unparker.original_future_needs_poll.swap(false, Ordering::SeqCst) {
                            (original_future, task::UnparkEvent::new(unparker.clone(), 0))
                        } else {
                            unparker.insert(self.id, task::park());
                            return Ok(Async::NotReady)
                        }
                    }
                    Err(TryLockError::WouldBlock) => {
                        // A clone of this `Shared`, possibly on the current thread, holds the mutex.
                        // The mutex will become unlocked again after that clone finishes calling
                        // original_future.poll(). We yield and then try again, in hopes that
                        // the original_future.poll() call finishes quickly.
                        //
                        // TODO(perf): Is there a better way to deal with the case where the poll()
                        // does not finish quickly? Does the kind of situation where that might
                        // matter actually arise much in practice?
                        task::park().unpark();
                        return Ok(Async::NotReady)
                    }
                    Err(TryLockError::Poisoned(e)) => {
                        panic!("poisoned mutex: {:?}", e)
                    }
                }
            }
            State::Done(ref r) => {
                match *r {
                    Ok(ref v) => return Ok(SharedItem { item: v.clone() }.into()),
                    Err(ref e) => return Err(SharedError { error: e.clone() }.into()),
                }
            }
        };
        drop(state);

        let done_val = match *original_future {
            Some(ref mut future) => {
                match task::with_unpark_event(event, || future.poll()) {
                    Ok(Async::NotReady) => return Ok(Async::NotReady),
                    Ok(Async::Ready(v)) => Ok(Arc::new(v)),
                    Err(e) => Err(Arc::new(e)),
                }
            }
            None => unreachable!(),
        };

        // We can now drop the original future to free up any resources it holds.
        original_future.take();
        drop(original_future);

        let mut state = self.inner.state.write().unwrap();
        match mem::replace(&mut *state, State::Done(done_val.clone())) {
            State::Waiting(ref unparker) => unparker.unpark(),
            _ => unreachable!(),
        }
        drop(state);

        match done_val {
            Ok(v) => Ok(SharedItem { item: v }.into()),
            Err(e) => Err(SharedError { error: e }.into()),
        }
    }
}

impl<F> Clone for Shared<F>
    where F: Future
{
    fn clone(&self) -> Self {
        let mut next_clone_id = self.inner.next_clone_id.lock().unwrap();
        let clone_id = *next_clone_id;
        *next_clone_id += 1;
        Shared {
            id: clone_id,
            inner: self.inner.clone(),
        }
    }
}

impl<F: Future> Drop for Shared<F> {
    fn drop(&mut self) {
        let state = self.inner.state.read().unwrap();
        match *state {
            State::Waiting(ref unparker) => {
                unparker.remove(self.id);
            }
            State::Done(_) => (),
        }
    }
}

/// A wrapped item of the original future that is clonable and implements Deref
/// for ease of use.
#[derive(Debug)]
pub struct SharedItem<T> {
    item: Arc<T>,
}

impl<T> Deref for SharedItem<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.item.as_ref()
    }
}

/// A wrapped error of the original future that is clonable and implements Deref
/// for ease of use.
#[derive(Debug)]
pub struct SharedError<E> {
    error: Arc<E>,
}

impl<E> Deref for SharedError<E> {
    type Target = E;

    fn deref(&self) -> &E {
        &self.error.as_ref()
    }
}

/// An `EventSet` implementation for passing to `with_unpark_event()` when a `Shared`
/// polls its underlying future. Usually, the purpose of an `EventSet` implementation
/// is to gather precise information about what triggered an unpark, but that is *not*
/// what this implementation does. Instead, it uses `EventSet::insert()` as a hook
/// to unpark a set of waiting tasks.
struct Unparker {
    original_future_needs_poll: AtomicBool,

    /// Tasks that need to be unparked once the original future resolves.
    tasks: Mutex<HashMap<u64, task::Task>>,
}

impl task::EventSet for Unparker {
    fn insert(&self, _id: usize) {
        // The original future is ready to get polled again.
        self.unpark();
    }
}

impl Unparker {
    fn new() -> Unparker {
        Unparker {
            original_future_needs_poll: AtomicBool::new(true),
            tasks: Mutex::new(HashMap::new()),
        }
    }

    fn insert(&self, idx: u64, task: task::Task) {
        self.tasks.lock().unwrap().insert(idx, task);
    }

    fn remove(&self, idx: u64) {
        self.tasks.lock().unwrap().remove(&idx);
    }

    fn unpark(&self) {
        self.original_future_needs_poll.store(true, Ordering::SeqCst);
        let tasks = ::std::mem::replace(&mut *self.tasks.lock().unwrap(), HashMap::new());
        for (_, task) in tasks {
            task.unpark();
        }
    }
}
<|endoftext|>


<commit_before>
use util;
use std;

pub type Result<T> = std::result::Result<T,String>;

/// A token.
#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Token
{
    Word(String),

    StringLiteral(String),
    // TODO: use BigNum
    IntegerLiteral(i64),

    Symbol(String),

    NewLine,
    EOF,
}

/// An iterator over a set of characters.
///
/// This type abstracts over another iterator of characters,
/// making sure that the yielded characters will have a specific
/// format.
///
/// * There will always be a new line (`\n`) before the end of file.
pub struct Characters<I: Iterator<Item=char>>
{
    it: std::iter::Peekable<I>,
    finished: bool,
    peek_buf: Option<char>,
}

impl<I> Characters<I>
    where I: Iterator<Item=char>
{
    pub fn new(it: I) -> Self {
        Characters {
            it: it.peekable(),
            finished: false,
            peek_buf: None,
        }
    }

    pub fn peek(&mut self) -> Option<char> {
        if self.peek_buf.is_none() {
            self.peek_buf = self.next();
        }

        self.peek_buf
    }

    pub fn eat_while<P>(&mut self, predicate: P)
        where P: FnMut(char) -> bool {
        self.consume_while(predicate);
    }

    pub fn consume_while<P>(&mut self, mut predicate: P)
        -> std::vec::IntoIter<char>
        where P: FnMut(char) -> bool {
        let mut result = Vec::new();

        loop {
            let c = match self.peek() {
                Some(c) => c,
                None => break,
            };

            if predicate(c) {
                result.push(self.next().unwrap());
            } else {
                break;
            }
        }

        result.into_iter()
    }
}

impl<I> Iterator for Characters<I>
    where I: Iterator<Item=char>
{
    type Item = char;

    fn next(&mut self) -> Option<char> {
        if self.peek_buf.is_some() {
            let c = self.peek_buf.unwrap();
            self.peek_buf = None;
            return Some(c);
        }

        match self.it.next() {
            Some(c) => Some(c),
            None => {
                if self.finished {
                    None
                } else { // When we first reach the EOF
                    self.finished = true;
                    Some('\n')
                }
            },
        }
    }
}

pub struct Tokenizer<I: Iterator<Item=char>>
{
    chars: Characters<I>,
}

impl<I> Tokenizer<I>
    where I: Iterator<Item=char>
{
    pub fn new(chars: I) -> Self {
        Tokenizer {
            chars: Characters::new(chars),
        }
    }

    fn eat_whitespace(&mut self) {
        self.chars.eat_while(|c| c.is_whitespace() && c != '\n')
    }

    fn next_string(&mut self) -> Option<Result<Token>> {
        self.assert('"');
        let string = self.chars.consume_while(|c| c != '\"');
        self.assert('"');

        Some(Ok(Token::StringLiteral(string.collect())))
    }

    fn next_symbol(&mut self) -> Option<Result<Token>> {
        unimplemented!();
    }

    fn assert(&mut self, expected: char) -> char {
        self.expect(expected).expect("unexpected character")
    }

    fn expect(&mut self, expected: char) -> Result<char> {
        // TODO: more specific error message
        self.expect_one_of(&[expected])
    }

    fn assert_one_of(&mut self, expected: &[char]) -> char {
        self.expect_one_of(expected)
            .expect("unexpected character")
    }

    fn expect_one_of(&mut self, expected: &[char]) -> Result<char> {
        let expected_str = util::comma_separated_values(expected.iter());

        let next = match self.chars.next() {
            Some(c) => c,
            None => {
                return Err(format!("expected one of {} but got nothing", expected_str))
            },
        };

        if expected.iter().any(|&c| c == next) {
            Ok(next)
        } else {
            Err(format!("Expected one of {} but got {}", expected_str, next))
        }
    }
}

impl<I> Iterator for Tokenizer<I>
    where I: Iterator<Item=char>
{
    type Item = Result<Token>;

    fn next(&mut self) -> Option<Result<Token>> {
        self.eat_whitespace();

        let first_char = match self.chars.peek() {
            Some(c) => c,
            None => return None,
        };

        if first_char == '"' {
            self.next_string()
        } else {
            self.next_symbol()
        }
    }
}

mod test
{
    use super::{Token,Tokenizer};

    macro_rules! expect_tokenize_into {
        // TODO: make the macro take several arguments
        // for several outputs
        ($input:expr => $( $output:expr ),* ) => {
            {
                let mut tokenizer = Tokenizer::new($input.chars());

                $(
                    assert_eq!(tokenizer.next().unwrap().unwrap(), $output);
                )*
            }
        }
    }

    #[test]
    fn test_string() {
        expect_tokenize_into!("\"hello\"" =>  Token::StringLiteral("hello".into()));
        expect_tokenize_into!("\"hello abc\"" => Token::StringLiteral("hello abc".into()));

        expect_tokenize_into!("\"hello world\"  \"it is me\"" =>
                              Token::StringLiteral("hello world".into()),
                              Token::StringLiteral("it is me".into()));
    }
}
<commit_msg>Added word tokenization<commit_after>
use util;
use std;
use std::error::Error;

pub type Result<T> = std::result::Result<T,String>;

/// A token.
#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Token
{
    Word(String),

    StringLiteral(String),
    // TODO: use BigNum
    IntegerLiteral(i64),

    Symbol(String),

    NewLine,
    EOF,
}

impl Token
{
    pub fn word<S>(word: S) -> Self
        where S: Into<String> {
        Token::Word(word.into())
    }

    pub fn string<S>(string: S) -> Self
        where S: Into<String> {
        Token::StringLiteral(string.into())
    }

    pub fn integer<I>(integer: I) -> Self
        where I: Into<i64> {
        Token::IntegerLiteral(integer.into())
    }

    pub fn symbol<S>(symbol: S) -> Self
        where S: Into<String> {
        Token::Symbol(symbol.into())
    }

    pub fn new_line() -> Self {
        Token::NewLine
    }

    pub fn eof() -> Self {
        Token::EOF
    }
}

/// An iterator over a set of characters.
///
/// This type abstracts over another iterator of characters,
/// making sure that the yielded characters will have a specific
/// format.
///
/// * There will always be a new line (`\n`) before the end of file.
pub struct Characters<I: Iterator<Item=char>>
{
    it: std::iter::Peekable<I>,
    finished: bool,
    peek_buf: Option<char>,
}

impl<I> Characters<I>
    where I: Iterator<Item=char>
{
    pub fn new(it: I) -> Self {
        Characters {
            it: it.peekable(),
            finished: false,
            peek_buf: None,
        }
    }

    pub fn peek(&mut self) -> Option<char> {
        if self.peek_buf.is_none() {
            self.peek_buf = self.next();
        }

        self.peek_buf
    }

    pub fn eat_while<P>(&mut self, predicate: P)
        where P: FnMut(char) -> bool {
        self.consume_while(predicate);
    }

    pub fn consume_while<P>(&mut self, mut predicate: P)
        -> std::vec::IntoIter<char>
        where P: FnMut(char) -> bool {
        let mut result = Vec::new();

        loop {
            let c = match self.peek() {
                Some(c) => c,
                None => break,
            };

            if predicate(c) {
                result.push(self.next().unwrap());
            } else {
                break;
            }
        }

        result.into_iter()
    }
}

impl<I> Iterator for Characters<I>
    where I: Iterator<Item=char>
{
    type Item = char;

    fn next(&mut self) -> Option<char> {
        if self.peek_buf.is_some() {
            let c = self.peek_buf.unwrap();
            self.peek_buf = None;
            return Some(c);
        }

        match self.it.next() {
            Some(c) => Some(c),
            None => {
                if self.finished {
                    None
                } else { // When we first reach the EOF
                    self.finished = true;
                    Some('\n')
                }
            },
        }
    }
}

pub struct Tokenizer<I: Iterator<Item=char>>
{
    chars: Characters<I>,
}

impl<I> Tokenizer<I>
    where I: Iterator<Item=char>
{
    pub fn new(chars: I) -> Self {
        Tokenizer {
            chars: Characters::new(chars),
        }
    }

    fn eat_whitespace(&mut self) {
        self.chars.eat_while(|c| c.is_whitespace() && c != '\n')
    }

    fn next_string(&mut self) -> Option<Result<Token>> {
        self.assert('"');
        let string = self.chars.consume_while(|c| c != '\"');
        self.assert('"');

        Some(Ok(Token::StringLiteral(string.collect())))
    }

    fn next_integer(&mut self) -> Option<Result<Token>> {
        let string: String = self.chars.consume_while(|c| c.is_numeric()).collect();

        let int = match i64::from_str_radix(&string, 10) {
            Ok(int) => int,
            Err(e) => return Some(Err(format!("Could not parse integer: {}",
                                              e.description()))),
        };

        Some(Ok(Token::IntegerLiteral(int)))
    }

    fn next_word(&mut self) -> Option<Result<Token>> {
        let word: String = self.chars.consume_while(internal::can_word_contain).collect();

        Some(Ok(Token::Word(word)))
    }

    fn next_symbol(&mut self) -> Option<Result<Token>> {
        unimplemented!();
    }

    fn assert(&mut self, expected: char) -> char {
        self.expect(expected).expect("unexpected character")
    }

    fn expect(&mut self, expected: char) -> Result<char> {
        // TODO: more specific error message
        self.expect_one_of(&[expected])
    }

    fn assert_one_of(&mut self, expected: &[char]) -> char {
        self.expect_one_of(expected)
            .expect("unexpected character")
    }

    fn expect_one_of(&mut self, expected: &[char]) -> Result<char> {
        let expected_str = util::comma_separated_values(expected.iter());

        let next = match self.chars.next() {
            Some(c) => c,
            None => {
                return Err(format!("expected one of {} but got nothing", expected_str))
            },
        };

        if expected.iter().any(|&c| c == next) {
            Ok(next)
        } else {
            Err(format!("Expected one of {} but got {}", expected_str, next))
        }
    }
}

impl<I> Iterator for Tokenizer<I>
    where I: Iterator<Item=char>
{
    type Item = Result<Token>;

    fn next(&mut self) -> Option<Result<Token>> {
        self.eat_whitespace();

        let first_char = match self.chars.peek() {
            Some(c) => c,
            None => return None,
        };

        if first_char == '"' {
            self.next_string()
        } else if first_char.is_numeric() {
            self.next_integer()
        } else if internal::can_word_start_with(first_char) {
            self.next_word()
        } else {
            self.next_symbol()
        }
    }
}

mod internal
{
    pub fn can_word_start_with(c: char) -> bool {
        c.is_alphabetic() || c == '_'
    }

    pub fn can_word_contain(c: char) -> bool {
        can_word_start_with(c) || c.is_numeric()
    }
}

mod test
{
    use super::{Token,Tokenizer};

    macro_rules! expect_tokenize_into {
        // TODO: make the macro take several arguments
        // for several outputs
        ($input:expr => $( $output:expr ),* ) => {
            {
                let mut tokenizer = Tokenizer::new($input.chars());

                $(
                    assert_eq!(tokenizer.next().unwrap().unwrap(), $output);
                )*
            }
        }
    }

    #[test]
    fn test_string() {
        expect_tokenize_into!("\"hello\"" =>  Token::StringLiteral("hello".into()));
        expect_tokenize_into!("\"hello abc\"" => Token::StringLiteral("hello abc".into()));

        expect_tokenize_into!("\"hello world\"  \"it is me\"" =>
                              Token::StringLiteral("hello world".into()),
                              Token::StringLiteral("it is me".into()));
    }

    #[test]
    fn test_integer() {
        expect_tokenize_into!("123" => Token::IntegerLiteral(123));
        expect_tokenize_into!("0982" => Token::IntegerLiteral(982));
        expect_tokenize_into!("333 662" => Token::IntegerLiteral(333),
                                           Token::IntegerLiteral(662));
        expect_tokenize_into!("1 2 3 4" => Token::IntegerLiteral(1),
                                           Token::IntegerLiteral(2),
                                           Token::IntegerLiteral(3),
                                           Token::IntegerLiteral(4));
    }

    #[test]
    fn test_word() {
        expect_tokenize_into!("hello" => Token::word("hello"));
        expect_tokenize_into!("ab cd" => Token::word("ab"),
                                         Token::word("cd"));
        expect_tokenize_into!("a b c d" => Token::word("a"),
                                           Token::word("b"),
                                           Token::word("c"),
                                           Token::word("d"));
    }
}
<|endoftext|>


<commit_before>use ::kdtree::*;

pub struct Bounds {
    pub bounds: Vec<(f64, f64)>
}

impl Bounds {
    pub fn new_from_points<T: KdtreePointTrait>(points: &Vec<T>) -> Bounds {
        let mut bounds = Bounds {
            bounds: vec![],
        };

        bounds.bounds.resize(points[0].dims().len(), (0., 0.));

        for i in 0..points[0].dims().len() {
            bounds.bounds[i].0 = points[0].dims()[i];
            bounds.bounds[i].1 = points[0].dims()[i];
        }

        for v in points.iter() {
            for dim in 0..v.dims().len() {
                bounds.bounds[dim].0 = bounds.bounds[dim].0.min(v.dims()[dim]);
                bounds.bounds[dim].1 = bounds.bounds[dim].1.max(v.dims()[dim]);
            }
        }

        bounds
    }

    pub fn get_widest_dim(&self) -> usize {
        let mut widest_dimension = 0usize;
        let mut max_found_spread = self.bounds[0].1 - self.bounds[0].0;

        for i in 0..self.bounds.len() {
            let dimension_spread = self.bounds[i].1 - self.bounds[i].0;

            if dimension_spread > max_found_spread {
                max_found_spread = dimension_spread;
                widest_dimension = i;
            }
        }

        widest_dimension
    }

    pub fn get_midvalue_of_widest_dim(&self) -> f64 {
        (self.bounds[self.get_widest_dim()].0 + self.bounds[self.get_widest_dim()].1) / 2.0
    }

    pub fn clone_moving_max(&self, value: f64, dimension: usize) -> Bounds {
        let mut cloned = Bounds {
            bounds: self.bounds.clone()
        };
        cloned.bounds[dimension].1 = value;

        cloned
    }

    pub fn clone_moving_min(&self, value: f64, dimension: usize) -> Bounds {
        let mut cloned = Bounds {
            bounds: self.bounds.clone()
        };
        cloned.bounds[dimension].0 = value;

        cloned
    }
}

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

    #[test]
    fn bounds_test() {
        let p1 = Point2WithId::new(1, 1.0, 0.5);
        let p2 = Point2WithId::new(1, 3.0, 4.0);
        let v = vec![p1, p2];

        let bounds = Bounds::new_from_points(&v);

        assert_eq!((1., 3.0), bounds.bounds[0]);
        assert_eq!((0.5, 4.0), bounds.bounds[1]);

        assert_eq!(1, bounds.get_widest_dim());
    }
}<commit_msg>Caching values for bounds.rs<commit_after>use ::kdtree::*;

pub struct Bounds {
    pub bounds: Vec<(f64, f64)>,

    widest_dim : usize,
    midvalue_of_widest_dim : f64,
}

impl Bounds {
    pub fn new_from_points<T: KdtreePointTrait>(points: &Vec<T>) -> Bounds {
        let mut bounds = Bounds {
            bounds: vec![],
            widest_dim : 0,
            midvalue_of_widest_dim : 0.,
        };

        bounds.bounds.resize(points[0].dims().len(), (0., 0.));

        for i in 0..points[0].dims().len() {
            bounds.bounds[i].0 = points[0].dims()[i];
            bounds.bounds[i].1 = points[0].dims()[i];
        }

        for v in points.iter() {
            for dim in 0..v.dims().len() {
                bounds.bounds[dim].0 = bounds.bounds[dim].0.min(v.dims()[dim]);
                bounds.bounds[dim].1 = bounds.bounds[dim].1.max(v.dims()[dim]);
            }
        }

        bounds.calculate_variables();

        bounds
    }

    pub fn get_widest_dim(&self) -> usize {
        self.widest_dim
    }

    pub fn get_midvalue_of_widest_dim(&self) -> f64 {
        self.midvalue_of_widest_dim
    }

    pub fn clone_moving_max(&self, value: f64, dimension: usize) -> Bounds {
        let mut cloned = Bounds {
            bounds: self.bounds.clone(),
            ..*self
        };
        cloned.bounds[dimension].1 = value;

        cloned.calculate_variables();

        cloned
    }

    pub fn clone_moving_min(&self, value: f64, dimension: usize) -> Bounds {
        let mut cloned = Bounds {
            bounds: self.bounds.clone(),
            ..*self
        };
        cloned.bounds[dimension].0 = value;

        cloned.calculate_variables();

        cloned
    }

    fn calculate_widest_dim(&mut self)  {
        let mut widest_dimension = 0usize;
        let mut max_found_spread = self.bounds[0].1 - self.bounds[0].0;

        for i in 0..self.bounds.len() {
            let dimension_spread = self.bounds[i].1 - self.bounds[i].0;

            if dimension_spread > max_found_spread {
                max_found_spread = dimension_spread;
                widest_dimension = i;
            }
        }

        self.widest_dim = widest_dimension;
    }

    fn calculate_variables(&mut self) {
        self.calculate_widest_dim();
        self.midvalue_of_widest_dim = (self.bounds[self.get_widest_dim()].0 + self.bounds[self.get_widest_dim()].1) / 2.0;
    }
}

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

    #[test]
    fn bounds_test() {
        let p1 = Point2WithId::new(1, 1.0, 0.5);
        let p2 = Point2WithId::new(1, 3.0, 4.0);
        let v = vec![p1, p2];

        let bounds = Bounds::new_from_points(&v);

        assert_eq!((1., 3.0), bounds.bounds[0]);
        assert_eq!((0.5, 4.0), bounds.bounds[1]);

        assert_eq!(1, bounds.get_widest_dim());
    }
}<|endoftext|>


<commit_before>
extern crate regex;

use std::process::{Command, Stdio, Child};
use std::error::Error;
use std::io::prelude::*;
use std::io::BufReader;
use std::io;
use std::ascii::AsciiExt;
use lib::config::ConfigGen;
use std::convert::Into;

use lib::downloader::DownloadError;

use mysql::conn::pool::{MyPool,MyPooledConn};
use mysql::conn::Stmt;

macro_rules! regex(
    ($s:expr) => (regex::Regex::new($s).unwrap());
);

pub struct Converter<'a> {
    pub ffmpeg_cmd: &'a str,
    pub audio_quality: &'a i16,
    pub pool: MyPool,
}

impl<'a> Converter<'a> {
    pub fn new(ffmpeg_cmd: &'a str, audio_quality: &'a i16, pool: MyPool) -> Converter<'a> {
        Converter{ffmpeg_cmd: ffmpeg_cmd, audio_quality: audio_quality, pool: pool}
    }

    ///Merge audo & video file to one, using ffmpeg, saving directly at the dest. folder
    pub fn merge_files(&self, qid: &i64, video_file: &'a str,audio_file: &'a str, output_file: &'a str) -> Result<(), DownloadError>{
        let process = try!(self.create_merge_cmd(audio_file, video_file, output_file));
        let stdout = BufReader::new(process.stdout.unwrap());
        let mut stderr_buffer = BufReader::new(process.stderr.unwrap());

        let mut conn = self.pool.get_conn().unwrap();
        let mut statement = self.prepare_progress_updater(&mut conn);
        let re = regex!(r"\d+\.\d");

        for line in stdout.lines(){
            match line{
                Err(why) => panic!("couldn't read cmd stdout: {}", Error::description(&why)),
                Ok(text) => {
                        println!("Out: {}",text);
                        match re.find(&text) {
                            Some(s) => { println!("Match at {}", s.0);
                                        println!("{}", &text[s.0..s.1]); // ONLY with ASCII chars makeable!
                                        self.update_progress(&mut statement, &text[s.0..s.1].to_string(), qid);
                                    },
                            None => println!("Detected no % match."),
                        }
                    },
            }
        }

        let mut stderr: String = String::new();
        try!(stderr_buffer.read_to_string(&mut stderr));
        println!("Stderr: {}", stderr);

        Ok(())
    }

    ///Merges an audio & an video file together.
    ///Due to ffmpeg not giving out new lines we need to use tr, till the ffmpeg bindings are better
    ///This removes the option to use .arg() -> params must be handled carefully
    fn create_merge_cmd(&self, audio_file: &str, video_file: &str, output_file: &str) -> Result<Child,DownloadError> {
        try!(self.create_bash_cmd(self.format_ffmpeg_cmd(audio_file, video_file, output_file))))
    }

    ///Creates a cmd to gain the amount of frames in a video, for progress calculation
    fn create_fps_get_cmd(&self, video_file: &str) -> Result<Child, DownloadError> {
        try!(self.create_bash_cmd(self.format_fps_get_cmd(video_file)))
    }

    ///Create an bash cmd
    fn create_bash_cmd(&self, cmd: String) -> Result<Child, DownloadError> {
        match Command::new("bash")
                                        .arg("-c")
                                        .arg(cmd)
                                        .stdin(Stdio::null())
                                        .stdout(Stdio::piped())
                                        .stderr(Stdio::piped())
                                        .spawn() {
                Err(why) => Err(DownloadError::InternalError(Error::description(&why).into())),
                Ok(process) => Ok(process),
        }
    }

    ///Formats a command to gain the total amount of frames in a video file
    ///which will be used for the progress calculation
    fn format_frame_get_cmd(&self, video_file: &str) -> String {
        let a = format!(r#"ffmpeg -i {} -vcodec copy -acodec copy -f null /dev/null 2>&1 | grep 'frame=' | cut -f 2 -d ' '"#, video_file);
        println!("ffmpeg-fps cmd: {}", a);
        a
    }

    ///Creates a ffmpeg_cmd containing the path to ffmpeg, as defined in the config
    ///and all the needed arguments, which can't be set using .arg, see create_merge_cmd.
    fn format_ffmpeg_cmd(&self, audio_file: &str, video_file: &str, output_file: &str) -> String {
        let a = format!(r#"{} -stats -threads 0 -i "{}" -i "{}" -map 0 -map 1 -codec copy -shortest "{}" 2>&1 |& tr '\r' '\n'"#,
            self.ffmpeg_cmd,
            video_file,
            audio_file,
            output_file);
        println!("ffmpeg cmd: {}", a);
        a
    }

    // MyPooledConn does only live when MyOpts is alive -> lifetime needs to be declared
    //TODO: think about generalizing this, while using the local pool
    fn prepare_progress_updater(&'a self,conn: &'a mut MyPooledConn) -> Stmt<'a> { // no livetime needed: struct livetime used
        conn.prepare("UPDATE querydetails SET progress = ? WHERE qid = ?").unwrap()
    }

    ///updater called from the stdout progress
    fn update_progress(&self,stmt: &mut Stmt, progress: &String, qid: &i64){
        stmt.execute(&[progress,qid]);
    }
}<commit_msg>*bugfix [untested]<commit_after>
extern crate regex;

use std::process::{Command, Stdio, Child};
use std::error::Error;
use std::io::prelude::*;
use std::io::BufReader;
use std::io;
use std::ascii::AsciiExt;
use lib::config::ConfigGen;
use std::convert::Into;

use lib::downloader::DownloadError;

use mysql::conn::pool::{MyPool,MyPooledConn};
use mysql::conn::Stmt;

macro_rules! regex(
    ($s:expr) => (regex::Regex::new($s).unwrap());
);

pub struct Converter<'a> {
    pub ffmpeg_cmd: &'a str,
    pub audio_quality: &'a i16,
    pub pool: MyPool,
}

impl<'a> Converter<'a> {
    pub fn new(ffmpeg_cmd: &'a str, audio_quality: &'a i16, pool: MyPool) -> Converter<'a> {
        Converter{ffmpeg_cmd: ffmpeg_cmd, audio_quality: audio_quality, pool: pool}
    }

    ///Merge audo & video file to one, using ffmpeg, saving directly at the dest. folder
    pub fn merge_files(&self, qid: &i64, video_file: &'a str,audio_file: &'a str, output_file: &'a str) -> Result<(), DownloadError>{
        let process = try!(self.create_merge_cmd(audio_file, video_file, output_file));
        let stdout = BufReader::new(process.stdout.unwrap());
        let mut stderr_buffer = BufReader::new(process.stderr.unwrap());

        let mut conn = self.pool.get_conn().unwrap();
        let mut statement = self.prepare_progress_updater(&mut conn);
        let re = regex!(r"\d+\.\d");

        for line in stdout.lines(){
            match line{
                Err(why) => panic!("couldn't read cmd stdout: {}", Error::description(&why)),
                Ok(text) => {
                        println!("Out: {}",text);
                        match re.find(&text) {
                            Some(s) => { println!("Match at {}", s.0);
                                        println!("{}", &text[s.0..s.1]); // ONLY with ASCII chars makeable!
                                        self.update_progress(&mut statement, &text[s.0..s.1].to_string(), qid);
                                    },
                            None => println!("Detected no % match."),
                        }
                    },
            }
        }

        let mut stderr: String = String::new();
        try!(stderr_buffer.read_to_string(&mut stderr));
        println!("Stderr: {}", stderr);

        Ok(())
    }

    ///Merges an audio & an video file together.
    ///Due to ffmpeg not giving out new lines we need to use tr, till the ffmpeg bindings are better
    ///This removes the option to use .arg() -> params must be handled carefully
    fn create_merge_cmd(&self, audio_file: &str, video_file: &str, output_file: &str) -> Result<Child,DownloadError> {
        try!(self.create_bash_cmd(self.format_ffmpeg_cmd(audio_file, video_file, output_file)))
    }

    ///Creates a cmd to gain the amount of frames in a video, for progress calculation
    fn create_fps_get_cmd(&self, video_file: &str) -> Result<Child, DownloadError> {
        try!(self.create_bash_cmd(self.format_frame_get_cmd(video_file)))
    }

    ///Create an bash cmd
    fn create_bash_cmd(&self, cmd: String) -> Result<Child, DownloadError> {
        match Command::new("bash")
                                        .arg("-c")
                                        .arg(cmd)
                                        .stdin(Stdio::null())
                                        .stdout(Stdio::piped())
                                        .stderr(Stdio::piped())
                                        .spawn() {
                Err(why) => Err(DownloadError::InternalError(Error::description(&why).into())),
                Ok(process) => Ok(process),
        }
    }

    ///Formats a command to gain the total amount of frames in a video file
    ///which will be used for the progress calculation
    fn format_frame_get_cmd(&self, video_file: &str) -> String {
        let a = format!(r#"ffmpeg -i {} -vcodec copy -acodec copy -f null /dev/null 2>&1 | grep 'frame=' | cut -f 2 -d ' '"#, video_file);
        println!("ffmpeg-fps cmd: {}", a);
        a
    }

    ///Creates a ffmpeg_cmd containing the path to ffmpeg, as defined in the config
    ///and all the needed arguments, which can't be set using .arg, see create_merge_cmd.
    fn format_ffmpeg_cmd(&self, audio_file: &str, video_file: &str, output_file: &str) -> String {
        let a = format!(r#"{} -stats -threads 0 -i "{}" -i "{}" -map 0 -map 1 -codec copy -shortest "{}" 2>&1 |& tr '\r' '\n'"#,
            self.ffmpeg_cmd,
            video_file,
            audio_file,
            output_file);
        println!("ffmpeg cmd: {}", a);
        a
    }

    // MyPooledConn does only live when MyOpts is alive -> lifetime needs to be declared
    //TODO: think about generalizing this, while using the local pool
    fn prepare_progress_updater(&'a self,conn: &'a mut MyPooledConn) -> Stmt<'a> { // no livetime needed: struct livetime used
        conn.prepare("UPDATE querydetails SET progress = ? WHERE qid = ?").unwrap()
    }

    ///updater called from the stdout progress
    fn update_progress(&self,stmt: &mut Stmt, progress: &String, qid: &i64){
        stmt.execute(&[progress,qid]);
    }
}<|endoftext|>


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

//! Borrowed pointer utilities

#[cfg(not(test))]
use prelude::*;

/// Cast a region pointer - &T - to a uint.
#[inline]
pub fn to_uint<T>(thing: &T) -> uint {
    thing as *T as uint
}

/// Determine if two borrowed pointers point to the same thing.
#[inline]
pub fn ref_eq<'a, 'b, T>(thing: &'a T, other: &'b T) -> bool {
    to_uint(thing) == to_uint(other)
}

// Equality for region pointers
#[cfg(not(test))]
impl<'self, T: Eq> Eq for &'self T {
    #[inline]
    fn eq(&self, other: & &'self T) -> bool {
        *(*self) == *(*other)
    }
    #[inline]
    fn ne(&self, other: & &'self T) -> bool {
        *(*self) != *(*other)
    }
}

// Comparison for region pointers
#[cfg(not(test))]
impl<'self, T: Ord> Ord for &'self T {
    #[inline]
    fn lt(&self, other: & &'self T) -> bool {
        *(*self) < *(*other)
    }
    #[inline]
    fn le(&self, other: & &'self T) -> bool {
        *(*self) <= *(*other)
    }
    #[inline]
    fn ge(&self, other: & &'self T) -> bool {
        *(*self) >= *(*other)
    }
    #[inline]
    fn gt(&self, other: & &'self T) -> bool {
        *(*self) > *(*other)
    }
}

#[cfg(not(test))]
impl<'self, T: TotalOrd> TotalOrd for &'self T {
    #[inline]
    fn cmp(&self, other: & &'self T) -> Ordering { (**self).cmp(*other) }
}

#[cfg(not(test))]
impl<'self, T: TotalEq> TotalEq for &'self T {
    #[inline]
    fn equals(&self, other: & &'self T) -> bool { (**self).equals(*other) }
}
<commit_msg>auto merge of #9292 : blake2-ppc/rust/borrow-ref-eq, r=huonw<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Borrowed pointer utilities

#[cfg(not(test))]
use prelude::*;

/// Cast a region pointer - &T - to a uint.
#[inline]
pub fn to_uint<T>(thing: &T) -> uint {
    thing as *T as uint
}

/// Determine if two borrowed pointers point to the same thing.
#[inline]
pub fn ref_eq<'a, 'b, T>(thing: &'a T, other: &'b T) -> bool {
    (thing as *T) == (other as *T)
}

// Equality for region pointers
#[cfg(not(test))]
impl<'self, T: Eq> Eq for &'self T {
    #[inline]
    fn eq(&self, other: & &'self T) -> bool {
        *(*self) == *(*other)
    }
    #[inline]
    fn ne(&self, other: & &'self T) -> bool {
        *(*self) != *(*other)
    }
}

// Comparison for region pointers
#[cfg(not(test))]
impl<'self, T: Ord> Ord for &'self T {
    #[inline]
    fn lt(&self, other: & &'self T) -> bool {
        *(*self) < *(*other)
    }
    #[inline]
    fn le(&self, other: & &'self T) -> bool {
        *(*self) <= *(*other)
    }
    #[inline]
    fn ge(&self, other: & &'self T) -> bool {
        *(*self) >= *(*other)
    }
    #[inline]
    fn gt(&self, other: & &'self T) -> bool {
        *(*self) > *(*other)
    }
}

#[cfg(not(test))]
impl<'self, T: TotalOrd> TotalOrd for &'self T {
    #[inline]
    fn cmp(&self, other: & &'self T) -> Ordering { (**self).cmp(*other) }
}

#[cfg(not(test))]
impl<'self, T: TotalEq> TotalEq for &'self T {
    #[inline]
    fn equals(&self, other: & &'self T) -> bool { (**self).equals(*other) }
}

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

    #[test]
    fn test_ref_eq() {
        let x = 1;
        let y = 1;

        assert!(ref_eq(&x, &x));
        assert!(!ref_eq(&x, &y));
    }
}
<|endoftext|>


<commit_before>use gfx;
use gfx::handle::{DepthStencilView, RenderTargetView};
use gfx::traits::*;

use utils::{grow_buffer, MAT4_ID};

pub struct LineRenderer<R: gfx::Resources> {
    vertex_data: Vec<Vertex>,
    vertex_buffer: gfx::handle::Buffer<R, Vertex>,
    pso: gfx::PipelineState<R, pipe::Meta>,
}

impl<R: gfx::Resources> LineRenderer<R> {

    pub fn new<F: gfx::Factory<R>>(
        factory: &mut F,
        initial_buffer_size: usize
    ) -> Result<LineRenderer<R>, gfx::PipelineStateError> {

        /* TODO: Update
        let vertex = gfx::ShaderSource {
            glsl_120: Some(VERTEX_SRC[0]),
            glsl_150: Some(VERTEX_SRC[1]),
            .. gfx::ShaderSource::empty()
        };
        */

        /* TODO: Update
        let fragment = gfx::ShaderSource {
            glsl_120: Some(FRAGMENT_SRC[0]),
            glsl_150: Some(FRAGMENT_SRC[1]),
            .. gfx::ShaderSource::empty()
        };
        */

        let pso = try!(factory.create_pipeline_simple(
            &VERTEX_SRC[1], &FRAGMENT_SRC[1], pipe::new()
        ));

        let vertex_buffer = factory.create_buffer_dynamic(
            initial_buffer_size, gfx::BufferRole::Vertex, gfx::Bind::empty()
        ).expect("Could not create vertex buffer");

        Ok(LineRenderer {
            vertex_data: Vec::new(),
            vertex_buffer: vertex_buffer,
            pso: pso,
        })
    }

    ///
    /// Add a line to the batch to be drawn on 'render'
    ///
    pub fn draw_line(&mut self, start: [f32; 3], end: [f32; 3], color: [f32; 4]) {
        self.vertex_data.push(Vertex{position: start, color: color});
        self.vertex_data.push(Vertex{position: end, color: color});
    }

    ///
    /// Draw and clear the current batch of lines
    ///
    pub fn render<F: gfx::Factory<R>, C: gfx::CommandBuffer<R>> (
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        factory: &mut F,
        color_target: &RenderTargetView<R, gfx::format::Srgba8>,
        depth_target: &DepthStencilView<R, gfx::format::DepthStencil>,
        projection: [[f32; 4]; 4],
    ) -> Result<(), gfx::UpdateError<usize>> {

        if self.vertex_data.len() > self.vertex_buffer.len() {
            self.vertex_buffer = grow_buffer(factory, &self.vertex_buffer, gfx::BufferRole::Vertex, self.vertex_data.len());
        }

        try!(encoder.update_buffer(&self.vertex_buffer, &self.vertex_data[..], 0));

        /* TODO: Update
        self.params.model_view_proj = projection;
        */

        /* TODO: Update
        let mesh = gfx::Mesh::from_format(
            self.vertex_buffer.clone(),
            self.vertex_data.len() as gfx::VertexCount
        );
        */

        /* TODO: Update
        let slice = mesh.to_slice(gfx::PrimitiveType::Line);
        */

        /* TODO: Update
        stream.draw(
            &gfx::batch::bind(&self.state, &mesh, slice, &self.program, &self.params)
        ).unwrap();
        */

        let data = pipe::Data {
            vbuf: self.vertex_buffer.clone(),
            u_model_view_proj: projection,
            out_color: color_target.clone(),
            out_depth: depth_target.clone(),
        };

        let slice = gfx::Slice::new_match_vertex_buffer(&self.vertex_buffer);
        encoder.draw(&slice, &self.pso, &data);

        self.vertex_data.clear();

        Ok(())
    }
}

static VERTEX_SRC: [&'static [u8]; 2] = [
b"
    #version 120

    uniform mat4 u_model_view_proj;
    attribute vec3 at_position;
    attribute vec4 at_color;
    varying vec4 v_color;

    void main() {
        gl_Position = u_model_view_proj * vec4(at_position, 1.0);
        v_color = at_color;
    }
",
b"
    #version 150 core

    uniform mat4 u_model_view_proj;
    in vec3 at_position;
    in vec4 at_color;
    out vec4 v_color;

    void main() {
        gl_Position = u_model_view_proj * vec4(at_position, 1.0);
        v_color = at_color;
    }
"];

static FRAGMENT_SRC: [&'static [u8]; 2] = [
b"
    #version 120

    varying vec4 v_color;

    void main() {
        gl_FragColor = v_color;
    }
",
b"
    #version 150

    in vec4 v_color;
    out vec4 out_color;

    void main() {
        out_color = v_color;
    }
"];

gfx_vertex_struct!( Vertex {
    position: [f32; 3] = "at_position",
    color: [f32; 4] = "at_color",
});

gfx_pipeline!( pipe {
    vbuf: gfx::VertexBuffer<Vertex> = (),
    u_model_view_proj: gfx::Global<[[f32; 4]; 4]> = "u_model_view_proj",
    out_color: gfx::RenderTarget<gfx::format::Srgba8> = "o_Color",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> =
        gfx::preset::depth::LESS_EQUAL_WRITE,
});
<commit_msg>Render lines<commit_after>use gfx;
use gfx::handle::{DepthStencilView, RenderTargetView};
use gfx::traits::*;

use utils::{grow_buffer, MAT4_ID};

pub struct LineRenderer<R: gfx::Resources> {
    vertex_data: Vec<Vertex>,
    vertex_buffer: gfx::handle::Buffer<R, Vertex>,
    pso: gfx::PipelineState<R, pipe::Meta>,
}

impl<R: gfx::Resources> LineRenderer<R> {

    pub fn new<F: gfx::Factory<R>>(
        factory: &mut F,
        initial_buffer_size: usize
    ) -> Result<LineRenderer<R>, gfx::PipelineStateError> {

        /* TODO: Update
        let vertex = gfx::ShaderSource {
            glsl_120: Some(VERTEX_SRC[0]),
            glsl_150: Some(VERTEX_SRC[1]),
            .. gfx::ShaderSource::empty()
        };
        */

        /* TODO: Update
        let fragment = gfx::ShaderSource {
            glsl_120: Some(FRAGMENT_SRC[0]),
            glsl_150: Some(FRAGMENT_SRC[1]),
            .. gfx::ShaderSource::empty()
        };
        */

        let set = factory.create_shader_set(&VERTEX_SRC[1], &FRAGMENT_SRC[1]).unwrap();
        let mut rasterizer = gfx::state::Rasterizer {
            front_face: gfx::state::FrontFace::CounterClockwise,
            cull_face: gfx::state::CullFace::Nothing,
            method: gfx::state::RasterMethod::Line(1),
            offset: None,
            samples: None,
        };
        let pso = try!(factory.create_pipeline_state(
            &set, gfx::Primitive::LineList, rasterizer, pipe::new()
        ));

        let vertex_buffer = factory.create_buffer_dynamic(
            initial_buffer_size, gfx::BufferRole::Vertex, gfx::Bind::empty()
        ).expect("Could not create vertex buffer");

        Ok(LineRenderer {
            vertex_data: Vec::new(),
            vertex_buffer: vertex_buffer,
            pso: pso,
        })
    }

    ///
    /// Add a line to the batch to be drawn on 'render'
    ///
    pub fn draw_line(&mut self, start: [f32; 3], end: [f32; 3], color: [f32; 4]) {
        self.vertex_data.push(Vertex{position: start, color: color});
        self.vertex_data.push(Vertex{position: end, color: color});
    }

    ///
    /// Draw and clear the current batch of lines
    ///
    pub fn render<F: gfx::Factory<R>, C: gfx::CommandBuffer<R>> (
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        factory: &mut F,
        color_target: &RenderTargetView<R, gfx::format::Srgba8>,
        depth_target: &DepthStencilView<R, gfx::format::DepthStencil>,
        projection: [[f32; 4]; 4],
    ) -> Result<(), gfx::UpdateError<usize>> {

        if self.vertex_data.len() > self.vertex_buffer.len() {
            self.vertex_buffer = grow_buffer(factory, &self.vertex_buffer, gfx::BufferRole::Vertex, self.vertex_data.len());
        }

        try!(encoder.update_buffer(&self.vertex_buffer, &self.vertex_data[..], 0));

        /* TODO: Update
        self.params.model_view_proj = projection;
        */

        /* TODO: Update
        let mesh = gfx::Mesh::from_format(
            self.vertex_buffer.clone(),
            self.vertex_data.len() as gfx::VertexCount
        );
        */

        /* TODO: Update
        let slice = mesh.to_slice(gfx::PrimitiveType::Line);
        */

        /* TODO: Update
        stream.draw(
            &gfx::batch::bind(&self.state, &mesh, slice, &self.program, &self.params)
        ).unwrap();
        */

        let data = pipe::Data {
            vbuf: self.vertex_buffer.clone(),
            u_model_view_proj: projection,
            out_color: color_target.clone(),
            out_depth: depth_target.clone(),
        };

        let slice = gfx::Slice::new_match_vertex_buffer(&self.vertex_buffer);
        encoder.draw(&slice, &self.pso, &data);

        self.vertex_data.clear();

        Ok(())
    }
}

static VERTEX_SRC: [&'static [u8]; 2] = [
b"
    #version 120

    uniform mat4 u_model_view_proj;
    attribute vec3 at_position;
    attribute vec4 at_color;
    varying vec4 v_color;

    void main() {
        gl_Position = u_model_view_proj * vec4(at_position, 1.0);
        v_color = at_color;
    }
",
b"
    #version 150 core

    uniform mat4 u_model_view_proj;
    in vec3 at_position;
    in vec4 at_color;
    out vec4 v_color;

    void main() {
        gl_Position = u_model_view_proj * vec4(at_position, 1.0);
        v_color = at_color;
    }
"];

static FRAGMENT_SRC: [&'static [u8]; 2] = [
b"
    #version 120

    varying vec4 v_color;

    void main() {
        gl_FragColor = v_color;
    }
",
b"
    #version 150

    in vec4 v_color;
    out vec4 out_color;

    void main() {
        out_color = v_color;
    }
"];

gfx_vertex_struct!( Vertex {
    position: [f32; 3] = "at_position",
    color: [f32; 4] = "at_color",
});

gfx_pipeline!( pipe {
    vbuf: gfx::VertexBuffer<Vertex> = (),
    u_model_view_proj: gfx::Global<[[f32; 4]; 4]> = "u_model_view_proj",
    out_color: gfx::RenderTarget<gfx::format::Srgba8> = "o_Color",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> =
        gfx::preset::depth::LESS_EQUAL_WRITE,
});
<|endoftext|>


<commit_before>extern crate uuid;

use uuid::Uuid;

use std::option::Option;

type OptInt32 = Option<i32>;
type OptInt64 = Option<i64>;
type OptString = Option<String>;

pub enum CellType {
    Int32 (OptInt32),
    Int64 (OptInt64),
    Text  (OptString)
}

trait Metainf {
    fn name(&self) -> String;
}

impl Metainf for CellType {
    fn name(&self) -> String {
        return match *self {
            CellType::Int32(_) => "INT32".to_string(),
            CellType::Int64(_) => "INT64".to_string(),
            CellType::Text(_) => "TEXT".to_string()
        }
    }
}

pub struct CellFormat {
    name: String,
    type_: CellType
}

trait Metaformat<T> {
    fn construct(format_: CellFormat) -> T;
}

pub struct Cell {
    value: CellType
}

impl Metaformat<Cell> for Cell {
    fn construct(format_: CellFormat) -> Cell {
        return match format_.type_ {
            CellType::Int32(_) => Cell { value: CellType::Int32(None) },
            CellType::Int64(_) => Cell { value: CellType::Int64(None) },
            CellType::Text(_) => Cell { value: CellType::Text(None) }
        }
    }
}

pub struct RowFormat {
    cols: Vec<CellFormat>
}

trait Container<T> {
    fn size(&self) -> usize;
    fn push(&mut self, item: T);
    //fn remove
}

pub struct Row {
    guid: Uuid,
    cells: Vec<Cell>
}

impl Container<Cell> for Row {
    fn size(&self) -> usize {
        return self.cells.len();
    }

    fn push(&mut self, item: Cell) {
        self.cells.push(item);
    }
}

pub struct Table {
    name: String,
    rows: Vec<Row>
}

impl Container<Row> for Table {
    fn size(&self) -> usize {
        return self.rows.len();
    }

    fn push(&mut self, item: Row) {
        self.rows.push(item);
    }
}
<commit_msg>Remove crate<commit_after>//extern crate uuid;

use uuid::Uuid;

use std::option::Option;

type OptInt32 = Option<i32>;
type OptInt64 = Option<i64>;
type OptString = Option<String>;

pub enum CellType {
    Int32 (OptInt32),
    Int64 (OptInt64),
    Text  (OptString)
}

trait Metainf {
    fn name(&self) -> String;
}

impl Metainf for CellType {
    fn name(&self) -> String {
        return match *self {
            CellType::Int32(_) => "INT32".to_string(),
            CellType::Int64(_) => "INT64".to_string(),
            CellType::Text(_) => "TEXT".to_string()
        }
    }
}

pub struct CellFormat {
    name: String,
    type_: CellType
}

trait Metaformat<T> {
    fn construct(format_: CellFormat) -> T;
}

pub struct Cell {
    value: CellType
}

impl Metaformat<Cell> for Cell {
    fn construct(format_: CellFormat) -> Cell {
        return match format_.type_ {
            CellType::Int32(_) => Cell { value: CellType::Int32(None) },
            CellType::Int64(_) => Cell { value: CellType::Int64(None) },
            CellType::Text(_) => Cell { value: CellType::Text(None) }
        }
    }
}

pub struct RowFormat {
    cols: Vec<CellFormat>
}

trait Container<T> {
    fn size(&self) -> usize;
    fn push(&mut self, item: T);
    //fn remove
}

pub struct Row {
    guid: Uuid,
    cells: Vec<Cell>
}

impl Container<Cell> for Row {
    fn size(&self) -> usize {
        return self.cells.len();
    }

    fn push(&mut self, item: Cell) {
        self.cells.push(item);
    }
}

pub struct Table {
    name: String,
    rows: Vec<Row>
}

impl Container<Row> for Table {
    fn size(&self) -> usize {
        return self.rows.len();
    }

    fn push(&mut self, item: Row) {
        self.rows.push(item);
    }
}
<|endoftext|>


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

impl<T> nsCOMPtr<T> {
    #[cfg(debug_assertions)]
    #[inline]
    pub fn raw(&self) -> *mut T {
        self.mRawPtr
    }

    #[cfg(not(debug_assertions))]
    #[inline]
    pub fn raw(&self) -> *mut T {
        self._base.mRawPtr as *mut _
    }
}
<commit_msg>style: Document the nsCOMPtr sugar.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Little helpers for `nsCOMPtr`.

use gecko_bindings::structs::nsCOMPtr;

impl<T> nsCOMPtr<T> {
    /// Get this pointer as a raw pointer.
    #[cfg(debug_assertions)]
    #[inline]
    pub fn raw(&self) -> *mut T {
        self.mRawPtr
    }

    /// Get this pointer as a raw pointer.
    #[cfg(not(debug_assertions))]
    #[inline]
    pub fn raw(&self) -> *mut T {
        self._base.mRawPtr as *mut _
    }
}
<|endoftext|>