<commit_before>#[derive(Debug, PartialEq, Eq)]
pub struct GitStatus {
    oid: String,
    branch: String,
    upstream: Option<String>,
    ahead: bool,
    behind: bool,
    staged: bool,
    unstaged: bool,
    unmerged: bool,
    untracked: bool,
    ignored: bool,
}

impl GitStatus {
    pub fn new(status_txt: &str) -> Result<GitStatus, &'static str> {
        let mut s = GitStatus {
            oid: String::new(),
            branch: String::new(),
            upstream: None,
            ahead: false,
            behind: false,
            staged: false,
            unstaged: false,
            untracked: false,
            unmerged: false,
            ignored: false,
        };
        let err = "Bad input";
        for line in status_txt.lines() {
            let mut words = line.split(' ');
            match words.next() {
                Some("#") => {
                    let key = words.next().ok_or(err)?;
                    let value = words.next().ok_or(err)?;
                    match key {
                        "branch.oid" => s.oid = String::from(value),
                        "branch.head" => s.branch = String::from(value),
                        "branch.upstream" => s.upstream = Some(String::from(value)),
                        "branch.ab" => {
                            if value != "+0" {
                                s.ahead = true;
                            }
                            if words.next().ok_or(err)? != "-0" {
                                s.behind = true;
                            }
                        },
                        _ => return Err(err),
                    }
                },
                Some("1") | Some("2") => {
                    let changes = words.next().ok_or(err)?;
                    let mut changes = changes.chars();
                    if changes.next().ok_or(err)? != '.' {
                        s.staged = true;
                    }
                    if changes.next().ok_or(err)? != '.' {
                        s.unstaged = true;
                    }
                },
                Some("u") => s.unmerged = true,
                Some("?") => s.untracked = true,
                Some("!") => s.ignored = true,
                Some("") | None => {},
                _ => return Err(err),
            }
        }
        Ok(s)
    }

    pub fn to_line(&self) -> String {
        let mut symbols = String::new();
        if self.ahead {
            symbols.push('A');
        }
        if self.behind {
            symbols.push('B');
        }
        if self.staged {
            symbols.push('+');
        }
        if self.unstaged {
            symbols.push('*');
        }
        if self.unmerged {
            symbols.push('%');
        }
        if self.untracked {
            symbols.push('?');
        }
        if self.ignored {
            symbols.push('!');
        }
        let short_oid = if self.oid == "(initial)" {
            &self.oid
        } else {
            &self.oid[..7]
        };
        if symbols.is_empty() {
            format!("[{} {}]", self.branch, short_oid)
        } else {
            format!("[{} {} {}]", self.branch, short_oid, symbols)
        }
    }
}

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

    #[test]
    fn parse_clean() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: None,
                ahead: false,
                behind: false,
                staged: false,
                unstaged: false,
                unmerged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_clean_upstream() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: Some(String::from("origin/master")),
                ahead: true,
                behind: true,
                staged: false,
                unstaged: false,
                unmerged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_staged_only() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 M. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_unstaged_only() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 .M N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(!s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_both_staged_and_unstaged() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 MM N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_deleted() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_renamed() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
2 R. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 R100 README	README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_unmerged() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
u UU N... 100644 100644 100644 100644 8fb20c5f0b7da31f56f74f0a98e1fadb13e4c2a0 801dd97d4dace6780f9eca5a99dbee77d6e05a95 cbf6eb8db76897842f3b77d1d2b95dbd422c180d README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.unmerged);
    }

    #[test]
    fn parse_untracked() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
? foo.txt
";
        assert!(GitStatus::new(test_status).unwrap().untracked);
    }

    #[test]
    fn parse_ignored() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
! node_modules/
";
        assert!(GitStatus::new(test_status).unwrap().ignored);
    }

    #[test]
    fn parse_very_dirty() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md
1 .M N... 100644 100644 100644 5e8a8090976077ddf16252a560460a20dbbdd6a5 5e8a8090976077ddf16252a560460a20dbbdd6a5 gh-pages.sh
? foo.txt
! ignored.txt
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: Some(String::from("origin/master")),
                ahead: true,
                behind: true,
                staged: true,
                unstaged: true,
                unmerged: false,
                untracked: true,
                ignored: true,
            }
        );
    }

    #[test]
    fn parse_bad_input() {
        assert_eq!(GitStatus::new("foo"), Err("Bad input"));
    }

    #[test]
    fn test_to_line_clean() {
        let s = GitStatus {
            oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
            branch: String::from("master"),
            upstream: None,
            ahead: false,
            behind: false,
            staged: false,
            unstaged: false,
            unmerged: false,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("[master 3845e7a]"));
    }

    #[test]
    fn test_to_line_dirty() {
        let s = GitStatus {
            oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
            branch: String::from("master"),
            upstream: Some(String::from("origin/master")),
            ahead: true,
            behind: true,
            staged: true,
            unstaged: true,
            unmerged: true,
            untracked: true,
            ignored: true,
        };
        assert_eq!(s.to_line(), String::from("[master 3845e7a AB+*%?!]"));
    }

    #[test]
    fn test_to_line_initial_commit() {
        let s = GitStatus {
            oid: String::from("(initial)"),
            branch: String::from("master"),
            upstream: None,
            ahead: false,
            behind: false,
            staged: false,
            unstaged: false,
            unmerged: false,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("[master (initial)]"));
    }
}
<commit_msg>Store merge status and show in to_line<commit_after>#[derive(Debug, PartialEq, Eq)]
pub struct GitStatus {
    oid: String,
    branch: String,
    upstream: Option<String>,
    ahead: bool,
    behind: bool,
    merge: Option<MergeStatus>,
    staged: bool,
    unstaged: bool,
    unmerged: bool,
    untracked: bool,
    ignored: bool,
}

#[derive(Debug, PartialEq, Eq)]
pub enum MergeStatus {
    Merge,
    Rebase,
}

impl GitStatus {
    pub fn new(status_txt: &str) -> Result<GitStatus, &'static str> {
        let mut s = GitStatus {
            oid: String::new(),
            branch: String::new(),
            upstream: None,
            ahead: false,
            behind: false,
            merge: None,
            staged: false,
            unstaged: false,
            untracked: false,
            unmerged: false,
            ignored: false,
        };
        let err = "Bad input";
        for line in status_txt.lines() {
            let mut words = line.split(' ');
            match words.next() {
                Some("#") => {
                    let key = words.next().ok_or(err)?;
                    let value = words.next().ok_or(err)?;
                    match key {
                        "branch.oid" => s.oid = String::from(value),
                        "branch.head" => s.branch = String::from(value),
                        "branch.upstream" => s.upstream = Some(String::from(value)),
                        "branch.ab" => {
                            if value != "+0" {
                                s.ahead = true;
                            }
                            if words.next().ok_or(err)? != "-0" {
                                s.behind = true;
                            }
                        },
                        _ => return Err(err),
                    }
                },
                Some("1") | Some("2") => {
                    let changes = words.next().ok_or(err)?;
                    let mut changes = changes.chars();
                    if changes.next().ok_or(err)? != '.' {
                        s.staged = true;
                    }
                    if changes.next().ok_or(err)? != '.' {
                        s.unstaged = true;
                    }
                },
                Some("u") => s.unmerged = true,
                Some("?") => s.untracked = true,
                Some("!") => s.ignored = true,
                Some("") | None => {},
                _ => return Err(err),
            }
        }
        Ok(s)
    }

    pub fn set_merge_status(&mut self, m: MergeStatus) {
        self.merge = Some(m);
    }

    pub fn to_line(&self) -> String {
        let short_oid = if self.oid == "(initial)" {
            &self.oid
        } else {
            &self.oid[..7]
        };
        let merge_status = match self.merge {
            None => "",
            Some(MergeStatus::Merge) => "(merge)",
            Some(MergeStatus::Rebase) => "(rebase)",
        };
        let mut symbols = String::new();
        if self.ahead {
            symbols.push('A');
        }
        if self.behind {
            symbols.push('B');
        }
        if self.staged {
            symbols.push('+');
        }
        if self.unstaged {
            symbols.push('*');
        }
        if self.unmerged {
            symbols.push('%');
        }
        if self.untracked {
            symbols.push('?');
        }
        if self.ignored {
            symbols.push('!');
        }
        let mut result = format!("[{} {}", self.branch, short_oid);
        if !merge_status.is_empty() {
            result.push(' ');
            result.push_str(merge_status);
        }
        if !symbols.is_empty() {
            result.push(' ');
            result.push_str(&symbols);
        }
        result.push(']');
        result
    }
}

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

    #[test]
    fn parse_clean() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: None,
                ahead: false,
                behind: false,
                merge: None,
                staged: false,
                unstaged: false,
                unmerged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_clean_upstream() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: Some(String::from("origin/master")),
                ahead: true,
                behind: true,
                merge: None,
                staged: false,
                unstaged: false,
                unmerged: false,
                untracked: false,
                ignored: false,
            }
        );
    }

    #[test]
    fn parse_staged_only() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 M. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_unstaged_only() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 .M N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(!s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_both_staged_and_unstaged() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 MM N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 311c77295c5b6056f4599c2b8d0a019d4c76746a README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(s.unstaged);
    }

    #[test]
    fn parse_deleted() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_renamed() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
2 R. N... 100644 100644 100644 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 R100 README	README.md
";
        let s = GitStatus::new(test_status).unwrap();
        assert!(s.staged);
        assert!(!s.unstaged);
    }

    #[test]
    fn parse_unmerged() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
u UU N... 100644 100644 100644 100644 8fb20c5f0b7da31f56f74f0a98e1fadb13e4c2a0 801dd97d4dace6780f9eca5a99dbee77d6e05a95 cbf6eb8db76897842f3b77d1d2b95dbd422c180d README.md
";
        let mut s = GitStatus::new(test_status).unwrap();
        s.set_merge_status(MergeStatus::Merge);
        assert!(s.unmerged);
        assert_eq!(s.merge, Some(MergeStatus::Merge));
    }

    #[test]
    fn parse_untracked() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
? foo.txt
";
        assert!(GitStatus::new(test_status).unwrap().untracked);
    }

    #[test]
    fn parse_ignored() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
! node_modules/
";
        assert!(GitStatus::new(test_status).unwrap().ignored);
    }

    #[test]
    fn parse_very_dirty() {
        let test_status = "\
# branch.oid 3845e7a3c3aadaaebb2d1b261bf07a9357d35a79
# branch.head master
# branch.upstream origin/master
# branch.ab +1 -1
1 D. N... 100644 000000 000000 1290f45e7ad7575848a436d8febbd6c4ba07f1f3 0000000000000000000000000000000000000000 README.md
1 .M N... 100644 100644 100644 5e8a8090976077ddf16252a560460a20dbbdd6a5 5e8a8090976077ddf16252a560460a20dbbdd6a5 gh-pages.sh
? foo.txt
! ignored.txt
";
        assert_eq!(
            GitStatus::new(test_status).unwrap(),
            GitStatus {
                oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
                branch: String::from("master"),
                upstream: Some(String::from("origin/master")),
                ahead: true,
                behind: true,
                merge: None,
                staged: true,
                unstaged: true,
                unmerged: false,
                untracked: true,
                ignored: true,
            }
        );
    }

    #[test]
    fn parse_bad_input() {
        assert_eq!(GitStatus::new("foo"), Err("Bad input"));
    }

    #[test]
    fn test_to_line_clean() {
        let s = GitStatus {
            oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
            branch: String::from("master"),
            upstream: None,
            ahead: false,
            behind: false,
            merge: None,
            staged: false,
            unstaged: false,
            unmerged: false,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("[master 3845e7a]"));
    }

    #[test]
    fn test_to_line_dirty() {
        let s = GitStatus {
            oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
            branch: String::from("master"),
            upstream: Some(String::from("origin/master")),
            ahead: true,
            behind: true,
            merge: None,
            staged: true,
            unstaged: true,
            unmerged: true,
            untracked: true,
            ignored: true,
        };
        assert_eq!(s.to_line(), String::from("[master 3845e7a AB+*%?!]"));
    }

    #[test]
    fn test_to_line_initial_commit() {
        let s = GitStatus {
            oid: String::from("(initial)"),
            branch: String::from("master"),
            upstream: None,
            ahead: false,
            behind: false,
            merge: None,
            staged: false,
            unstaged: false,
            unmerged: false,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("[master (initial)]"));
    }

    #[test]
    fn test_to_line_merge() {
        let s = GitStatus {
            oid: String::from("3845e7a3c3aadaaebb2d1b261bf07a9357d35a79"),
            branch: String::from("master"),
            upstream: None,
            ahead: false,
            behind: false,
            merge: Some(MergeStatus::Merge),
            staged: false,
            unstaged: false,
            unmerged: true,
            untracked: false,
            ignored: false,
        };
        assert_eq!(s.to_line(), String::from("[master 3845e7a (merge) %]"));
    }
}
<|endoftext|>


<commit_before>use std::io;

/// Circular buffer to store a stream. Read/write boundaries are not preserved.
pub struct StreamBuffer {
    buf: Box<[u8]>,
    head: usize,
    tail: usize,
}

impl StreamBuffer {
    pub fn new(capacity: usize) -> Self {
        Self {
            buf: vec![0; capacity + 1].into_boxed_slice(),
            head: 0,
            tail: 0,
        }
    }

    pub fn is_empty(&self) -> bool{
        self.head == self.tail
    }

    pub fn size(&self) -> usize {
        if self.head < self.tail {
            self.head + self.buf.len() - self.tail
        } else {
            self.head - self.tail
        }
    }

    pub fn remaining(&self) -> usize {
        self.buf.len() - self.size()
    }

    pub fn write_to<W: io::Write>(&mut self, destination: &mut W) -> io::Result<usize> {
        if self.head == self.tail {
            // buffer is empty, nothing to do
            Ok(0)
        } else {
            let w;
            if self.head > self.tail {
                let source_slice = &self.buf[self.tail..self.head];
                w = destination.write(source_slice)?;
                self.tail += w;
            } else { // self.head < self.tail
                let source_slice = &self.buf[self.tail..];
                w = destination.write(source_slice)?;
                self.tail = (self.tail + w) % self.buf.len();
            }
            self.optimize();
            Ok(w)
        }
    }

    pub fn read_from(&mut self, source: &[u8]) -> io::Result<()> {
        if self.remaining() < source.len() {
            return Err(io::Error::new(io::ErrorKind::Other, "StreamBuffer is full"));
        }
        let source_len = source.len();
        let buf_len = self.buf.len();
        if source_len <= buf_len - self.head {
            let target_slice = &mut self.buf[self.head..self.head + source_len];
            target_slice.copy_from_slice(source);
        } else {
            {
                // fill until the right-end of the buffer
                let target_slice = &mut self.buf[self.head..];
                let source_slice = &source[..buf_len - self.head];
                target_slice.copy_from_slice(source_slice);
            }
            // fill the remaining from the left-end of the buffer
            let target_slice = &mut self.buf[..self.head + source_len - buf_len];
            let source_slice = &source[buf_len - self.head..];
            target_slice.copy_from_slice(source_slice);
        }
        self.head = (self.head + source_len) % buf_len;
        Ok(())
    }

    /// To avoid unnecessary copies, StreamBuffer writes at most until the "end" of the circular
    /// buffer, which is suboptimal (it could have written more data if they have been contiguous).
    ///
    /// In order to minimize the occurrence of this event, reset the head and tail to 0 when the
    /// buffer is empty (no copy is involved).
    ///
    /// This is especially useful when the StreamBuffer is used to read/write one packet at a time,
    /// so the "end" of the buffer is guaranteed to never be reached.
    fn optimize(&mut self) {
        if self.is_empty() {
            self.head = 0;
            self.tail = 0;
        }
    }
}

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

    fn create_data() -> Vec<u8> {
        (0..6).collect()
    }

    #[test]
    fn bufferize_data() {
        let data = create_data();
        let mut stream_buffer = StreamBuffer::new(9);

        let mut cursor = io::Cursor::new(vec![]);
        stream_buffer.read_from(&data).unwrap();
        stream_buffer.write_to(&mut cursor).unwrap();

        assert_eq!(cursor.get_ref(), &data);
    }

    #[test]
    fn circular() {
        let data = create_data();
        let mut stream_buffer = StreamBuffer::new(9);

        // put 6 bytes
        stream_buffer.read_from(&data).unwrap();
        // consume 3 bytes
        read_some(&mut stream_buffer, 3);

        // put test data
        stream_buffer.read_from(&data).unwrap();
        // consume 3 bytes (so that the first 6 bytes are totally consumed, and the "tail" position is 6)
        read_some(&mut stream_buffer, 3);

        // consume test data
        let result = read(&mut stream_buffer);

        // StreamBuffer is expected to break writes at circular buffer boundaries (capacity + 1)
        // This is not a requirement, but this verifies that the implementation works as expected
        assert_eq!([0u8, 1, 2, 3], &result[..]);

        // consume the remaining
        let result = read(&mut stream_buffer);
        assert_eq!([4u8, 5], &result[..]);
    }

    fn read_some(stream_buffer: &mut StreamBuffer, bytes: usize) -> Vec<u8> {
        let mut vec = vec![0u8; bytes];
        {
            let mut cursor = io::Cursor::new(&mut vec[..bytes]);
            stream_buffer.write_to(&mut cursor).unwrap();
        }
        vec
    }

    fn read(stream_buffer: &mut StreamBuffer) -> Vec<u8> {
        let mut cursor = io::Cursor::new(vec![]);
        stream_buffer.write_to(&mut cursor).unwrap();
        cursor.into_inner()
    }
}
<commit_msg>Add more tests to StreamBuffer<commit_after>use std::io;

/// Circular buffer to store a stream. Read/write boundaries are not preserved.
pub struct StreamBuffer {
    buf: Box<[u8]>,
    head: usize,
    tail: usize,
}

impl StreamBuffer {
    pub fn new(capacity: usize) -> Self {
        Self {
            buf: vec![0; capacity + 1].into_boxed_slice(),
            head: 0,
            tail: 0,
        }
    }

    pub fn is_empty(&self) -> bool{
        self.head == self.tail
    }

    pub fn size(&self) -> usize {
        if self.head < self.tail {
            self.head + self.buf.len() - self.tail
        } else {
            self.head - self.tail
        }
    }

    pub fn capacity(&self) -> usize {
        self.buf.len() - 1
    }

    pub fn remaining(&self) -> usize {
        self.capacity() - self.size()
    }

    pub fn write_to<W: io::Write>(&mut self, destination: &mut W) -> io::Result<usize> {
        if self.head == self.tail {
            // buffer is empty, nothing to do
            Ok(0)
        } else {
            let w;
            if self.head > self.tail {
                let source_slice = &self.buf[self.tail..self.head];
                w = destination.write(source_slice)?;
                self.tail += w;
            } else { // self.head < self.tail
                let source_slice = &self.buf[self.tail..];
                w = destination.write(source_slice)?;
                self.tail = (self.tail + w) % self.buf.len();
            }
            self.optimize();
            Ok(w)
        }
    }

    pub fn read_from(&mut self, source: &[u8]) -> io::Result<()> {
        if self.remaining() < source.len() {
            return Err(io::Error::new(io::ErrorKind::Other, "StreamBuffer is full"));
        }
        let source_len = source.len();
        let buf_len = self.buf.len();
        if source_len <= buf_len - self.head {
            let target_slice = &mut self.buf[self.head..self.head + source_len];
            target_slice.copy_from_slice(source);
        } else {
            {
                // fill until the right-end of the buffer
                let target_slice = &mut self.buf[self.head..];
                let source_slice = &source[..buf_len - self.head];
                target_slice.copy_from_slice(source_slice);
            }
            // fill the remaining from the left-end of the buffer
            let target_slice = &mut self.buf[..self.head + source_len - buf_len];
            let source_slice = &source[buf_len - self.head..];
            target_slice.copy_from_slice(source_slice);
        }
        self.head = (self.head + source_len) % buf_len;
        Ok(())
    }

    /// To avoid unnecessary copies, StreamBuffer writes at most until the "end" of the circular
    /// buffer, which is suboptimal (it could have written more data if they have been contiguous).
    ///
    /// In order to minimize the occurrence of this event, reset the head and tail to 0 when the
    /// buffer is empty (no copy is involved).
    ///
    /// This is especially useful when the StreamBuffer is used to read/write one packet at a time,
    /// so the "end" of the buffer is guaranteed to never be reached.
    fn optimize(&mut self) {
        if self.is_empty() {
            self.head = 0;
            self.tail = 0;
        }
    }
}

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

    fn create_data() -> Vec<u8> {
        (0..6).collect()
    }

    #[test]
    fn bufferize_data() {
        let data = create_data();
        let mut stream_buffer = StreamBuffer::new(9);

        let mut cursor = io::Cursor::new(vec![]);
        stream_buffer.read_from(&data).unwrap();
        stream_buffer.write_to(&mut cursor).unwrap();

        assert_eq!(cursor.get_ref(), &data);
    }

    #[test]
    fn circular() {
        let data = create_data();
        let mut stream_buffer = StreamBuffer::new(9);

        // put 6 bytes
        stream_buffer.read_from(&data).unwrap();
        // consume 3 bytes
        read_some(&mut stream_buffer, 3);

        // put test data
        stream_buffer.read_from(&data).unwrap();
        // consume 3 bytes (so that the first 6 bytes are totally consumed, and the "tail" position is 6)
        read_some(&mut stream_buffer, 3);

        // consume test data
        let result = read(&mut stream_buffer);

        // StreamBuffer is expected to break writes at circular buffer boundaries (capacity + 1)
        // This is not a requirement, but this verifies that the implementation works as expected
        assert_eq!([0u8, 1, 2, 3], &result[..]);

        // consume the remaining
        let result = read(&mut stream_buffer);
        assert_eq!([4u8, 5], &result[..]);
    }

    #[test]
    fn not_enough_space() {
        let data = create_data();
        let mut stream_buffer = StreamBuffer::new(9);

        // fill the buffer twice
        stream_buffer.read_from(&data).unwrap();
        assert_eq!(3, stream_buffer.remaining());

        // not enough space for another packet of 6 bytes
        assert!(stream_buffer.read_from(&data).is_err());

        // but enough space for a smaller one
        stream_buffer.read_from(&[0, 1, 2]).unwrap();
    }

    fn read_some(stream_buffer: &mut StreamBuffer, bytes: usize) -> Vec<u8> {
        let mut vec = vec![0u8; bytes];
        {
            let mut cursor = io::Cursor::new(&mut vec[..bytes]);
            stream_buffer.write_to(&mut cursor).unwrap();
        }
        vec
    }

    fn read(stream_buffer: &mut StreamBuffer) -> Vec<u8> {
        let mut cursor = io::Cursor::new(vec![]);
        stream_buffer.write_to(&mut cursor).unwrap();
        cursor.into_inner()
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Hugo Duncan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![deny(missing_docs)]
#![feature(collections, core)]

//! Austenite
//!
//! A library for building [Iron](https://github.com/iron/iron)
//! handlers that implements HTTP header handling and content
//! negotiation.
//!
//! ```ignore
//! #[macro_use] extern crate austenite;
//! use austenite::handle;
//! use iron::{Iron, Listening, Request, Response};
//!
//! struct GetOkContent;
//! resource_handler!(GetOkContent);
//! impl Resource for GetOkContent {
//!     fn handle_ok(&self, req: &Request, resp: &mut Response)
//!                -> IronResult<Response>
//!     {
//!       resp.set_mut((status::Ok, "hello"));
//!       Ok(Response::new())
//!     }
//! }
//!
//! fn start_iron() -> Listening {
//!   Iron::new(Resource).listen((address,0u16)).unwrap();
//! }
//! ```

#[macro_use] extern crate hyper;
extern crate iron;
extern crate mime;
extern crate time;
#[macro_use] extern crate log;

pub use hyper_headers::*;
pub use resource::Resource;

/// Content Negotiation
pub mod content_neg;
/// Headers
pub mod hyper_headers;
/// A Resource
pub mod resource;
<commit_msg>Expose ResourceError and ResourceResult<commit_after>// Copyright 2015 Hugo Duncan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![deny(missing_docs)]
#![feature(collections, core)]

//! Austenite
//!
//! A library for building [Iron](https://github.com/iron/iron)
//! handlers that implements HTTP header handling and content
//! negotiation.
//!
//! ```ignore
//! #[macro_use] extern crate austenite;
//! use austenite::handle;
//! use iron::{Iron, Listening, Request, Response};
//!
//! struct GetOkContent;
//! resource_handler!(GetOkContent);
//! impl Resource for GetOkContent {
//!     fn handle_ok(&self, req: &Request, resp: &mut Response)
//!                -> IronResult<Response>
//!     {
//!       resp.set_mut((status::Ok, "hello"));
//!       Ok(Response::new())
//!     }
//! }
//!
//! fn start_iron() -> Listening {
//!   Iron::new(Resource).listen((address,0u16)).unwrap();
//! }
//! ```

#[macro_use] extern crate hyper;
extern crate iron;
extern crate mime;
extern crate time;
#[macro_use] extern crate log;

pub use hyper_headers::*;
pub use resource::{Resource, ResourceError, ResourceResult};

/// Content Negotiation
pub mod content_neg;
/// Headers
pub mod hyper_headers;
/// A Resource
pub mod resource;
<|endoftext|>


<commit_before>

extern crate openvr_sys;

pub struct IVRSystem(*const ());

#[derive(Debug, Copy, Clone)]
pub struct Size {
    pub width: u32,
    pub height: u32
}

#[derive(Debug, Copy, Clone)]
pub struct Position {
    pub x: i32,
    pub y: i32
}

#[derive(Debug, Copy, Clone)]
pub struct Rectangle {
    pub position: Position,
    pub size: Size
}

#[derive(Debug, Copy, Clone)]
pub struct DistortionCoordinates {
    pub red: [f32; 2],
    pub green: [f32; 2],
    pub blue: [f32; 2],
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Eye {
    Left, Right
}

impl Eye {
    /// Convert a eye to a HmdEye
    fn to_raw(&self) -> openvr_sys::Hmd_Eye {
        match self {
            &Eye::Left => openvr_sys::Hmd_Eye::Left,
            &Eye::Right => openvr_sys::Hmd_Eye::Right,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TextureBounds {
    pub u_min: f32,
    pub u_max: f32,
    pub v_min: f32,
    pub v_max: f32
}

impl TextureBounds {
    /// Convert a bounds to a openvr_bounds
    fn to_raw(self) -> openvr_sys::VRTextureBounds_t {
        openvr_sys::VRTextureBounds_t{
            uMin: self.u_min,
            uMax: self.u_max,
            vMin: self.v_min,
            vMax: self.v_max
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePose {
    pub to_device: [[f32; 4]; 3],
    pub velocity: [f32; 3],
    pub angular_velocity: [f32; 3],
    pub is_valid: bool,
    pub is_connected: bool,
}

#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePoses {
    pub count: usize,
    pub poses: [TrackedDevicePose; 16],
}

impl TrackedDevicePoses {
    pub fn as_slice(&self) -> &[TrackedDevicePose] {
        &self.poses[0..self.count]
    }
}

unsafe fn to_tracked(data: [openvr_sys::TrackedDevicePose_t; 16]) -> TrackedDevicePoses {
    let mut out: TrackedDevicePoses = std::mem::zeroed();
    for (i, d) in data.iter().enumerate() {
        if d.bDeviceIsConnected {
            out.count = i + 1;
        }
        out.poses[i].is_connected = d.bDeviceIsConnected;
        out.poses[i].is_valid = d.bPoseIsValid;
        out.poses[i].to_device = d.mDeviceToAbsoluteTracking.m;
        out.poses[i].velocity = d.vVelocity.v;
        out.poses[i].angular_velocity = d.vAngularVelocity.v;
    }
    out
}

impl IVRSystem {
    /// Initialize the IVR System
    pub fn init() -> Result<IVRSystem, openvr_sys::HmdError> {
        let mut err = openvr_sys::HmdError::None;
        let ptr = unsafe {
            openvr_sys::VR_Init(&mut err as *mut openvr_sys::HmdError)
        };
        if ptr.is_null() {
            Err(err)
        } else {
            Ok(IVRSystem(ptr))
        }
    }

    /// Get the window bounds
    pub fn bounds(&self) -> Rectangle {
        unsafe {
            let mut size = Size{width: 0, height: 0};
            let mut pos = Position{x: 0, y: 0};
            openvr_sys::VR_IVRSystem_GetWindowBounds(
                self.0,
                &mut pos.x,
                &mut pos.y,
                &mut size.width,
                &mut size.height
            );
            Rectangle {
                position: pos,
                size: size
            }
        }
    }

    /// Get the recommended render target size
    pub fn recommended_render_target_size(&self) -> Size {
        unsafe {
            let mut size = Size{width: 0, height: 0};
            openvr_sys::VR_IVRSystem_GetRecommendedRenderTargetSize(
                self.0,
                &mut size.width,
                &mut size.height
            );
            size
        }
    }

    /// Get eye viewport size
    pub fn eye_viewport(&self, eye: Eye) -> Rectangle {
        use std::mem;
        unsafe {
            let mut size = Size{width: 0, height: 0};
            let mut pos = Position{x: 0, y: 0};
            openvr_sys::VR_IVRSystem_GetEyeOutputViewport(
                self.0,
                eye.to_raw(),
                mem::transmute(&mut pos.x),
                mem::transmute(&mut pos.y),
                &mut size.width,
                &mut size.height
            );
            Rectangle {
                position: pos,
                size: size
            }
        }
    }

    /// Get the projection matrix for an eye
    /// supply the near and the far position
    /// assumes opengl conventions
    pub fn projection_matrix(&self, eye: Eye, near: f32, far: f32) -> [[f32; 4]; 4] {
        unsafe {
            let mat = openvr_sys::VR_IVRSystem_GetProjectionMatrix(
                self.0,
                eye.to_raw(),
                near,
                far,
                openvr_sys::GraphicsAPIConvention::OpenGL
            );
            mat.m
        }
    }

    /// Computes the distortion caused by the optics
    pub fn compute_distortion(&self, eye: Eye, u: f32, v: f32) -> DistortionCoordinates {
        unsafe {
            let coord = openvr_sys::VR_IVRSystem_ComputeDistortion(
                self.0,
                eye.to_raw(),
                u, v
            );
            DistortionCoordinates {
                red: coord.rfRed,
                blue: coord.rfBlue,
                green: coord.rfGreen
            }
        }
    }

    /// Computes the distortion caused by the optics
    pub fn eye_to_head_transform(&self, eye: Eye) -> [[f32; 4]; 3] {
        unsafe {
            let mat = openvr_sys::VR_IVRSystem_GetEyeToHeadTransform(
                self.0,
                eye.to_raw(),
            );
            mat.m
        }
    }

    /// Computes the distortion caused by the optics
    pub fn time_since_last_vsync(&self) -> Option<(f32, u64)> {
        unsafe {
            let mut frame = 0;
            let mut sync = 0.;
            let found = openvr_sys::VR_IVRSystem_GetTimeSinceLastVsync(
                self.0,
                &mut sync,
                &mut frame
            );

            if found {
                Some((sync, frame))
            } else {
                None
            }
        }
    }

    /// Fetch the tracked results from the HMD
    pub fn tracked_devices(&self, time: f32) -> TrackedDevicePoses {
        unsafe {
            let mut data: [openvr_sys::TrackedDevicePose_t; 16] = std::mem::zeroed();
            openvr_sys::VR_IVRSystem_GetDeviceToAbsoluteTrackingPose(
                self.0,
                openvr_sys::TrackingUniverseOrigin::TrackingUniverseSeated,
                time,
                &mut data[0],
                16
            );
            to_tracked(data)
        }
    }

    /// If the device supports a compositor return a instance
    pub fn compositor(&self) -> Result<Compositor, openvr_sys::HmdError> {
        unsafe {
            let mut err = openvr_sys::HmdError::None;
            let name = std::ffi::CString::new("IVRCompositor_006").unwrap();
            let ptr = openvr_sys::VR_GetGenericInterface(name.as_ptr(), &mut err as *mut openvr_sys::HmdError);
            match err {
                openvr_sys::HmdError::None => Ok(Compositor(ptr)),
                err => Err(err)
            }
        }
    }

    /// get frequency of hmd in hz
    pub fn display_frequency(&self) -> f32 {
        unsafe {
            openvr_sys::VR_IVRSystem_GetFloatTrackedDeviceProperty(
                self.0,
                0,
                openvr_sys::TrackedDeviceProperty::DisplayFrequency_Float,
                std::ptr::null_mut()
            )
        }
    }

    /// get the time vsync to phonts
    pub fn vsync_to_photons(&self) -> f32 {
        unsafe {
            openvr_sys::VR_IVRSystem_GetFloatTrackedDeviceProperty(
                self.0,
                0,
                openvr_sys::TrackedDeviceProperty::SecondsFromVsyncToPhotons_Float,
                std::ptr::null_mut()
            )
        }
    }
}

impl Drop for IVRSystem {
    fn drop(&mut self) {
        unsafe {
            println!("Trying to shutdown openvr");
            openvr_sys::VR_Shutdown();
            println!("Should be done now.");
        }
    }
}

/// A VR compositor
pub struct Compositor(*const ());

impl Compositor {
    /// Check to see if the compositor is fullscreen
    pub fn is_fullscreen(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_IsFullscreen(self.0) }
    }

    /// Check if vsync in enabled
    pub fn get_vsync(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_GetVSync(self.0) }
    }

    /// Set the vsync value
    pub fn set_vsync(&self, v: bool) {
        unsafe { openvr_sys::VR_IVRCompositor_SetVSync(self.0, v) }
    }

    /// Check if vsync in enabled
    pub fn can_render_scene(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_CanRenderScene(self.0) }
    }

    /// Get the gamma value
    pub fn get_gamma(&self) -> f32 {
        unsafe { openvr_sys::VR_IVRCompositor_GetGamma(self.0) }
    }

    /// Get the gamma value
    pub fn set_gamma(&self, v: f32) {
        unsafe { openvr_sys::VR_IVRCompositor_SetGamma(self.0, v) }
    }

    /// Set the compositor to gl mode
    pub fn set_graphics_device_gl(&self) {
        unsafe {
            openvr_sys::VR_IVRCompositor_SetGraphicsDevice(
                self.0,
                openvr_sys::Compositor_DeviceType::DeviceType_OpenGL,
                std::ptr::null_mut()
            )
        }
    }

    /// Submit an eye to the render
    pub fn submit(&self, eye: Eye, texture: usize, bounds: TextureBounds) {
        let mut b = bounds.to_raw();
        let e = eye.to_raw();
        unsafe {
            use std::mem;
            let t = mem::transmute(texture);

            openvr_sys::VR_IVRCompositor_Submit(
                self.0,
                e,
                t,
                &mut b as *mut openvr_sys::VRTextureBounds_t
            );
        }
    }

    /// Get the poses
    pub fn wait_get_poses(&self) -> TrackedDevicePoses {
        unsafe {
            let mut data: [openvr_sys::TrackedDevicePose_t; 16] = std::mem::zeroed();
            openvr_sys::VR_IVRCompositor_WaitGetPoses(
                self.0,
                &mut data[0],
                16,
                std::ptr::null_mut(),
                0
            );
            to_tracked(data)
        }
    }
}
<commit_msg>maybe get api working again<commit_after>

extern crate openvr_sys;

pub struct IVRSystem(*const ());

#[derive(Debug, Copy, Clone)]
pub struct Size {
    pub width: u32,
    pub height: u32
}

#[derive(Debug, Copy, Clone)]
pub struct Position {
    pub x: i32,
    pub y: i32
}

#[derive(Debug, Copy, Clone)]
pub struct Rectangle {
    pub position: Position,
    pub size: Size
}

#[derive(Debug, Copy, Clone)]
pub struct DistortionCoordinates {
    pub red: [f32; 2],
    pub green: [f32; 2],
    pub blue: [f32; 2],
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Eye {
    Left, Right
}

impl Eye {
    /// Convert a eye to a HmdEye
    fn to_raw(&self) -> openvr_sys::Hmd_Eye {
        match self {
            &Eye::Left => openvr_sys::Hmd_Eye::Left,
            &Eye::Right => openvr_sys::Hmd_Eye::Right,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TextureBounds {
    pub u_min: f32,
    pub u_max: f32,
    pub v_min: f32,
    pub v_max: f32
}

impl TextureBounds {
    /// Convert a bounds to a openvr_bounds
    fn to_raw(self) -> openvr_sys::VRTextureBounds_t {
        openvr_sys::VRTextureBounds_t{
            uMin: self.u_min,
            uMax: self.u_max,
            vMin: self.v_min,
            vMax: self.v_max
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePose {
    pub to_device: [[f32; 4]; 3],
    pub velocity: [f32; 3],
    pub angular_velocity: [f32; 3],
    pub is_valid: bool,
    pub is_connected: bool,
}

#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePoses {
    pub count: usize,
    pub poses: [TrackedDevicePose; 16],
}

impl TrackedDevicePoses {
    pub fn as_slice(&self) -> &[TrackedDevicePose] {
        &self.poses[0..self.count]
    }
}

unsafe fn to_tracked(data: [openvr_sys::TrackedDevicePose_t; 16]) -> TrackedDevicePoses {
    let mut out: TrackedDevicePoses = std::mem::zeroed();
    for (i, d) in data.iter().enumerate() {
        if d.bDeviceIsConnected {
            out.count = i + 1;
        }
        out.poses[i].is_connected = d.bDeviceIsConnected;
        out.poses[i].is_valid = d.bPoseIsValid;
        out.poses[i].to_device = d.mDeviceToAbsoluteTracking.m;
        out.poses[i].velocity = d.vVelocity.v;
        out.poses[i].angular_velocity = d.vAngularVelocity.v;
    }
    out
}

impl IVRSystem {
    /// Initialize the IVR System
    pub fn init() -> Result<IVRSystem, openvr_sys::HmdError> {
        let mut err = openvr_sys::HmdError::None;
        let ptr = unsafe {
            openvr_sys::VR_Init(&mut err as *mut openvr_sys::HmdError)
        };
        if ptr.is_null() {
            Err(err)
        } else {
            Ok(IVRSystem(ptr))
        }
    }

    /// Get the window bounds
    pub fn bounds(&self) -> Rectangle {
        unsafe {
            let mut size = Size{width: 0, height: 0};
            let mut pos = Position{x: 0, y: 0};
            openvr_sys::VR_IVRSystem_GetWindowBounds(
                self.0,
                &mut pos.x,
                &mut pos.y,
                &mut size.width,
                &mut size.height
            );
            Rectangle {
                position: pos,
                size: size
            }
        }
    }

    /// Get the recommended render target size
    pub fn recommended_render_target_size(&self) -> Size {
        unsafe {
            let mut size = Size{width: 0, height: 0};
            openvr_sys::VR_IVRSystem_GetRecommendedRenderTargetSize(
                self.0,
                &mut size.width,
                &mut size.height
            );
            size
        }
    }

    /// Get eye viewport size
    pub fn eye_viewport(&self, eye: Eye) -> Rectangle {
        use std::mem;
        unsafe {
            let mut size = Size{width: 0, height: 0};
            let mut pos = Position{x: 0, y: 0};
            openvr_sys::VR_IVRSystem_GetEyeOutputViewport(
                self.0,
                eye.to_raw(),
                mem::transmute(&mut pos.x),
                mem::transmute(&mut pos.y),
                &mut size.width,
                &mut size.height
            );
            Rectangle {
                position: pos,
                size: size
            }
        }
    }

    /// Get the projection matrix for an eye
    /// supply the near and the far position
    /// assumes opengl conventions
    pub fn projection_matrix(&self, eye: Eye, near: f32, far: f32) -> [[f32; 4]; 4] {
        unsafe {
            let mat = openvr_sys::VR_IVRSystem_GetProjectionMatrix(
                self.0,
                eye.to_raw(),
                near,
                far,
                openvr_sys::GraphicsAPIConvention::OpenGL
            );
            mat.m
        }
    }

    /// Computes the distortion caused by the optics
    pub fn compute_distortion(&self, eye: Eye, u: f32, v: f32) -> DistortionCoordinates {
        unsafe {
            let coord = openvr_sys::VR_IVRSystem_ComputeDistortion(
                self.0,
                eye.to_raw(),
                u, v
            );
            DistortionCoordinates {
                red: coord.rfRed,
                blue: coord.rfBlue,
                green: coord.rfGreen
            }
        }
    }

    /// Computes the distortion caused by the optics
    pub fn eye_to_head_transform(&self, eye: Eye) -> [[f32; 4]; 3] {
        unsafe {
            let mat = openvr_sys::VR_IVRSystem_GetEyeToHeadTransform(
                self.0,
                eye.to_raw(),
            );
            mat.m
        }
    }

    /// Computes the distortion caused by the optics
    pub fn time_since_last_vsync(&self) -> Option<(f32, u64)> {
        unsafe {
            let mut frame = 0;
            let mut sync = 0.;
            let found = openvr_sys::VR_IVRSystem_GetTimeSinceLastVsync(
                self.0,
                &mut sync,
                &mut frame
            );

            if found {
                Some((sync, frame))
            } else {
                None
            }
        }
    }

    /// Fetch the tracked results from the HMD
    pub fn tracked_devices(&self, time: f32) -> TrackedDevicePoses {
        unsafe {
            let mut data: [openvr_sys::TrackedDevicePose_t; 16] = std::mem::zeroed();
            openvr_sys::VR_IVRSystem_GetDeviceToAbsoluteTrackingPose(
                self.0,
                openvr_sys::TrackingUniverseOrigin::TrackingUniverseSeated,
                time,
                &mut data[0],
                16
            );
            to_tracked(data)
        }
    }

    /// If the device supports a compositor return a instance
    pub fn compositor(&self) -> Result<Compositor, openvr_sys::HmdError> {
        unsafe {
            let mut err = openvr_sys::HmdError::None;
            let name = std::ffi::CString::new("IVRCompositor_006").unwrap();
            let ptr = openvr_sys::VR_GetGenericInterface(name.as_ptr() as *const u8, &mut err as *mut openvr_sys::HmdError);
            match err {
                openvr_sys::HmdError::None => Ok(Compositor(ptr)),
                err => Err(err)
            }
        }
    }

    /// get frequency of hmd in hz
    pub fn display_frequency(&self) -> f32 {
        unsafe {
            openvr_sys::VR_IVRSystem_GetFloatTrackedDeviceProperty(
                self.0,
                0,
                openvr_sys::TrackedDeviceProperty::DisplayFrequency_Float,
                std::ptr::null_mut()
            )
        }
    }

    /// get the time vsync to phonts
    pub fn vsync_to_photons(&self) -> f32 {
        unsafe {
            openvr_sys::VR_IVRSystem_GetFloatTrackedDeviceProperty(
                self.0,
                0,
                openvr_sys::TrackedDeviceProperty::SecondsFromVsyncToPhotons_Float,
                std::ptr::null_mut()
            )
        }
    }
}

impl Drop for IVRSystem {
    fn drop(&mut self) {
        unsafe {
            println!("Trying to shutdown openvr");
            openvr_sys::VR_Shutdown();
            println!("Should be done now.");
        }
    }
}

/// A VR compositor
pub struct Compositor(*const ());

impl Compositor {
    /// Check to see if the compositor is fullscreen
    pub fn is_fullscreen(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_IsFullscreen(self.0) }
    }

    /// Check if vsync in enabled
    pub fn get_vsync(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_GetVSync(self.0) }
    }

    /// Set the vsync value
    pub fn set_vsync(&self, v: bool) {
        unsafe { openvr_sys::VR_IVRCompositor_SetVSync(self.0, v) }
    }

    /// Check if vsync in enabled
    pub fn can_render_scene(&self) -> bool {
        unsafe { openvr_sys::VR_IVRCompositor_CanRenderScene(self.0) }
    }

    /// Get the gamma value
    pub fn get_gamma(&self) -> f32 {
        unsafe { openvr_sys::VR_IVRCompositor_GetGamma(self.0) }
    }

    /// Get the gamma value
    pub fn set_gamma(&self, v: f32) {
        unsafe { openvr_sys::VR_IVRCompositor_SetGamma(self.0, v) }
    }

    /// Submit an eye to the render
    pub fn submit(&self, eye: Eye, texture: usize, bounds: TextureBounds) {
        let mut b = bounds.to_raw();
        let e = eye.to_raw();
        unsafe {
            use std::mem;
            let t = mem::transmute(texture);

            openvr_sys::VR_IVRCompositor_Submit(
                self.0,
                e,
                openvr_sys::GraphicsAPIConvention::OpenGL,
                t,
                &mut b as *mut openvr_sys::VRTextureBounds_t,
                openvr_sys::VRSubmitFlags_t::Default
            );
        }
    }

    /// Get the poses
    pub fn wait_get_poses(&self) -> TrackedDevicePoses {
        unsafe {
            let mut data: [openvr_sys::TrackedDevicePose_t; 16] = std::mem::zeroed();
            openvr_sys::VR_IVRCompositor_WaitGetPoses(
                self.0,
                &mut data[0],
                16,
                std::ptr::null_mut(),
                0
            );
            to_tracked(data)
        }
    }
}
<|endoftext|>


<commit_before>//! This crate provides native rust implementations of
//! image encoders and decoders and basic image manipulation
//! functions.

#![warn(missing_docs)]
#![warn(unused_qualifications)]
#![deny(missing_copy_implementations)]
#![cfg_attr(all(test, feature = "benchmarks"), feature(test))]
// it's a bit of a pain otherwise
#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))]

extern crate byteorder;
extern crate lzw;
extern crate num_iter;
extern crate num_rational;
extern crate num_traits;
extern crate scoped_threadpool;
#[cfg(all(test, feature = "benchmarks"))]
extern crate test;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

use std::io::Write;

pub use color::ColorType::{self, Gray, GrayA, Palette, RGB, RGBA, BGR, BGRA};

pub use color::{Luma, LumaA, Rgb, Rgba, Bgr, Bgra};

pub use image::{AnimationDecoder,
                GenericImage,
                GenericImageView,
                ImageDecoder,
                ImageDecoderExt,
                ImageError,
                ImageResult,
                MutPixels,
                // Iterators
                Pixels,
                SubImage};

pub use imageops::FilterType::{self, CatmullRom, Gaussian, Lanczos3, Nearest, Triangle};

pub use image::ImageFormat::{self, BMP, GIF, ICO, JPEG, PNG, PNM, WEBP};

pub use image::ImageOutputFormat;

pub use buffer::{ConvertBuffer,
                 GrayAlphaImage,
                 GrayImage,
                 // Image types
                 ImageBuffer,
                 Pixel,
                 RgbImage,
                 RgbaImage};

pub use flat::{FlatSamples};

// Traits
pub use traits::Primitive;

// Opening and loading images
pub use dynimage::{guess_format, load, load_from_memory, load_from_memory_with_format, open,
                   save_buffer};

pub use dynimage::DynamicImage::{self, ImageLuma8, ImageLumaA8, ImageRgb8, ImageRgba8, ImageBgr8, ImageBgra8};

pub use animation::{Frame, Frames};

// Math utils
pub mod math;

// Image processing functions
pub mod imageops;

// Buffer representations for ffi.
pub mod flat;

// Image codecs
#[cfg(feature = "bmp")]
pub mod bmp;
#[cfg(feature = "dxt")]
pub mod dxt;
#[cfg(feature = "gif_codec")]
pub mod gif;
#[cfg(feature = "hdr")]
pub mod hdr;
#[cfg(feature = "ico")]
pub mod ico;
#[cfg(feature = "jpeg")]
pub mod jpeg;
#[cfg(feature = "png_codec")]
pub mod png;
#[cfg(feature = "pnm")]
pub mod pnm;
#[cfg(feature = "tga")]
pub mod tga;
#[cfg(feature = "tiff")]
pub mod tiff;
#[cfg(feature = "webp")]
pub mod webp;

mod animation;
mod buffer;
mod color;
mod dynimage;
mod image;
mod traits;
mod utils;

// Copies data from `src` to `dst`
//
// Panics if the length of `dst` is less than the length of `src`.
#[inline]
fn copy_memory(src: &[u8], mut dst: &mut [u8]) {
    let len_src = src.len();
    assert!(dst.len() >= len_src);
    dst.write_all(src).unwrap();
}
<commit_msg>Use scope_threadpool crate only with hdr feature<commit_after>//! This crate provides native rust implementations of
//! image encoders and decoders and basic image manipulation
//! functions.

#![warn(missing_docs)]
#![warn(unused_qualifications)]
#![deny(missing_copy_implementations)]
#![cfg_attr(all(test, feature = "benchmarks"), feature(test))]
// it's a bit of a pain otherwise
#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))]

extern crate byteorder;
extern crate lzw;
extern crate num_iter;
extern crate num_rational;
extern crate num_traits;
#[cfg(feature = "hdr")]
extern crate scoped_threadpool;
#[cfg(all(test, feature = "benchmarks"))]
extern crate test;

#[cfg(test)]
#[macro_use]
extern crate quickcheck;

use std::io::Write;

pub use color::ColorType::{self, Gray, GrayA, Palette, RGB, RGBA, BGR, BGRA};

pub use color::{Luma, LumaA, Rgb, Rgba, Bgr, Bgra};

pub use image::{AnimationDecoder,
                GenericImage,
                GenericImageView,
                ImageDecoder,
                ImageDecoderExt,
                ImageError,
                ImageResult,
                MutPixels,
                // Iterators
                Pixels,
                SubImage};

pub use imageops::FilterType::{self, CatmullRom, Gaussian, Lanczos3, Nearest, Triangle};

pub use image::ImageFormat::{self, BMP, GIF, ICO, JPEG, PNG, PNM, WEBP};

pub use image::ImageOutputFormat;

pub use buffer::{ConvertBuffer,
                 GrayAlphaImage,
                 GrayImage,
                 // Image types
                 ImageBuffer,
                 Pixel,
                 RgbImage,
                 RgbaImage};

pub use flat::{FlatSamples};

// Traits
pub use traits::Primitive;

// Opening and loading images
pub use dynimage::{guess_format, load, load_from_memory, load_from_memory_with_format, open,
                   save_buffer};

pub use dynimage::DynamicImage::{self, ImageLuma8, ImageLumaA8, ImageRgb8, ImageRgba8, ImageBgr8, ImageBgra8};

pub use animation::{Frame, Frames};

// Math utils
pub mod math;

// Image processing functions
pub mod imageops;

// Buffer representations for ffi.
pub mod flat;

// Image codecs
#[cfg(feature = "bmp")]
pub mod bmp;
#[cfg(feature = "dxt")]
pub mod dxt;
#[cfg(feature = "gif_codec")]
pub mod gif;
#[cfg(feature = "hdr")]
pub mod hdr;
#[cfg(feature = "ico")]
pub mod ico;
#[cfg(feature = "jpeg")]
pub mod jpeg;
#[cfg(feature = "png_codec")]
pub mod png;
#[cfg(feature = "pnm")]
pub mod pnm;
#[cfg(feature = "tga")]
pub mod tga;
#[cfg(feature = "tiff")]
pub mod tiff;
#[cfg(feature = "webp")]
pub mod webp;

mod animation;
mod buffer;
mod color;
mod dynimage;
mod image;
mod traits;
mod utils;

// Copies data from `src` to `dst`
//
// Panics if the length of `dst` is less than the length of `src`.
#[inline]
fn copy_memory(src: &[u8], mut dst: &mut [u8]) {
    let len_src = src.len();
    assert!(dst.len() >= len_src);
    dst.write_all(src).unwrap();
}
<|endoftext|>


<commit_before>#![cfg_attr(feature="nightly", feature(duration))]
#![doc(html_root_url = "http://ogeon.github.io/docs/rust-wiringpi/master/")]

extern crate libc;

use std::marker::PhantomData;

use pin::{Pin, RequiresRoot};

macro_rules! impl_pins {
    ($($name:ident),+) => (
        $(
            #[derive(Clone, Copy)]
            pub struct $name;

            impl Pin for $name {}
        )+
    )
}

macro_rules! require_root {
    ($($name:ident: $pwm:expr),+) => (
        $(
            impl RequiresRoot for $name {
                #[inline]
                fn pwm_pin() -> PwmPin<$name> {
                    PwmPin::new($pwm)
                }
            }
        )+
    )
}

mod bindings;

pub mod time {
    use bindings;
    #[cfg(feature="nightly")]
    use std::time::Duration;

    ///This causes program execution to pause for at least the provided
    ///duration in milliseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer or approximately 49
    ///days.
    #[cfg(feature="nightly")]
    pub fn delay(duration: Duration) {
        use libc;

        let duration = (duration.secs() * 1000) as u32 + duration.extra_nanos() / 1_000_000;
        if duration <= 0 {
            return;
        }

        unsafe {
            bindings::delay(duration as libc::c_uint);
        }
    }

    ///This causes program execution to pause for at least the provided number
    ///of milliseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer or approximately 49
    ///days.
    #[cfg(not(feature="nightly"))]
    pub fn delay(duration: u32) {
        unsafe {
            bindings::delay(duration);
        }
    }

    ///This causes program execution to pause for at least the provided number
    ///of microseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer microseconds or
    ///approximately 71 minutes.
    pub fn delay_microseconds(microseconds: u32) {
        unsafe {
            bindings::delayMicroseconds(microseconds);
        }
    }
}

pub mod thread {
    use bindings;
    use libc;

    ///This attempts to shift your program (or thread in a multi-threaded
    ///program) to a higher priority and enables a real-time scheduling.
    ///
    ///The priority parameter should be from 0 (the default) to 99 (the
    ///maximum). This won’t make your program go any faster, but it will give
    ///it a bigger slice of time when other programs are running. The priority
    ///parameter works relative to others – so you can make one program
    ///priority 1 and another priority 2 and it will have the same effect as
    ///setting one to 10 and the other to 90 (as long as no other programs are
    ///running with elevated priorities)
    ///
    ///The return value is `true` for success and `false` for error. If an
    ///error is returned, the program should then consult the _errno_ global
    ///variable, as per the usual conventions.
    ///
    ///_Note_: Only programs running as root can change their priority. If
    ///called from a non-root program then nothing happens.
    pub fn priority(priority: u8) -> bool {
        unsafe {
            bindings::piHiPri(priority as libc::c_int) >= 0
        }
    }
}

pub mod pin {
    use bindings;
    use libc;
    use self::Value::{Low, High};

    use std::marker::PhantomData;

    ///This returns the BCM_GPIO pin number of the supplied **wiringPi** pin.
    ///
    ///It takes the board revision into account.
    pub fn wpi_to_gpio_number(wpi_number: u16) -> u16 {
        unsafe {
            bindings::wpiPinToGpio(wpi_number as libc::c_int) as u16
        }
    }

    ///This returns the BCM_GPIO pin number of the supplied physical pin on
    ///the P1 connector.
    pub fn phys_to_gpio_number(phys_number: u16) -> u16 {
        unsafe {
            bindings::physPinToGpio(phys_number as libc::c_int) as u16
        }
    }

    impl_pins!(WiringPi, Gpio, Phys, Sys);
    require_root!(WiringPi: 1, Gpio: 18, Phys: 12);

    pub trait Pin {}

    pub trait RequiresRoot: Pin {
        fn pwm_pin() -> PwmPin<Self>;
    }

    #[derive(Clone, Copy)]
    pub enum Value {
        Low = 0,
        High
    }

    #[derive(Clone, Copy)]
    pub enum Pull {
        Off = 0,
        Down,
        Up
    }

    #[derive(Clone, Copy)]
    pub enum PwmMode {
        MarkSpace = 0,
        Balanced
    }

    pub struct InputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> InputPin<P> {
        pub fn new(pin: libc::c_int) -> InputPin<P> {
            unsafe {
                bindings::pinMode(pin, 0);
            }

            InputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &InputPin(number, _) = self;
            number
        }

        pub fn into_output(self) -> OutputPin<P> {
            let InputPin(number, _) = self;
            OutputPin::new(number)
        }

        ///This function returns the value read at the given pin.
        ///
        ///It will be `High` or `Low` (1 or 0) depending on the logic level at the pin.
        pub fn digital_read(&self) -> Value {
            let value = unsafe {
                bindings::digitalRead(self.number())
            };

            if value == 0 {
                Low
            } else {
                High
            }
        }
    }

    impl<P: Pin + RequiresRoot> InputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let InputPin(number, _) = self;
            PwmPin::new(number)
        }

        ///This sets the pull-up or pull-down resistor mode on the given pin.
        ///
        ///Unlike the Arduino, the BCM2835 has both pull-up an down internal
        ///resistors. The parameter pud should be; `Off`, (no pull up/down),
        ///`Down` (pull to ground) or `Up` (pull to 3.3v)
        pub fn pull_up_dn_control(&self, pud: Pull) {
            unsafe {
                bindings::pullUpDnControl(self.number(), pud as libc::c_int);
            }
        }
    }

    pub struct OutputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> OutputPin<P> {
        pub fn new(pin: libc::c_int) -> OutputPin<P> {
            unsafe {
                bindings::pinMode(pin, 1);
            }

            OutputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &OutputPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let OutputPin(number, _) = self;
            InputPin::new(number)
        }

        ///Writes the value `High` or `Low` (1 or 0) to the given pin which must have been previously set as an output.
        pub fn digital_write(&self, value: Value) {
            unsafe {
                bindings::digitalWrite(self.number(), value as libc::c_int);
            }
        }
    }

    impl<P: Pin + RequiresRoot> OutputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let OutputPin(number, _) = self;
            PwmPin::new(number)
        }
    }

    ///To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual.
    pub struct PwmPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin + RequiresRoot> PwmPin<P> {
        pub fn new(pin: libc::c_int) -> PwmPin<P> {
            unsafe {
                bindings::pinMode(pin, 2);
            }

            PwmPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &PwmPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let PwmPin(number, _) = self;
            InputPin::new(number)
        }

        pub fn into_output(self) -> OutputPin<P> {
            let PwmPin(number, _) = self;
            OutputPin::new(number)
        }

        ///Writes the value to the PWM register for the given pin.
        ///
        ///The value must be between 0 and 1024.
        pub fn write(&self, value: u16) {
            unsafe {
                bindings::pwmWrite(self.number(), value as libc::c_int);
            }
        }

        ///The PWM generator can run in 2 modes – "balanced" and "mark:space".
        ///
        ///The mark:space mode is traditional, however the default mode in the
        ///Pi is "balanced". You can switch modes by supplying the parameter:
        ///`Balanced` or `MarkSpace`.
        pub fn set_mode(&self, mode: PwmMode) {
            unsafe {
                bindings::pwmSetMode(mode as libc::c_int);
            }
        }

        ///This sets the range register in the PWM generator. The default is 1024.
        pub fn set_range(&self, value: u16) {
            unsafe {
                bindings::pwmSetRange(value as libc::c_uint);
            }
        }

        ///This sets the divisor for the PWM clock.
        pub fn set_clock(&self, value: u16) {
            unsafe {
                bindings::pwmSetClock(value as libc::c_int);
            }
        }
    }
}

///This initialises the wiringPi system and assumes that the calling program
///is going to be using the **wiringPi** pin numbering scheme.
///
///This is a simplified numbering scheme which provides a mapping from virtual
///pin numbers 0 through 16 to the real underlying Broadcom GPIO pin numbers.
///See the pins page for a table which maps the **wiringPi** pin number to the
///Broadcom GPIO pin number to the physical location on the edge connector.
///
///This function needs to be called with root privileges.
pub fn setup() -> WiringPi<pin::WiringPi> {
    unsafe { bindings::wiringPiSetup(); }
    WiringPi(PhantomData)
}

///This is identical to `setup()`, however it allows the calling programs to
///use the Broadcom GPIO pin numbers directly with no re-mapping.
///
///This function needs to be called with root privileges.
pub fn setup_gpio() -> WiringPi<pin::Gpio> {
    unsafe { bindings::wiringPiSetupGpio(); }
    WiringPi(PhantomData)
}

///This is identical to `setup()`, however it allows the calling programs to
///use the physical pin numbers _on the P1 connector only_.
///
///This function needs to be called with root privileges.
pub fn setup_phys() -> WiringPi<pin::Phys> {
    unsafe { bindings::wiringPiSetupPhys(); }
    WiringPi(PhantomData)
}

///This initialises the wiringPi system but uses the /sys/class/gpio interface
///rather than accessing the hardware directly.
///
///This can be called as a non-root user provided the GPIO pins have been
///exported before-hand using the gpio program. Pin number in this mode is the
///native Broadcom GPIO numbers.
///
///_Note_: In this mode you can only use the pins which have been exported via
///the /sys/class/gpio interface. You must export these pins before you call
///your program. You can do this in a separate shell-script, or by using the
///system() function from inside your program.
///
///Also note that some functions have no effect when using this mode as
///they’re not currently possible to action unless called with root
///privileges.
pub fn setup_sys() -> WiringPi<pin::Sys> {
    unsafe { bindings::wiringPiSetupSys(); }
    WiringPi(PhantomData)
}

///This returns the board revision of the Raspberry Pi.
///
///It will be either 1 or 2. Some of the BCM_GPIO pins changed number and
///function when moving from board revision 1 to 2, so if you are using
///BCM_GPIO pin numbers, then you need to be aware of the differences.
pub fn board_revision() -> i32 {
    unsafe {
        bindings::piBoardRev()
    }
}

pub struct WiringPi<Pin>(PhantomData<Pin>);

impl<P: Pin> WiringPi<P> {
    pub fn input_pin(&self, pin: u16) -> pin::InputPin<P> {
        let pin = pin as libc::c_int;
        pin::InputPin::new(pin)
    }

    pub fn output_pin(&self, pin: u16) -> pin::OutputPin<P> {
        let pin = pin as libc::c_int;
        pin::OutputPin::new(pin)
    }

    ///This returns a number representing the number if milliseconds since
    ///your program called one of the setup functions.
    ///
    ///It returns an unsigned 32-bit number which wraps after 49 days.
    pub fn millis(&self) -> u32 {
        unsafe {
            bindings::millis()
        }
    }

    ///This returns a number representing the number if microseconds since
    ///your program called one of the setup functions.
    ///
    ///It returns an unsigned 32-bit number which wraps after 71 minutes.

    pub fn micros(&self) -> u32 {
        unsafe {
            bindings::micros()
        }
    }
}

impl<P: RequiresRoot + Pin> WiringPi<P> {
    pub fn pwm_pin(&self) -> pin::PwmPin<P> {
        RequiresRoot::pwm_pin()
    }
}<commit_msg>Add digital_write_byte<commit_after>#![cfg_attr(feature="nightly", feature(duration))]
#![doc(html_root_url = "http://ogeon.github.io/docs/rust-wiringpi/master/")]

extern crate libc;

use std::marker::PhantomData;

use pin::{Pin, RequiresRoot};

macro_rules! impl_pins {
    ($($name:ident),+) => (
        $(
            #[derive(Clone, Copy)]
            pub struct $name;

            impl Pin for $name {}
        )+
    )
}

macro_rules! require_root {
    ($($name:ident: $pwm:expr),+) => (
        $(
            impl RequiresRoot for $name {
                #[inline]
                fn pwm_pin() -> PwmPin<$name> {
                    PwmPin::new($pwm)
                }
            }
        )+
    )
}

mod bindings;

pub mod time {
    use bindings;
    #[cfg(feature="nightly")]
    use std::time::Duration;

    ///This causes program execution to pause for at least the provided
    ///duration in milliseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer or approximately 49
    ///days.
    #[cfg(feature="nightly")]
    pub fn delay(duration: Duration) {
        use libc;

        let duration = (duration.secs() * 1000) as u32 + duration.extra_nanos() / 1_000_000;
        if duration <= 0 {
            return;
        }

        unsafe {
            bindings::delay(duration as libc::c_uint);
        }
    }

    ///This causes program execution to pause for at least the provided number
    ///of milliseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer or approximately 49
    ///days.
    #[cfg(not(feature="nightly"))]
    pub fn delay(duration: u32) {
        unsafe {
            bindings::delay(duration);
        }
    }

    ///This causes program execution to pause for at least the provided number
    ///of microseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer microseconds or
    ///approximately 71 minutes.
    pub fn delay_microseconds(microseconds: u32) {
        unsafe {
            bindings::delayMicroseconds(microseconds);
        }
    }
}

pub mod thread {
    use bindings;
    use libc;

    ///This attempts to shift your program (or thread in a multi-threaded
    ///program) to a higher priority and enables a real-time scheduling.
    ///
    ///The priority parameter should be from 0 (the default) to 99 (the
    ///maximum). This won’t make your program go any faster, but it will give
    ///it a bigger slice of time when other programs are running. The priority
    ///parameter works relative to others – so you can make one program
    ///priority 1 and another priority 2 and it will have the same effect as
    ///setting one to 10 and the other to 90 (as long as no other programs are
    ///running with elevated priorities)
    ///
    ///The return value is `true` for success and `false` for error. If an
    ///error is returned, the program should then consult the _errno_ global
    ///variable, as per the usual conventions.
    ///
    ///_Note_: Only programs running as root can change their priority. If
    ///called from a non-root program then nothing happens.
    pub fn priority(priority: u8) -> bool {
        unsafe {
            bindings::piHiPri(priority as libc::c_int) >= 0
        }
    }
}

pub mod pin {
    use bindings;
    use libc;
    use self::Value::{Low, High};

    use std::marker::PhantomData;

    ///This returns the BCM_GPIO pin number of the supplied **wiringPi** pin.
    ///
    ///It takes the board revision into account.
    pub fn wpi_to_gpio_number(wpi_number: u16) -> u16 {
        unsafe {
            bindings::wpiPinToGpio(wpi_number as libc::c_int) as u16
        }
    }

    ///This returns the BCM_GPIO pin number of the supplied physical pin on
    ///the P1 connector.
    pub fn phys_to_gpio_number(phys_number: u16) -> u16 {
        unsafe {
            bindings::physPinToGpio(phys_number as libc::c_int) as u16
        }
    }

    impl_pins!(WiringPi, Gpio, Phys, Sys);
    require_root!(WiringPi: 1, Gpio: 18, Phys: 12);

    pub trait Pin {}

    pub trait RequiresRoot: Pin {
        fn pwm_pin() -> PwmPin<Self>;
    }

    #[derive(Clone, Copy)]
    pub enum Value {
        Low = 0,
        High
    }

    #[derive(Clone, Copy)]
    pub enum Pull {
        Off = 0,
        Down,
        Up
    }

    #[derive(Clone, Copy)]
    pub enum PwmMode {
        MarkSpace = 0,
        Balanced
    }

    pub struct InputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> InputPin<P> {
        pub fn new(pin: libc::c_int) -> InputPin<P> {
            unsafe {
                bindings::pinMode(pin, 0);
            }

            InputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &InputPin(number, _) = self;
            number
        }

        pub fn into_output(self) -> OutputPin<P> {
            let InputPin(number, _) = self;
            OutputPin::new(number)
        }

        ///This function returns the value read at the given pin.
        ///
        ///It will be `High` or `Low` (1 or 0) depending on the logic level at the pin.
        pub fn digital_read(&self) -> Value {
            let value = unsafe {
                bindings::digitalRead(self.number())
            };

            if value == 0 {
                Low
            } else {
                High
            }
        }
    }

    impl<P: Pin + RequiresRoot> InputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let InputPin(number, _) = self;
            PwmPin::new(number)
        }

        ///This sets the pull-up or pull-down resistor mode on the given pin.
        ///
        ///Unlike the Arduino, the BCM2835 has both pull-up an down internal
        ///resistors. The parameter pud should be; `Off`, (no pull up/down),
        ///`Down` (pull to ground) or `Up` (pull to 3.3v)
        pub fn pull_up_dn_control(&self, pud: Pull) {
            unsafe {
                bindings::pullUpDnControl(self.number(), pud as libc::c_int);
            }
        }
    }

    pub struct OutputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> OutputPin<P> {
        pub fn new(pin: libc::c_int) -> OutputPin<P> {
            unsafe {
                bindings::pinMode(pin, 1);
            }

            OutputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &OutputPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let OutputPin(number, _) = self;
            InputPin::new(number)
        }

        ///Writes the value `High` or `Low` (1 or 0) to the given pin which must have been previously set as an output.
        pub fn digital_write(&self, value: Value) {
            unsafe {
                bindings::digitalWrite(self.number(), value as libc::c_int);
            }
        }
    }

    impl<P: Pin + RequiresRoot> OutputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let OutputPin(number, _) = self;
            PwmPin::new(number)
        }
    }

    ///To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual.
    pub struct PwmPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin + RequiresRoot> PwmPin<P> {
        pub fn new(pin: libc::c_int) -> PwmPin<P> {
            unsafe {
                bindings::pinMode(pin, 2);
            }

            PwmPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &PwmPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let PwmPin(number, _) = self;
            InputPin::new(number)
        }

        pub fn into_output(self) -> OutputPin<P> {
            let PwmPin(number, _) = self;
            OutputPin::new(number)
        }

        ///Writes the value to the PWM register for the given pin.
        ///
        ///The value must be between 0 and 1024.
        pub fn write(&self, value: u16) {
            unsafe {
                bindings::pwmWrite(self.number(), value as libc::c_int);
            }
        }

        ///The PWM generator can run in 2 modes – "balanced" and "mark:space".
        ///
        ///The mark:space mode is traditional, however the default mode in the
        ///Pi is "balanced". You can switch modes by supplying the parameter:
        ///`Balanced` or `MarkSpace`.
        pub fn set_mode(&self, mode: PwmMode) {
            unsafe {
                bindings::pwmSetMode(mode as libc::c_int);
            }
        }

        ///This sets the range register in the PWM generator. The default is 1024.
        pub fn set_range(&self, value: u16) {
            unsafe {
                bindings::pwmSetRange(value as libc::c_uint);
            }
        }

        ///This sets the divisor for the PWM clock.
        pub fn set_clock(&self, value: u16) {
            unsafe {
                bindings::pwmSetClock(value as libc::c_int);
            }
        }
    }
}

///This initialises the wiringPi system and assumes that the calling program
///is going to be using the **wiringPi** pin numbering scheme.
///
///This is a simplified numbering scheme which provides a mapping from virtual
///pin numbers 0 through 16 to the real underlying Broadcom GPIO pin numbers.
///See the pins page for a table which maps the **wiringPi** pin number to the
///Broadcom GPIO pin number to the physical location on the edge connector.
///
///This function needs to be called with root privileges.
pub fn setup() -> WiringPi<pin::WiringPi> {
    unsafe { bindings::wiringPiSetup(); }
    WiringPi(PhantomData)
}

///This is identical to `setup()`, however it allows the calling programs to
///use the Broadcom GPIO pin numbers directly with no re-mapping.
///
///This function needs to be called with root privileges.
pub fn setup_gpio() -> WiringPi<pin::Gpio> {
    unsafe { bindings::wiringPiSetupGpio(); }
    WiringPi(PhantomData)
}

///This is identical to `setup()`, however it allows the calling programs to
///use the physical pin numbers _on the P1 connector only_.
///
///This function needs to be called with root privileges.
pub fn setup_phys() -> WiringPi<pin::Phys> {
    unsafe { bindings::wiringPiSetupPhys(); }
    WiringPi(PhantomData)
}

///This initialises the wiringPi system but uses the /sys/class/gpio interface
///rather than accessing the hardware directly.
///
///This can be called as a non-root user provided the GPIO pins have been
///exported before-hand using the gpio program. Pin number in this mode is the
///native Broadcom GPIO numbers.
///
///_Note_: In this mode you can only use the pins which have been exported via
///the /sys/class/gpio interface. You must export these pins before you call
///your program. You can do this in a separate shell-script, or by using the
///system() function from inside your program.
///
///Also note that some functions have no effect when using this mode as
///they’re not currently possible to action unless called with root
///privileges.
pub fn setup_sys() -> WiringPi<pin::Sys> {
    unsafe { bindings::wiringPiSetupSys(); }
    WiringPi(PhantomData)
}

///This returns the board revision of the Raspberry Pi.
///
///It will be either 1 or 2. Some of the BCM_GPIO pins changed number and
///function when moving from board revision 1 to 2, so if you are using
///BCM_GPIO pin numbers, then you need to be aware of the differences.
pub fn board_revision() -> i32 {
    unsafe {
        bindings::piBoardRev()
    }
}

pub struct WiringPi<Pin>(PhantomData<Pin>);

impl<P: Pin> WiringPi<P> {
    pub fn input_pin(&self, pin: u16) -> pin::InputPin<P> {
        let pin = pin as libc::c_int;
        pin::InputPin::new(pin)
    }

    pub fn output_pin(&self, pin: u16) -> pin::OutputPin<P> {
        let pin = pin as libc::c_int;
        pin::OutputPin::new(pin)
    }

    ///This returns a number representing the number if milliseconds since
    ///your program called one of the setup functions.
    ///
    ///It returns an unsigned 32-bit number which wraps after 49 days.
    pub fn millis(&self) -> u32 {
        unsafe {
            bindings::millis()
        }
    }

    ///This returns a number representing the number if microseconds since
    ///your program called one of the setup functions.
    ///
    ///It returns an unsigned 32-bit number which wraps after 71 minutes.
    pub fn micros(&self) -> u32 {
        unsafe {
            bindings::micros()
        }
    }

    ///This writes the 8-bit byte supplied to the first 8 GPIO pins. It’s the
    ///fastest way to set all 8 bits at once to a particular value, although
    ///it still takes two write operations to the Pi’s GPIO hardware.
    pub fn digital_write_byte(&self, byte: u8) {
        unsafe {
            bindings::digitalWriteByte(byte as libc::c_int);
        }
    }
}

impl<P: RequiresRoot + Pin> WiringPi<P> {
    pub fn pwm_pin(&self) -> pin::PwmPin<P> {
        RequiresRoot::pwm_pin()
    }
}<|endoftext|>


<commit_before>#![feature(old_io)]
#![feature(old_path)]

extern crate time;

use std::old_io::IoError;
use std::old_io::net::udp::UdpSocket;
use std::old_io::net::ip::{ Ipv4Addr, SocketAddr };
use time::Tm;
use std::old_io::net::pipe::UnixStream;

// https://tools.ietf.org/html/rfc5424#section-6.2.1

#[derive(Copy,Clone)]
pub enum Facility {
  KERN     = 0,
  USER     = 1 << 3,
  MAIL     = 2 << 3,
  DAEMON   = 3 << 3,
  AUTH     = 4 << 3,
  SYSLOG   = 5 << 3,
  LPR      = 6 << 3,
  NEWS     = 7 << 3,
  UUCP     = 8 << 3,
  CRON     = 9 << 3,
  AUTHPRIV = 10 << 3,
  FTP      = 11 << 3,
  LOCAL0   = 16 << 3,
  LOCAL1   = 17 << 3,
  LOCAL2   = 18 << 3,
  LOCAL3   = 19 << 3,
  LOCAL4   = 20 << 3,
  LOCAL5   = 21 << 3,
  LOCAL6   = 22 << 3,
  LOCAL7   = 23 << 3
}

pub enum Severity {
  EMERG,
  ALERT,
  CRIT,
  ERR,
  WARNING,
  NOTICE,
  INFO,
  DEBUG
}

trait Transport {
  fn send(&mut self, line: &str) -> Result<(), IoError>;
}

impl Transport for (UdpSocket, SocketAddr) {
  fn send(&mut self, line: &str) -> Result<(), IoError> {
    self.0.send_to(line.as_bytes(), self.1)
  }
}

impl Transport for UnixStream {
  fn send(&mut self, line: &str) -> Result<(), IoError> {
    self.write_line(line)
  }
}

// a rust interface for syslog
pub struct Syslog {
  facility: Facility,
  tag: Option<String>,
  transport: Box<Transport>
}

impl Syslog {
   pub fn udp(host: SocketAddr) -> Syslog {
     let socket =
       match UdpSocket::bind(SocketAddr { ip: Ipv4Addr(0,0,0,0), port: 0 }) {
         Err(e) => panic!("error binding to local addr {}", e),
         Ok(s) => s
       };
      let tup = (socket, host);
      Syslog {
        facility: Facility::USER,
        tag: None,
        transport: Box::new(tup)
      }
  }

  pub fn unix(path: Path) -> Syslog {
    let stream =
      match UnixStream::connect(&path) {
        Err(_) => panic!("failed to connect to socket"),
        Ok(s)  => s
      };
    Syslog {
      facility: Facility::USER,
      tag: None,
      transport: Box::new(stream)
    }
  }

  pub fn tag(self, tag: &str) -> Syslog {
    Syslog {
      facility: self.facility,
      tag: Some(tag.to_string()),
      transport: self.transport
    }
  }

  pub fn facility(self, facility: Facility) -> Syslog {
    Syslog {
      facility: facility,
      tag: self.tag,
      transport: self.transport
    }
  }

  fn log(&mut self, severity: Severity,  msg: &str) -> Result<(), IoError> {
    let formatted = Syslog::line(self.facility.clone(), severity, time::now(), msg);
    self.transport.send(&formatted)
  }

  pub fn debug(&mut self, msg: &str) -> Result<(), IoError> {
    self.log(Severity::DEBUG, msg)
  }

  pub fn info(&mut self, msg: &str) -> Result<(), IoError> {
    self.log(Severity::INFO, msg)
  }

  fn line(facility: Facility, severity: Severity, timestamp: Tm, msg: &str) -> String {
    format!("<{:?}> {} {}", Syslog::priority(facility, severity), timestamp.rfc3339(), msg)
  }

  // computes the priority of a message based on a facility and severity
  fn priority(facility: Facility, severity: Severity) -> u8 {
    facility as u8 | severity as u8
  }
}

#[cfg(test)]
mod tests {
  use super::{Syslog, Facility, Severity};
  use time;
  #[test]
  fn test_syslog_line() {
    let ts = time::now();
    assert_eq!(Syslog::line(Facility::LOCAL0, Severity::INFO, ts, "yo"),
               format!("<134> {} yo", ts.rfc3339()));
  }
}
<commit_msg>better names<commit_after>#![feature(old_io)]
#![feature(old_path)]

extern crate time;

use std::old_io::IoError;
use std::old_io::net::udp::UdpSocket;
use std::old_io::net::ip::{ Ipv4Addr, SocketAddr };
use std::result;
use time::Tm;
use std::old_io::net::pipe::UnixStream;

// https://tools.ietf.org/html/rfc5424#section-6.2.1

pub type Result = result::Result<(), IoError>;

#[derive(Copy,Clone)]
pub enum Facility {
  KERN     = 0,
  USER     = 1 << 3,
  MAIL     = 2 << 3,
  DAEMON   = 3 << 3,
  AUTH     = 4 << 3,
  SYSLOG   = 5 << 3,
  LINEPTR  = 6 << 3,
  NEWS     = 7 << 3,
  UUCP     = 8 << 3,
  CLOCK    = 9 << 3,
  AUTHPRIV = 10 << 3,
  FTP      = 11 << 3,
  LOCAL0   = 16 << 3,
  LOCAL1   = 17 << 3,
  LOCAL2   = 18 << 3,
  LOCAL3   = 19 << 3,
  LOCAL4   = 20 << 3,
  LOCAL5   = 21 << 3,
  LOCAL6   = 22 << 3,
  LOCAL7   = 23 << 3
}

pub enum Severity {
  EMERGENCY,
  ALERT,
  CRITICAL,
  ERROR,
  WARNING,
  NOTICE,
  INFO,
  DEBUG
}

trait Transport {
  fn send(&mut self, line: &str) -> Result;
}

impl Transport for (UdpSocket, SocketAddr) {
  fn send(&mut self, line: &str) -> Result {
    self.0.send_to(line.as_bytes(), self.1)
  }
}

impl Transport for UnixStream {
  fn send(&mut self, line: &str) -> Result {
    self.write_line(line)
  }
}

// a rust interface for syslog
pub struct Syslog {
  facility: Facility,
  tag: Option<String>,
  transport: Box<Transport>
}

impl Syslog {
   pub fn udp(host: SocketAddr) -> Syslog {
     let socket =
       match UdpSocket::bind(SocketAddr { ip: Ipv4Addr(0,0,0,0), port: 0 }) {
         Err(e) => panic!("error binding to local addr {}", e),
         Ok(s) => s
       };
      let tup = (socket, host);
      Syslog {
        facility: Facility::USER,
        tag: None,
        transport: Box::new(tup)
      }
  }

  pub fn unix(path: Path) -> Syslog {
    let stream =
      match UnixStream::connect(&path) {
        Err(_) => panic!("failed to connect to socket"),
        Ok(s)  => s
      };
    Syslog {
      facility: Facility::USER,
      tag: None,
      transport: Box::new(stream)
    }
  }

  pub fn tag(self, tag: &str) -> Syslog {
    Syslog {
      facility: self.facility,
      tag: Some(tag.to_string()),
      transport: self.transport
    }
  }

  pub fn facility(self, facility: Facility) -> Syslog {
    Syslog {
      facility: facility,
      tag: self.tag,
      transport: self.transport
    }
  }

  fn log(&mut self, severity: Severity,  msg: &str) -> Result {
    let formatted = Syslog::line(self.facility.clone(), severity, time::now(), msg);
    self.transport.send(&formatted)
  }

  pub fn debug(&mut self, msg: &str) -> Result {
    self.log(Severity::DEBUG, msg)
  }

  pub fn info(&mut self, msg: &str) -> Result {
    self.log(Severity::INFO, msg)
  }

  pub fn notice(&mut self, msg: &str) -> Result {
    self.log(Severity::NOTICE, msg)
  }

  pub fn warn(&mut self, msg: &str) -> Result {
    self.log(Severity::WARNING, msg)
  }

  pub fn err(&mut self, msg: &str) -> Result {
    self.log(Severity::ERROR, msg)
  }

  pub fn critical(&mut self, msg: &str) -> Result {
    self.log(Severity::CRITICAL, msg)
  }

  pub fn alert(&mut self, msg: &str) -> Result {
    self.log(Severity::ALERT, msg)
  }

  pub fn emergency(&mut self, msg: &str) -> Result {
    self.log(Severity::EMERGENCY, msg)
  }

  fn line(facility: Facility, severity: Severity, timestamp: Tm, msg: &str) -> String {
    format!("<{:?}> {} {}", Syslog::priority(facility, severity), timestamp.rfc3339(), msg)
  }

  // computes the priority of a message based on a facility and severity
  fn priority(facility: Facility, severity: Severity) -> u8 {
    facility as u8 | severity as u8
  }
}

#[cfg(test)]
mod tests {
  use super::{Syslog, Facility, Severity};
  use time;
  #[test]
  fn test_syslog_line() {
    let ts = time::now();
    assert_eq!(Syslog::line(Facility::LOCAL0, Severity::INFO, ts, "yo"),
               format!("<134> {} yo", ts.rfc3339()));
  }
}
<|endoftext|>