<commit_before>use std::fmt;
use std::cmp::Ordering;
use std::hash::{Hasher, Hash};
use std::str;
use libc;

use {raw, Error};
use util::Binding;

/// Unique identity of any object (commit, tree, blob, tag).
#[derive(Copy)]
pub struct Oid {
    raw: raw::git_oid,
}

impl Oid {
    /// Parse a hex-formatted object id into an Oid structure.
    ///
    /// If the string is not a valid 40-character hex string, an error is
    /// returned.
    pub fn from_str(s: &str) -> Result<Oid, Error> {
        ::init();
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        unsafe {
            try_call!(raw::git_oid_fromstrn(&mut raw,
                                            s.as_bytes().as_ptr()
                                                as *const libc::c_char,
                                            s.len() as libc::size_t));
        }
        Ok(Oid { raw: raw })
    }

    /// Parse a raw object id into an Oid structure.
    ///
    /// If the array given is not 20 bytes in length, an error is returned.
    pub fn from_bytes(bytes: &[u8]) -> Result<Oid, Error> {
        ::init();
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        if bytes.len() != raw::GIT_OID_RAWSZ {
            Err(Error::from_str("raw byte array must be 20 bytes"))
        } else {
            unsafe { raw::git_oid_fromraw(&mut raw, bytes.as_ptr()) }
            Ok(Oid { raw: raw })
        }
    }

    /// View this OID as a byte-slice 20 bytes in length.
    pub fn as_bytes(&self) -> &[u8] { &self.raw.id }

    /// Test if this OID is all zeros.
    pub fn is_zero(&self) -> bool {
        unsafe { raw::git_oid_iszero(&self.raw) == 1 }
    }
}

impl Binding for Oid {
    type Raw = *const raw::git_oid;

    unsafe fn from_raw(oid: *const raw::git_oid) -> Oid {
        Oid { raw: *oid }
    }
    fn raw(&self) -> *const raw::git_oid { &self.raw as *const _ }
}

impl fmt::Debug for Oid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl fmt::Display for Oid {
    /// Hex-encode this Oid into a formatter.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut dst = [0u8; raw::GIT_OID_HEXSZ + 1];
        unsafe {
            raw::git_oid_tostr(dst.as_mut_ptr() as *mut libc::c_char,
                               dst.len() as libc::size_t, &self.raw);
        }
        let s = &dst[..dst.iter().position(|&a| a == 0).unwrap()];
        str::from_utf8(s).unwrap().fmt(f)
    }
}

impl str::FromStr for Oid {
    type Err = Error;

    /// Parse a hex-formatted object id into an Oid structure.
    ///
    /// If the string is not a valid 40-character hex string, an error is
    /// returned.
    fn from_str(s: &str) -> Result<Oid, Error> {
        Oid::from_str(s)
    }
}

impl PartialEq for Oid {
    fn eq(&self, other: &Oid) -> bool {
        unsafe { raw::git_oid_equal(&self.raw, &other.raw) != 0 }
    }
}
impl Eq for Oid {}

impl PartialOrd for Oid {
    fn partial_cmp(&self, other: &Oid) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Oid {
    fn cmp(&self, other: &Oid) -> Ordering {
        match unsafe { raw::git_oid_cmp(&self.raw, &other.raw) } {
            0 => Ordering::Equal,
            n if n < 0 => Ordering::Less,
            _ => Ordering::Greater,
        }
    }
}

impl Clone for Oid {
    fn clone(&self) -> Oid { *self }
}

impl Hash for Oid {
    fn hash<H: Hasher>(&self, into: &mut H) {
        self.raw.id.hash(into)
    }
}

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

    #[test]
    fn conversions() {
        assert!(Oid::from_str("foo").is_err());
        assert!(Oid::from_str("decbf2be529ab6557d5429922251e5ee36519817").is_ok());
        assert!(Oid::from_bytes(b"foo").is_err());
        assert!(Oid::from_bytes(b"00000000000000000000").is_ok());
    }
}
<commit_msg>Add `impl AsRef<[u8]> for Oid` (closes #108)<commit_after>use std::fmt;
use std::cmp::Ordering;
use std::hash::{Hasher, Hash};
use std::str;
use libc;

use {raw, Error};
use util::Binding;

/// Unique identity of any object (commit, tree, blob, tag).
#[derive(Copy)]
pub struct Oid {
    raw: raw::git_oid,
}

impl Oid {
    /// Parse a hex-formatted object id into an Oid structure.
    ///
    /// If the string is not a valid 40-character hex string, an error is
    /// returned.
    pub fn from_str(s: &str) -> Result<Oid, Error> {
        ::init();
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        unsafe {
            try_call!(raw::git_oid_fromstrn(&mut raw,
                                            s.as_bytes().as_ptr()
                                                as *const libc::c_char,
                                            s.len() as libc::size_t));
        }
        Ok(Oid { raw: raw })
    }

    /// Parse a raw object id into an Oid structure.
    ///
    /// If the array given is not 20 bytes in length, an error is returned.
    pub fn from_bytes(bytes: &[u8]) -> Result<Oid, Error> {
        ::init();
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        if bytes.len() != raw::GIT_OID_RAWSZ {
            Err(Error::from_str("raw byte array must be 20 bytes"))
        } else {
            unsafe { raw::git_oid_fromraw(&mut raw, bytes.as_ptr()) }
            Ok(Oid { raw: raw })
        }
    }

    /// View this OID as a byte-slice 20 bytes in length.
    pub fn as_bytes(&self) -> &[u8] { &self.raw.id }

    /// Test if this OID is all zeros.
    pub fn is_zero(&self) -> bool {
        unsafe { raw::git_oid_iszero(&self.raw) == 1 }
    }
}

impl Binding for Oid {
    type Raw = *const raw::git_oid;

    unsafe fn from_raw(oid: *const raw::git_oid) -> Oid {
        Oid { raw: *oid }
    }
    fn raw(&self) -> *const raw::git_oid { &self.raw as *const _ }
}

impl fmt::Debug for Oid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl fmt::Display for Oid {
    /// Hex-encode this Oid into a formatter.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut dst = [0u8; raw::GIT_OID_HEXSZ + 1];
        unsafe {
            raw::git_oid_tostr(dst.as_mut_ptr() as *mut libc::c_char,
                               dst.len() as libc::size_t, &self.raw);
        }
        let s = &dst[..dst.iter().position(|&a| a == 0).unwrap()];
        str::from_utf8(s).unwrap().fmt(f)
    }
}

impl str::FromStr for Oid {
    type Err = Error;

    /// Parse a hex-formatted object id into an Oid structure.
    ///
    /// If the string is not a valid 40-character hex string, an error is
    /// returned.
    fn from_str(s: &str) -> Result<Oid, Error> {
        Oid::from_str(s)
    }
}

impl PartialEq for Oid {
    fn eq(&self, other: &Oid) -> bool {
        unsafe { raw::git_oid_equal(&self.raw, &other.raw) != 0 }
    }
}
impl Eq for Oid {}

impl PartialOrd for Oid {
    fn partial_cmp(&self, other: &Oid) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Oid {
    fn cmp(&self, other: &Oid) -> Ordering {
        match unsafe { raw::git_oid_cmp(&self.raw, &other.raw) } {
            0 => Ordering::Equal,
            n if n < 0 => Ordering::Less,
            _ => Ordering::Greater,
        }
    }
}

impl Clone for Oid {
    fn clone(&self) -> Oid { *self }
}

impl Hash for Oid {
    fn hash<H: Hasher>(&self, into: &mut H) {
        self.raw.id.hash(into)
    }
}

impl AsRef<[u8]> for Oid {
    fn as_ref(&self) -> &[u8] { self.as_bytes() }
}

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

    #[test]
    fn conversions() {
        assert!(Oid::from_str("foo").is_err());
        assert!(Oid::from_str("decbf2be529ab6557d5429922251e5ee36519817").is_ok());
        assert!(Oid::from_bytes(b"foo").is_err());
        assert!(Oid::from_bytes(b"00000000000000000000").is_ok());
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::cmp::Ordering;
use std::hash::{Hasher, Hash};
use std::str;
use libc;

use {raw, Error};
use util::Binding;

/// Unique identity of any object (commit, tree, blob, tag).
#[derive(Copy)]
pub struct Oid {
    raw: raw::git_oid,
}

impl Oid {
    /// Parse a hex-formatted object id into an Oid structure.
    ///
    /// If the string is not a valid 40-character hex string, an error is
    /// returned.
    pub fn from_str(s: &str) -> Result<Oid, Error> {
        ::init();
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        unsafe {
            try_call!(raw::git_oid_fromstrn(&mut raw,
                                            s.as_bytes().as_ptr()
                                                as *const libc::c_char,
                                            s.len() as libc::size_t));
        }
        Ok(Oid { raw: raw })
    }

    /// Parse a raw object id into an Oid structure.
    ///
    /// If the array given is not 20 bytes in length, an error is returned.
    pub fn from_bytes(bytes: &[u8]) -> Result<Oid, Error> {
        ::init();
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        if bytes.len() != raw::GIT_OID_RAWSZ {
            Err(Error::from_str("raw byte array must be 20 bytes"))
        } else {
            unsafe { raw::git_oid_fromraw(&mut raw, bytes.as_ptr()) }
            Ok(Oid { raw: raw })
        }
    }

    /// View this OID as a byte-slice 20 bytes in length.
    pub fn as_bytes(&self) -> &[u8] { &self.raw.id }

    /// Test if this OID is all zeros.
    pub fn is_zero(&self) -> bool {
        unsafe { raw::git_oid_iszero(&self.raw) == 1 }
    }
}

impl Binding for Oid {
    type Raw = *const raw::git_oid;

    unsafe fn from_raw(oid: *const raw::git_oid) -> Oid {
        Oid { raw: *oid }
    }
    fn raw(&self) -> *const raw::git_oid { &self.raw as *const _ }
}

impl fmt::Debug for Oid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl fmt::Display for Oid {
    /// Hex-encode this Oid into a formatter.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut dst = [0u8; raw::GIT_OID_HEXSZ + 1];
        unsafe {
            raw::git_oid_tostr(dst.as_mut_ptr() as *mut libc::c_char,
                               dst.len() as libc::size_t, &self.raw);
        }
        let s = &dst[..dst.iter().position(|&a| a == 0).unwrap()];
        str::from_utf8(s).unwrap().fmt(f)
    }
}

impl PartialEq for Oid {
    fn eq(&self, other: &Oid) -> bool {
        unsafe { raw::git_oid_equal(&self.raw, &other.raw) != 0 }
    }
}
impl Eq for Oid {}

impl PartialOrd for Oid {
    fn partial_cmp(&self, other: &Oid) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Oid {
    fn cmp(&self, other: &Oid) -> Ordering {
        match unsafe { raw::git_oid_cmp(&self.raw, &other.raw) } {
            0 => Ordering::Equal,
            n if n < 0 => Ordering::Less,
            _ => Ordering::Greater,
        }
    }
}

impl Clone for Oid {
    fn clone(&self) -> Oid { *self }
}

impl Hash for Oid {
    fn hash<H: Hasher>(&self, into: &mut H) {
        self.raw.id.hash(into)
    }
}

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

    #[test]
    fn conversions() {
        assert!(Oid::from_str("foo").is_err());
        assert!(Oid::from_str("decbf2be529ab6557d5429922251e5ee36519817").is_ok());
        assert!(Oid::from_bytes(b"foo").is_err());
        assert!(Oid::from_bytes(b"00000000000000000000").is_ok());
    }
}
<commit_msg>Add `FromStr` implementation for `Oid`<commit_after>use std::fmt;
use std::cmp::Ordering;
use std::hash::{Hasher, Hash};
use std::str;
use libc;

use {raw, Error};
use util::Binding;

/// Unique identity of any object (commit, tree, blob, tag).
#[derive(Copy)]
pub struct Oid {
    raw: raw::git_oid,
}

impl Oid {
    /// Parse a hex-formatted object id into an Oid structure.
    ///
    /// If the string is not a valid 40-character hex string, an error is
    /// returned.
    pub fn from_str(s: &str) -> Result<Oid, Error> {
        ::init();
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        unsafe {
            try_call!(raw::git_oid_fromstrn(&mut raw,
                                            s.as_bytes().as_ptr()
                                                as *const libc::c_char,
                                            s.len() as libc::size_t));
        }
        Ok(Oid { raw: raw })
    }

    /// Parse a raw object id into an Oid structure.
    ///
    /// If the array given is not 20 bytes in length, an error is returned.
    pub fn from_bytes(bytes: &[u8]) -> Result<Oid, Error> {
        ::init();
        let mut raw = raw::git_oid { id: [0; raw::GIT_OID_RAWSZ] };
        if bytes.len() != raw::GIT_OID_RAWSZ {
            Err(Error::from_str("raw byte array must be 20 bytes"))
        } else {
            unsafe { raw::git_oid_fromraw(&mut raw, bytes.as_ptr()) }
            Ok(Oid { raw: raw })
        }
    }

    /// View this OID as a byte-slice 20 bytes in length.
    pub fn as_bytes(&self) -> &[u8] { &self.raw.id }

    /// Test if this OID is all zeros.
    pub fn is_zero(&self) -> bool {
        unsafe { raw::git_oid_iszero(&self.raw) == 1 }
    }
}

impl Binding for Oid {
    type Raw = *const raw::git_oid;

    unsafe fn from_raw(oid: *const raw::git_oid) -> Oid {
        Oid { raw: *oid }
    }
    fn raw(&self) -> *const raw::git_oid { &self.raw as *const _ }
}

impl fmt::Debug for Oid {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl fmt::Display for Oid {
    /// Hex-encode this Oid into a formatter.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut dst = [0u8; raw::GIT_OID_HEXSZ + 1];
        unsafe {
            raw::git_oid_tostr(dst.as_mut_ptr() as *mut libc::c_char,
                               dst.len() as libc::size_t, &self.raw);
        }
        let s = &dst[..dst.iter().position(|&a| a == 0).unwrap()];
        str::from_utf8(s).unwrap().fmt(f)
    }
}

impl str::FromStr for Oid {
    type Err = Error;

    /// Parse a hex-formatted object id into an Oid structure.
    ///
    /// If the string is not a valid 40-character hex string, an error is
    /// returned.
    fn from_str(s: &str) -> Result<Oid, Error> {
        Oid::from_str(s)
    }
}

impl PartialEq for Oid {
    fn eq(&self, other: &Oid) -> bool {
        unsafe { raw::git_oid_equal(&self.raw, &other.raw) != 0 }
    }
}
impl Eq for Oid {}

impl PartialOrd for Oid {
    fn partial_cmp(&self, other: &Oid) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Oid {
    fn cmp(&self, other: &Oid) -> Ordering {
        match unsafe { raw::git_oid_cmp(&self.raw, &other.raw) } {
            0 => Ordering::Equal,
            n if n < 0 => Ordering::Less,
            _ => Ordering::Greater,
        }
    }
}

impl Clone for Oid {
    fn clone(&self) -> Oid { *self }
}

impl Hash for Oid {
    fn hash<H: Hasher>(&self, into: &mut H) {
        self.raw.id.hash(into)
    }
}

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

    #[test]
    fn conversions() {
        assert!(Oid::from_str("foo").is_err());
        assert!(Oid::from_str("decbf2be529ab6557d5429922251e5ee36519817").is_ok());
        assert!(Oid::from_bytes(b"foo").is_err());
        assert!(Oid::from_bytes(b"00000000000000000000").is_ok());
    }
}
<|endoftext|>


<commit_before>use std::io::net::ip::{Ipv4Addr, SocketAddr};

mod libtorresmo {
    extern crate time;

    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::SocketAddr;
    use std::io::IoResult;
    use std::mem::transmute;
    use std::rand::random;
    use std::fmt;

    #[allow(dead_code,non_camel_case_types)]
    enum UtpPacketType {
        ST_DATA  = 0,
        ST_FIN   = 1,
        ST_STATE = 2,
        ST_RESET = 3,
        ST_SYN   = 4,
    }

    impl fmt::Show for UtpPacketType {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let s = match *self {
                ST_DATA  => "ST_DATA",
                ST_FIN   => "ST_FIN",
                ST_STATE => "ST_STATE",
                ST_RESET => "ST_RESET",
                ST_SYN   => "ST_SYN",
            };
            write!(f, "{}", s)
        }
    }

    #[allow(dead_code)]
    #[packed]
    struct UtpPacketHeader {
        type_ver: u8, // type: u4, ver: u4
        extension: u8,
        connection_id: u16,
        timestamp_microseconds: u32,
        timestamp_difference_microseconds: u32,
        wnd_size: u32,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpPacketHeader {
        fn bytes(&self) -> &[u8] {
            unsafe {
                let buf: &[u8, ..20] = transmute(self);
                return buf.as_slice();
            }
        }

        fn len(&self) -> uint {
            static HEADER_SIZE: uint = 20;
            return HEADER_SIZE;
        }
    }

    impl fmt::Show for UtpPacketHeader {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let t: UtpPacketType = unsafe { transmute(self.type_ver >> 4) };
            let ptype = match t {
                ST_DATA  => "ST_DATA",
                ST_FIN   => "ST_FIN",
                ST_STATE => "ST_STATE",
                ST_RESET => "ST_RESET",
                ST_SYN   => "ST_SYN",
            };
            write!(f, "(type: {}, version: {}, extension: {}, connection_id: {}, timestamp_microseconds: {}, timestamp_difference_microseconds: {}, wnd_size: {}, seq_nr: {}, ack_nr: {})", ptype, self.type_ver & 0x0F, self.extension, self.connection_id, self.timestamp_microseconds, self.timestamp_difference_microseconds, self.wnd_size, self.seq_nr, self.ack_nr)
        }
    }

    #[allow(dead_code)]
    struct UtpPacket {
        header: UtpPacketHeader,
        payload: Vec<u8>,
    }

    impl UtpPacket {
        /// Constructs a new, empty UtpPacket.
        fn new() -> UtpPacket {
            UtpPacket {
                header: UtpPacketHeader {
                    type_ver: ST_DATA as u8 << 4 | 1,
                    extension: 0,
                    connection_id: 0,
                    timestamp_microseconds: 0,
                    timestamp_difference_microseconds: 0,
                    wnd_size: 0,
                    seq_nr: 0,
                    ack_nr: 0,
                },
                payload: Vec::new(),
            }
        }

        fn set_type(&mut self, t: UtpPacketType) {
            let version = 0x0F & self.header.type_ver;
            self.header.type_ver = t as u8 << 4 | version;
        }

        fn bytes(&self) -> Vec<u8> {
            let mut buf: Vec<u8> = Vec::with_capacity(self.len());
            buf.push_all(self.header.bytes());
            buf.push_all(self.payload.as_slice());
            return buf;
        }

        fn len(&self) -> uint {
            self.header.len() + self.payload.len()
        }

        fn decode(buf: &[u8]) -> UtpPacket {
            let header: UtpPacketHeader = UtpPacketHeader {
                type_ver: buf[0],
                extension: buf[1],
                connection_id: buf[2] as u16 << 8 | buf[3] as u16,
                timestamp_microseconds: buf[4] as u32 << 24 | buf[5] as u32 << 16 | buf[6] as u32 << 8 | buf[7] as u32,
                timestamp_difference_microseconds: buf[8] as u32 << 24 | buf[9] as u32 << 16 | buf[10] as u32 << 8 | buf[11] as u32,
                wnd_size: buf[12] as u32 << 24 | buf[13] as u32 << 16 | buf[14] as u32 << 8 | buf[15] as u32,
                seq_nr: buf[16] as u16 << 8 | buf[17] as u16,
                ack_nr: buf[18] as u16 << 8 | buf[19] as u16,
            };
            UtpPacket { header: header, payload: Vec::from_slice(buf.slice(20, buf.len())) }
        }
    }

    pub struct UtpSocket {
        socket: UdpSocket,
    }

    impl UtpSocket {
        pub fn bind(addr: SocketAddr) -> IoResult<UtpSocket> {
            let skt = UdpSocket::bind(addr);
            match skt {
                Ok(x)  => Ok(UtpSocket { socket: x }),
                Err(e) => Err(e)
            }
        }

        pub fn connect(self, other: SocketAddr) -> UtpStream {
            let stream = UtpStream::new(self.socket, other);
            stream.connect()
        }

        pub fn recvfrom(&mut self, buf: &mut[u8]) -> IoResult<(uint,SocketAddr)> {
            self.socket.recvfrom(buf)
        }
    }

    impl Clone for UtpSocket {
        fn clone(&self) -> UtpSocket {
            UtpSocket {
                socket: self.socket.clone(),
            }
        }
    }

    #[allow(dead_code)]
    pub struct UtpStream {
        socket: UdpSocket,
        connected_to: SocketAddr,
        connection_id: u16,
        seq_nr: u16,
        ack_nr: u16,
    }

    #[allow(dead_code)]
    impl UtpStream {
        pub fn new(socket: UdpSocket, conn: SocketAddr) -> UtpStream {
            let r: u16 = random();
            UtpStream {
                socket: socket,
                connected_to: conn,
                connection_id: r.to_be(),
                seq_nr: 1,
                ack_nr: 0,
            }
        }

        pub fn connect(mut self) -> UtpStream {
            let mut packet = UtpPacket::new();
            packet.set_type(ST_SYN);
            packet.header.connection_id = self.connection_id;
            packet.header.seq_nr = self.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let _result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;

            self
        }

        pub fn terminate(mut self) -> UtpStream {
            let mut packet = UtpPacket::new();
            packet.set_type(ST_FIN);
            packet.header.connection_id = self.connection_id;
            packet.header.seq_nr = self.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let _result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;

            self
        }

        pub fn disconnect(self) -> UdpSocket {
            self.socket
        }
    }

    impl Reader for UtpStream {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            match self.socket.recvfrom(buf) {
                Ok((_nread, src)) if src != self.connected_to => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e),
            }
        }
    }
    impl Writer for UtpStream {
        fn write(&mut self, buf: &[u8]) -> IoResult<()> {
            let mut packet = UtpPacket::new();
            packet.payload = Vec::from_slice(buf);
            packet.header.connection_id = self.connection_id;
            packet.header.seq_nr = self.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;
            result
        }
    }
}

fn usage() {
    println!("Usage: torresmo [-s|-c] <address> <port>");
}

fn main() {
    use libtorresmo::{UtpSocket, UtpStream};
    use std::from_str::FromStr;

    // Defaults
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

    if args.len() == 4 {
        let ip = FromStr::from_str(args.get(2).as_slice()).unwrap();
        let port = FromStr::from_str(args.get(3).as_slice()).unwrap();
        addr = SocketAddr { ip: ip, port: port };
    }

    match args.get(1).as_slice() {
        "-s" => {
            let mut buf = [0, ..512];
            let sock = UtpSocket::bind(addr).unwrap();
            println!("Serving on {}", addr);

            loop {
                let mut sock = sock.clone();
                match sock.recvfrom(buf) {
                    Ok((_, src)) => {
                        spawn(proc() {
                            let mut stream = sock.connect(src);
                            let payload = String::from_str("Hello\n").into_bytes();

                            // Send uTP packet
                            let _ = stream.write(payload.as_slice());
                        })
                    }
                    Err(_) => {}
                }
            }
        }
        "-c" => {
            let sock = UtpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: std::rand::random() }).unwrap();
            let mut stream = sock.connect(addr);
            let _ = stream.write([0]);
            let stream = stream.terminate();
            drop(stream);
        }
        _ => usage(),
    }
}
<commit_msg>Add getter and setter for packet header type.<commit_after>use std::io::net::ip::{Ipv4Addr, SocketAddr};

mod libtorresmo {
    extern crate time;

    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::SocketAddr;
    use std::io::IoResult;
    use std::mem::transmute;
    use std::rand::random;
    use std::fmt;

    #[allow(dead_code,non_camel_case_types)]
    enum UtpPacketType {
        ST_DATA  = 0,
        ST_FIN   = 1,
        ST_STATE = 2,
        ST_RESET = 3,
        ST_SYN   = 4,
    }

    impl fmt::Show for UtpPacketType {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let s = match *self {
                ST_DATA  => "ST_DATA",
                ST_FIN   => "ST_FIN",
                ST_STATE => "ST_STATE",
                ST_RESET => "ST_RESET",
                ST_SYN   => "ST_SYN",
            };
            write!(f, "{}", s)
        }
    }

    #[allow(dead_code)]
    #[packed]
    struct UtpPacketHeader {
        type_ver: u8, // type: u4, ver: u4
        extension: u8,
        connection_id: u16,
        timestamp_microseconds: u32,
        timestamp_difference_microseconds: u32,
        wnd_size: u32,
        seq_nr: u16,
        ack_nr: u16,
    }

    impl UtpPacketHeader {
        fn set_type(&mut self, t: UtpPacketType) {
            let version = 0x0F & self.type_ver;
            self.type_ver = t as u8 << 4 | version;
        }

        fn get_type(self) -> UtpPacketType {
            let t: UtpPacketType = unsafe { transmute(self.type_ver >> 4) };
            t
        }

        fn bytes(&self) -> &[u8] {
            unsafe {
                let buf: &[u8, ..20] = transmute(self);
                return buf.as_slice();
            }
        }

        fn len(&self) -> uint {
            static HEADER_SIZE: uint = 20;
            return HEADER_SIZE;
        }
    }

    impl fmt::Show for UtpPacketHeader {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            let t: UtpPacketType = self.get_type();
            write!(f, "(type: {}, version: {}, extension: {}, connection_id: {}, timestamp_microseconds: {}, timestamp_difference_microseconds: {}, wnd_size: {}, seq_nr: {}, ack_nr: {})", t, self.type_ver & 0x0F, self.extension, self.connection_id, self.timestamp_microseconds, self.timestamp_difference_microseconds, self.wnd_size, self.seq_nr, self.ack_nr)
        }
    }

    #[allow(dead_code)]
    struct UtpPacket {
        header: UtpPacketHeader,
        payload: Vec<u8>,
    }

    impl UtpPacket {
        /// Constructs a new, empty UtpPacket.
        fn new() -> UtpPacket {
            UtpPacket {
                header: UtpPacketHeader {
                    type_ver: ST_DATA as u8 << 4 | 1,
                    extension: 0,
                    connection_id: 0,
                    timestamp_microseconds: 0,
                    timestamp_difference_microseconds: 0,
                    wnd_size: 0,
                    seq_nr: 0,
                    ack_nr: 0,
                },
                payload: Vec::new(),
            }
        }

        fn set_type(&mut self, t: UtpPacketType) {
            self.header.set_type(t);
        }

        fn get_type(self) -> UtpPacketType {
            self.header.get_type()
        }

        fn bytes(&self) -> Vec<u8> {
            let mut buf: Vec<u8> = Vec::with_capacity(self.len());
            buf.push_all(self.header.bytes());
            buf.push_all(self.payload.as_slice());
            return buf;
        }

        fn len(&self) -> uint {
            self.header.len() + self.payload.len()
        }

        fn decode(buf: &[u8]) -> UtpPacket {
            let header: UtpPacketHeader = UtpPacketHeader {
                type_ver: buf[0],
                extension: buf[1],
                connection_id: buf[2] as u16 << 8 | buf[3] as u16,
                timestamp_microseconds: buf[4] as u32 << 24 | buf[5] as u32 << 16 | buf[6] as u32 << 8 | buf[7] as u32,
                timestamp_difference_microseconds: buf[8] as u32 << 24 | buf[9] as u32 << 16 | buf[10] as u32 << 8 | buf[11] as u32,
                wnd_size: buf[12] as u32 << 24 | buf[13] as u32 << 16 | buf[14] as u32 << 8 | buf[15] as u32,
                seq_nr: buf[16] as u16 << 8 | buf[17] as u16,
                ack_nr: buf[18] as u16 << 8 | buf[19] as u16,
            };
            UtpPacket { header: header, payload: Vec::from_slice(buf.slice(20, buf.len())) }
        }
    }

    pub struct UtpSocket {
        socket: UdpSocket,
    }

    impl UtpSocket {
        pub fn bind(addr: SocketAddr) -> IoResult<UtpSocket> {
            let skt = UdpSocket::bind(addr);
            match skt {
                Ok(x)  => Ok(UtpSocket { socket: x }),
                Err(e) => Err(e)
            }
        }

        pub fn connect(self, other: SocketAddr) -> UtpStream {
            let stream = UtpStream::new(self.socket, other);
            stream.connect()
        }

        pub fn recvfrom(&mut self, buf: &mut[u8]) -> IoResult<(uint,SocketAddr)> {
            self.socket.recvfrom(buf)
        }
    }

    impl Clone for UtpSocket {
        fn clone(&self) -> UtpSocket {
            UtpSocket {
                socket: self.socket.clone(),
            }
        }
    }

    #[allow(dead_code)]
    pub struct UtpStream {
        socket: UdpSocket,
        connected_to: SocketAddr,
        connection_id: u16,
        seq_nr: u16,
        ack_nr: u16,
    }

    #[allow(dead_code)]
    impl UtpStream {
        pub fn new(socket: UdpSocket, conn: SocketAddr) -> UtpStream {
            let r: u16 = random();
            UtpStream {
                socket: socket,
                connected_to: conn,
                connection_id: r.to_be(),
                seq_nr: 1,
                ack_nr: 0,
            }
        }

        pub fn connect(mut self) -> UtpStream {
            let mut packet = UtpPacket::new();
            packet.set_type(ST_SYN);
            packet.header.connection_id = self.connection_id;
            packet.header.seq_nr = self.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let _result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;

            self
        }

        pub fn terminate(mut self) -> UtpStream {
            let mut packet = UtpPacket::new();
            packet.set_type(ST_FIN);
            packet.header.connection_id = self.connection_id;
            packet.header.seq_nr = self.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let _result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;

            self
        }

        pub fn disconnect(self) -> UdpSocket {
            self.socket
        }
    }

    impl Reader for UtpStream {
        fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
            match self.socket.recvfrom(buf) {
                Ok((_nread, src)) if src != self.connected_to => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e),
            }
        }
    }
    impl Writer for UtpStream {
        fn write(&mut self, buf: &[u8]) -> IoResult<()> {
            let mut packet = UtpPacket::new();
            packet.payload = Vec::from_slice(buf);
            packet.header.connection_id = self.connection_id;
            packet.header.seq_nr = self.seq_nr.to_be();
            let t = time::get_time();
            packet.header.timestamp_microseconds = ((t.sec * 1_000_000) as u32 + (t.nsec/1000) as u32).to_be();

            // Send packet
            let result = self.socket.sendto(packet.bytes().as_slice(), self.connected_to);

            self.seq_nr += 1;
            result
        }
    }
}

fn usage() {
    println!("Usage: torresmo [-s|-c] <address> <port>");
}

fn main() {
    use libtorresmo::{UtpSocket, UtpStream};
    use std::from_str::FromStr;

    // Defaults
    let mut addr = SocketAddr { ip: Ipv4Addr(127,0,0,1), port: 8080 };

    let args = std::os::args();

    if args.len() == 4 {
        let ip = FromStr::from_str(args.get(2).as_slice()).unwrap();
        let port = FromStr::from_str(args.get(3).as_slice()).unwrap();
        addr = SocketAddr { ip: ip, port: port };
    }

    match args.get(1).as_slice() {
        "-s" => {
            let mut buf = [0, ..512];
            let sock = UtpSocket::bind(addr).unwrap();
            println!("Serving on {}", addr);

            loop {
                let mut sock = sock.clone();
                match sock.recvfrom(buf) {
                    Ok((_, src)) => {
                        spawn(proc() {
                            let mut stream = sock.connect(src);
                            let payload = String::from_str("Hello\n").into_bytes();

                            // Send uTP packet
                            let _ = stream.write(payload.as_slice());
                        })
                    }
                    Err(_) => {}
                }
            }
        }
        "-c" => {
            let sock = UtpSocket::bind(SocketAddr { ip: Ipv4Addr(127,0,0,1), port: std::rand::random() }).unwrap();
            let mut stream = sock.connect(addr);
            let _ = stream.write([0]);
            let stream = stream.terminate();
            drop(stream);
        }
        _ => usage(),
    }
}
<|endoftext|>


<commit_before>use error::Error;
use edit::{EditCtx, EditResult, edit};
use builder::Builder;
use parser::{parse_cursor_pos, ParseError, ParseSuccess};

pub trait RunIO {

    fn write(&mut self, Vec<u8>) -> Result<(), Error>;
    fn read_byte(&mut self) -> Result<u8, Error>;
    fn read_seq(&mut self) -> Result<Vec<u8>, Error>;

    fn prompt(&mut self, w: Vec<u8>) -> Result<Vec<u8>, Error> {
        try!(self.write(w));
        self.read_seq()
    }

}

fn query_cursor_pos(io: &mut RunIO) -> Result<(u64, u64), Error> {
    let mut line = Builder::new();
    line.ask_cursor_pos();
    try!(io.write(line.build()));
    let mut seq = vec![];
    loop {
        match parse_cursor_pos(&seq) {
            Ok(ParseSuccess(pos, _)) => {
                return Ok(pos);
            },
            Err(ParseError::Error(_)) => {
                return Err(Error::ParseError);
            },
            Err(ParseError::Incomplete) => {
                let byte = try!(io.read_byte());
                seq.push(byte);
            }
        }
    }
}

fn protect_newline(io: &mut RunIO) -> Result<(), Error> {
    let (x, _) = try!(query_cursor_pos(io));
    if x > 1 {
        let mut line = Builder::new();
        line.invert_color();
        line.append("%\n");
        line.reset_color();
        try!(io.write(line.build()));
    }
    Ok(())
}

fn run_edit<'a>(mut ctx: EditCtx<'a>, io: &mut RunIO) -> Result<String, Error> {
    loop {
        match edit(&mut ctx) {
            EditResult::Cont(line) => {
                let bytes = try!(io.prompt(line));
                for byte in bytes.iter() {
                    ctx.fill(*byte);
                }
            },
            EditResult::Halt(res) => { return res; }
        }
    }
}

pub fn run<'a>(ctx: EditCtx<'a>, io: &mut RunIO) -> Result<String, Error> {
    try!(protect_newline(io));
    run_edit(ctx, io)
}

#[cfg(test)]
mod test {
    use encoding::all::ASCII;
    use super::super::error::Error;
    use super::super::edit::EditCtx;
    use super::super::history::History;
    use super::{RunIO, run_edit};
    use edit::EditMode;

    pub struct TestIO {
        input: Vec<u8>,
        output: Vec<u8>
    }

    impl RunIO for TestIO {
        fn write(&mut self, w: Vec<u8>) -> Result<(), Error> {
            self.output.extend(w);
            Ok(())
        }
        fn read_byte(&mut self) -> Result<u8, Error> {
            if self.input.len() > 0 {
                Ok(self.input.remove(0))
            } else {
                Err(Error::EndOfFile)
            }
        }
    }

    #[test]
    fn error_eof_on_empty_input() {
        let mut io = TestIO { input: vec![], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Err(Error::EndOfFile));
    }

    #[test]
    fn ok_empty_after_return() {
        let mut io = TestIO { input: vec![13], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Ok("".to_string()));
    }

    #[test]
    fn ok_ascii_after_return() {
        let mut io = TestIO { input: vec![65, 66, 67, 13], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Ok("ABC".to_string()));
    }

}
<commit_msg>edit: fix test for multi byte reads<commit_after>use error::Error;
use edit::{EditCtx, EditResult, edit};
use builder::Builder;
use parser::{parse_cursor_pos, ParseError, ParseSuccess};

pub trait RunIO {

    fn write(&mut self, Vec<u8>) -> Result<(), Error>;
    fn read_byte(&mut self) -> Result<u8, Error>;
    fn read_seq(&mut self) -> Result<Vec<u8>, Error>;

    fn prompt(&mut self, w: Vec<u8>) -> Result<Vec<u8>, Error> {
        try!(self.write(w));
        self.read_seq()
    }

}

fn query_cursor_pos(io: &mut RunIO) -> Result<(u64, u64), Error> {
    let mut line = Builder::new();
    line.ask_cursor_pos();
    try!(io.write(line.build()));
    let mut seq = vec![];
    loop {
        match parse_cursor_pos(&seq) {
            Ok(ParseSuccess(pos, _)) => {
                return Ok(pos);
            },
            Err(ParseError::Error(_)) => {
                return Err(Error::ParseError);
            },
            Err(ParseError::Incomplete) => {
                let byte = try!(io.read_byte());
                seq.push(byte);
            }
        }
    }
}

fn protect_newline(io: &mut RunIO) -> Result<(), Error> {
    let (x, _) = try!(query_cursor_pos(io));
    if x > 1 {
        let mut line = Builder::new();
        line.invert_color();
        line.append("%\n");
        line.reset_color();
        try!(io.write(line.build()));
    }
    Ok(())
}

fn run_edit<'a>(mut ctx: EditCtx<'a>, io: &mut RunIO) -> Result<String, Error> {
    loop {
        match edit(&mut ctx) {
            EditResult::Cont(line) => {
                let bytes = try!(io.prompt(line));
                for byte in bytes.iter() {
                    ctx.fill(*byte);
                }
            },
            EditResult::Halt(res) => { return res; }
        }
    }
}

pub fn run<'a>(ctx: EditCtx<'a>, io: &mut RunIO) -> Result<String, Error> {
    try!(protect_newline(io));
    run_edit(ctx, io)
}

#[cfg(test)]
mod test {
    use encoding::all::ASCII;
    use super::super::error::Error;
    use super::super::edit::EditCtx;
    use super::super::history::History;
    use super::{RunIO, run_edit};
    use edit::EditMode;

    pub struct TestIO {
        input: Vec<u8>,
        output: Vec<u8>
    }

    impl RunIO for TestIO {
        fn write(&mut self, w: Vec<u8>) -> Result<(), Error> {
            self.output.extend(w);
            Ok(())
        }
        fn read_byte(&mut self) -> Result<u8, Error> {
            if self.input.len() > 0 {
                Ok(self.input.remove(0))
            } else {
                Err(Error::EndOfFile)
            }
        }

        fn read_seq(&mut self) -> Result<Vec<u8>, Error> {
            // XXX return more than one byte
            if self.input.len() > 0 {
                Ok(vec![self.input.remove(0)])
            } else {
                Err(Error::EndOfFile)
            }
        }
    }

    #[test]
    fn error_eof_on_empty_input() {
        let mut io = TestIO { input: vec![], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Err(Error::EndOfFile));
    }

    #[test]
    fn ok_empty_after_return() {
        let mut io = TestIO { input: vec![13], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Ok("".to_string()));
    }

    #[test]
    fn ok_ascii_after_return() {
        let mut io = TestIO { input: vec![65, 66, 67, 13], output: vec![] };
        let h = History::new();
        let ctx = EditCtx::new("foo> ", &h, ASCII, EditMode::Emacs);
        assert_eq!(run_edit(ctx, &mut io), Ok("ABC".to_string()));
    }

}
<|endoftext|>


<commit_before>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

#[link(name = "sax",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/sax-rs")];

#[comment = "Wrapper for libxml2's SAX parser."];
#[crate_type = "lib"];

extern mod extra;

use std::cast;
use std::comm::{Port, stream};
use std::libc::{c_char, c_int};
use std::str;
// use std::task;

use error::ErrorData;

pub mod error;
pub mod ffi;
mod extfn;

/// Events to be sent by the parser.
#[deriving(Eq, Clone)]
pub enum ParseEvent {
    /// The document has begun to be processed.
    StartDocument,
    /// The document processing has finished.
    EndDocument,
    /// An opening tag has was parsed.
    StartElement(~str, Attributes),
    /// A closing tag was parsed.
    EndElement(~str),
    /// Some characters between tags have been recived.
    Characters(~str),
    /// A comment tag was parsed.
    Comment(~str),
    /// A `CDATA` block was parsed.
    CdataBlock(~str),
}

impl ToStr for ParseEvent {
    fn to_str(&self) -> ~str {
        match *self {
            StartDocument => ~"START DOCUMENT",
            EndDocument => ~"END DOCUMENT",
            StartElement(ref name, ref atts) => fmt!("<%s%s>", *name, atts.to_str()),
            EndElement(ref name) => fmt!("</%s>", *name),
            Characters(ref ch) => ch.clone(),
            Comment(ref value) => fmt!("", *value),
            CdataBlock(ref value) => fmt!("<![CDATA[%s]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attribute {
    name: ~str,
    value: ~str,
}

/// A list of attributes
#[deriving(Eq, Clone)]
pub struct Attributes(~[Attribute]);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut ret = Attributes(~[]);
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            ret.push(
                Attribute {
                    name: str::raw::from_c_str(*ptr),
                    value: str::raw::from_c_str(*(ptr + 1)),
                }
            );
            ptr = ptr + 2;
        }
        ret
    }

    pub fn find<'a>(&'a self, name: &str) -> Option<&'a str> {
        self.iter()
            .find(|att| name == att.name)
            .map(|att| att.value.as_slice())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.find(name).expect(fmt!("Could not find an attribute with the name \"%s\"", name))
    }

    pub fn find_clone(&self, name: &str) -> Option<~str> {
        self.find(name).map(|v| v.to_owned())
    }

    pub fn get_clone(&self, name: &str) -> ~str {
        self.get(name).to_owned()
    }
}

impl ToStr for Attributes {
    fn to_str(&self) -> ~str {
        do self.iter().map |att| {
            fmt!(" %s=\"%s\"", att.name, att.value)
        }.to_owned_vec().concat()
    }
}

/// Either a parse event wrapped in `Ok` or some Error data wrapped in `Err`.
pub type ParseResult = Result<ParseEvent, ErrorData>;

/// A port to recieve `ParseResult`s from the parser.
pub struct SaxPort {
    priv port: Port<ParseResult>,
}

impl GenericPort<ParseResult> for SaxPort {
    /// Recives a new parse message.
    ///
    /// # Failure
    ///
    /// Fails if the method is called again after the final `Ok(EndDocument)`
    /// parse result has been recived.
    fn recv(&self) -> ParseResult {
        self.port.try_recv().expect(
            "Could not get a new parse result, the parser has already finished!"
        )
    }

    /// Receives a parse result wrapped in `Some`, or `None` if the parser has
    /// finished.
    fn try_recv(&self) -> Option<ParseResult> {
        self.port.try_recv()
    }
}

/// Parses the entire XML string.
///
/// # Returns
///
/// A port that recieves parse results.
///
/// # Example
///
/// ~~~rust
/// let port = parse_xml("<hullo><world /></hullo>");
/// loop {
///     if port.recv() == Ok(EndDocument) { break }
/// }
/// ~~~
#[fixed_stack_segment]
#[inline(never)]
pub fn parse_xml(src: &str) -> SaxPort {
    let len = src.len() as c_int;
    do src.to_c_str().with_ref |c_str| {
        let (port, chan) = stream();
        // do task::spawn {
            unsafe {
                ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                           cast::transmute(&chan),
                                           c_str, len);
                ffi::xmlCleanupParser();
            }
        // }
        SaxPort { port: port }
    }
}

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

    fn get_mock_atts() -> Attributes {
        Attributes(~[
            Attribute { name: ~"foo", value: ~"0" },
            Attribute { name: ~"bar", value: ~"1" },
            Attribute { name: ~"baz", value: ~"2" }
        ])
    }

    #[test]
    fn test_att_get() {
        let atts = get_mock_atts();
        assert_eq!(atts.get("foo"), "0");
        assert_eq!(atts.get("bar"), "1");
        assert_eq!(atts.get("baz"), "2");
    }

    #[test]
    fn test_att_find() {
        let atts = get_mock_atts();
        assert_eq!(atts.find("foo"), Some("0"));
        assert_eq!(atts.find("bar"), Some("1"));
        assert_eq!(atts.find("baz"), Some("2"));
    }

    #[test]
    fn test() {
        let sax = parse_xml(
            "<hello><this />test</hello>"
        );
        loop {
            match sax.recv() {
                Ok(StartDocument) => (),
                Ok(EndDocument) => break,
                Ok(event) => println(event.to_str()),
                Err(err) => println(err.to_str()),
            }
        }
    }
}
<commit_msg>Use ptr::offset<commit_after>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

#[link(name = "sax",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/sax-rs")];

#[comment = "Wrapper for libxml2's SAX parser."];
#[crate_type = "lib"];

extern mod extra;

use std::cast;
use std::comm::{Port, stream};
use std::libc::{c_char, c_int};
use std::str;
// use std::task;

use error::ErrorData;

pub mod error;
pub mod ffi;
mod extfn;

/// Events to be sent by the parser.
#[deriving(Eq, Clone)]
pub enum ParseEvent {
    /// The document has begun to be processed.
    StartDocument,
    /// The document processing has finished.
    EndDocument,
    /// An opening tag has was parsed.
    StartElement(~str, Attributes),
    /// A closing tag was parsed.
    EndElement(~str),
    /// Some characters between tags have been recived.
    Characters(~str),
    /// A comment tag was parsed.
    Comment(~str),
    /// A `CDATA` block was parsed.
    CdataBlock(~str),
}

impl ToStr for ParseEvent {
    fn to_str(&self) -> ~str {
        match *self {
            StartDocument => ~"START DOCUMENT",
            EndDocument => ~"END DOCUMENT",
            StartElement(ref name, ref atts) => fmt!("<%s%s>", *name, atts.to_str()),
            EndElement(ref name) => fmt!("</%s>", *name),
            Characters(ref ch) => ch.clone(),
            Comment(ref value) => fmt!("", *value),
            CdataBlock(ref value) => fmt!("<![CDATA[%s]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attribute {
    name: ~str,
    value: ~str,
}

/// A list of attributes
#[deriving(Eq, Clone)]
pub struct Attributes(~[Attribute]);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut ret = Attributes(~[]);
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            ret.push(
                Attribute {
                    name: str::raw::from_c_str(*ptr),
                    value: str::raw::from_c_str(*ptr.offset(1)),
                }
            );
            ptr = ptr.offset(2);
        }
        ret
    }

    pub fn find<'a>(&'a self, name: &str) -> Option<&'a str> {
        self.iter()
            .find(|att| name == att.name)
            .map(|att| att.value.as_slice())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.find(name).expect(fmt!("Could not find an attribute with the name \"%s\"", name))
    }

    pub fn find_clone(&self, name: &str) -> Option<~str> {
        self.find(name).map(|v| v.to_owned())
    }

    pub fn get_clone(&self, name: &str) -> ~str {
        self.get(name).to_owned()
    }
}

impl ToStr for Attributes {
    fn to_str(&self) -> ~str {
        do self.iter().map |att| {
            fmt!(" %s=\"%s\"", att.name, att.value)
        }.to_owned_vec().concat()
    }
}

/// Either a parse event wrapped in `Ok` or some Error data wrapped in `Err`.
pub type ParseResult = Result<ParseEvent, ErrorData>;

/// A port to recieve `ParseResult`s from the parser.
pub struct SaxPort {
    priv port: Port<ParseResult>,
}

impl GenericPort<ParseResult> for SaxPort {
    /// Recives a new parse message.
    ///
    /// # Failure
    ///
    /// Fails if the method is called again after the final `Ok(EndDocument)`
    /// parse result has been recived.
    fn recv(&self) -> ParseResult {
        self.port.try_recv().expect(
            "Could not get a new parse result, the parser has already finished!"
        )
    }

    /// Receives a parse result wrapped in `Some`, or `None` if the parser has
    /// finished.
    fn try_recv(&self) -> Option<ParseResult> {
        self.port.try_recv()
    }
}

/// Parses the entire XML string.
///
/// # Returns
///
/// A port that recieves parse results.
///
/// # Example
///
/// ~~~rust
/// let port = parse_xml("<hullo><world /></hullo>");
/// loop {
///     if port.recv() == Ok(EndDocument) { break }
/// }
/// ~~~
#[fixed_stack_segment]
#[inline(never)]
pub fn parse_xml(src: &str) -> SaxPort {
    let len = src.len() as c_int;
    do src.to_c_str().with_ref |c_str| {
        let (port, chan) = stream();
        // do task::spawn {
            unsafe {
                ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                           cast::transmute(&chan),
                                           c_str, len);
                ffi::xmlCleanupParser();
            }
        // }
        SaxPort { port: port }
    }
}

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

    fn get_mock_atts() -> Attributes {
        Attributes(~[
            Attribute { name: ~"foo", value: ~"0" },
            Attribute { name: ~"bar", value: ~"1" },
            Attribute { name: ~"baz", value: ~"2" }
        ])
    }

    #[test]
    fn test_att_get() {
        let atts = get_mock_atts();
        assert_eq!(atts.get("foo"), "0");
        assert_eq!(atts.get("bar"), "1");
        assert_eq!(atts.get("baz"), "2");
    }

    #[test]
    fn test_att_find() {
        let atts = get_mock_atts();
        assert_eq!(atts.find("foo"), Some("0"));
        assert_eq!(atts.find("bar"), Some("1"));
        assert_eq!(atts.find("baz"), Some("2"));
    }

    #[test]
    fn test() {
        let sax = parse_xml(
            "<hello><this />test</hello>"
        );
        loop {
            match sax.recv() {
                Ok(StartDocument) => (),
                Ok(EndDocument) => break,
                Ok(event) => println(event.to_str()),
                Err(err) => println(err.to_str()),
            }
        }
    }
}
<|endoftext|>


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

//! Windows console handling

// FIXME (#13400): this is only a tiny fraction of the Windows console api

use crate::color;
use crate::Attr;
use crate::Error;
use crate::Result;
use crate::Terminal;
use std::io;
use std::io::prelude::*;
use std::ops::Deref;
use std::ptr;

use winapi::shared::minwindef::{DWORD, WORD};
use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
use winapi::um::fileapi::{CreateFileA, OPEN_EXISTING};
use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
use winapi::um::wincon::FillConsoleOutputAttribute;
use winapi::um::wincon::{
    FillConsoleOutputCharacterW, GetConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO, COORD,
};
use winapi::um::wincon::{SetConsoleCursorPosition, SetConsoleTextAttribute};
use winapi::um::wincon::{BACKGROUND_INTENSITY, ENABLE_VIRTUAL_TERMINAL_PROCESSING};
use winapi::um::winnt::{FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE};

/// Console info which can be used by a Terminal implementation
/// which uses the Win32 Console API.
pub struct WinConsoleInfo {
    def_foreground: color::Color,
    def_background: color::Color,
    foreground: color::Color,
    background: color::Color,
    reverse: bool,
    secure: bool,
    standout: bool,
}

/// A Terminal implementation which uses the Win32 Console API.
pub struct WinConsole<T> {
    buf: T,
    info: WinConsoleInfo,
}

fn color_to_bits(color: color::Color) -> u16 {
    // magic numbers from mingw-w64's wincon.h

    let bits = match color % 8 {
        color::BLACK => 0,
        color::BLUE => 0x1,
        color::GREEN => 0x2,
        color::RED => 0x4,
        color::YELLOW => 0x2 | 0x4,
        color::MAGENTA => 0x1 | 0x4,
        color::CYAN => 0x1 | 0x2,
        color::WHITE => 0x1 | 0x2 | 0x4,
        _ => unreachable!(),
    };

    if color >= 8 {
        bits | 0x8
    } else {
        bits
    }
}

fn bits_to_color(bits: u16) -> color::Color {
    let color = match bits & 0x7 {
        0 => color::BLACK,
        0x1 => color::BLUE,
        0x2 => color::GREEN,
        0x4 => color::RED,
        0x6 => color::YELLOW,
        0x5 => color::MAGENTA,
        0x3 => color::CYAN,
        0x7 => color::WHITE,
        _ => unreachable!(),
    };

    color | (bits as u32 & 0x8) // copy the hi-intensity bit
}

struct HandleWrapper {
    inner: HANDLE,
}

impl HandleWrapper {
    fn new(h: HANDLE) -> HandleWrapper {
        HandleWrapper { inner: h }
    }
}

impl Drop for HandleWrapper {
    fn drop(&mut self) {
        if self.inner != INVALID_HANDLE_VALUE {
            unsafe {
                CloseHandle(self.inner);
            }
        }
    }
}

impl Deref for HandleWrapper {
    type Target = HANDLE;
    fn deref(&self) -> &HANDLE {
        &self.inner
    }
}

/// Just get a handle to the current console buffer whatever it is
fn conout() -> io::Result<HandleWrapper> {
    let name = b"CONOUT$\0";
    let handle = unsafe {
        CreateFileA(
            name.as_ptr() as *const i8,
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_WRITE,
            ptr::null_mut(),
            OPEN_EXISTING,
            0,
            ptr::null_mut(),
        )
    };
    if handle == INVALID_HANDLE_VALUE {
        Err(io::Error::last_os_error())
    } else {
        Ok(HandleWrapper::new(handle))
    }
}

unsafe fn set_flag(handle: HANDLE, flag: DWORD) -> io::Result<()> {
    let mut curr_mode: DWORD = 0;
    if GetConsoleMode(handle, &mut curr_mode) == 0 {
        return Err(io::Error::last_os_error());
    }

    if SetConsoleMode(handle, curr_mode | flag) == 0 {
        return Err(io::Error::last_os_error());
    }
    return Ok(());
}

/// Check if console supports ansi codes (should succeed on Windows 10)
pub fn supports_ansi() -> bool {
    conout()
        .and_then(|handle| unsafe { set_flag(*handle, ENABLE_VIRTUAL_TERMINAL_PROCESSING) })
        .is_ok()
}

// This test will only pass if it is running in an actual console, probably
#[test]
fn test_conout() {
    assert!(conout().is_ok())
}

#[rustversion::before(1.36)]
unsafe fn get_console_screen_buffer_info(handle: HANDLE) -> io::Result<CONSOLE_SCREEN_BUFFER_INFO> {
    let mut buffer_info = ::std::mem::uninitialized();
    if GetConsoleScreenBufferInfo(handle, &mut buffer_info) == 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(buffer_info)
    }
}
#[rustversion::since(1.36)]
unsafe fn get_console_screen_buffer_info(handle: HANDLE) -> io::Result<CONSOLE_SCREEN_BUFFER_INFO> {
    let mut buffer_info = ::std::mem::MaybeUninit::uninit();
    if GetConsoleScreenBufferInfo(handle, buffer_info.as_mut_ptr()) == 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(buffer_info.assume_init())
    }
}

impl WinConsoleInfo {
    /// Returns `Err` whenever console info cannot be retrieved for some
    /// reason.
    pub fn from_env() -> io::Result<WinConsoleInfo> {
        let fg;
        let bg;
        let handle = conout()?;
        unsafe {
            let buffer_info = get_console_screen_buffer_info(*handle)?;
            fg = bits_to_color(buffer_info.wAttributes);
            bg = bits_to_color(buffer_info.wAttributes >> 4);
        }
        Ok(WinConsoleInfo {
            def_foreground: fg,
            def_background: bg,
            foreground: fg,
            background: bg,
            reverse: false,
            secure: false,
            standout: false,
        })
    }
}

impl<T: Write + Send> WinConsole<T> {
    fn apply(&mut self) -> io::Result<()> {
        let out = conout()?;
        let _unused = self.buf.flush();

        let (mut fg, bg) = if self.info.reverse {
            (self.info.background, self.info.foreground)
        } else {
            (self.info.foreground, self.info.background)
        };

        if self.info.secure {
            fg = bg;
        }

        let mut accum: WORD = 0;

        accum |= color_to_bits(fg);
        accum |= color_to_bits(bg) << 4;

        if self.info.standout {
            accum |= BACKGROUND_INTENSITY;
        } else {
            accum &= BACKGROUND_INTENSITY ^ 0xFF;
        }

        unsafe {
            SetConsoleTextAttribute(*out, accum);
        }
        Ok(())
    }

    /// Create a new WinConsole with the given WinConsoleInfo and out
    pub fn new_with_consoleinfo(out: T, info: WinConsoleInfo) -> WinConsole<T> {
        WinConsole { buf: out, info }
    }

    /// Returns `Err` whenever the terminal cannot be created for some
    /// reason.
    pub fn new(out: T) -> io::Result<WinConsole<T>> {
        let info = WinConsoleInfo::from_env()?;
        Ok(Self::new_with_consoleinfo(out, info))
    }
}

impl<T: Write> Write for WinConsole<T> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.buf.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buf.flush()
    }
}

impl<T: Write + Send> Terminal for WinConsole<T> {
    type Output = T;

    fn fg(&mut self, color: color::Color) -> Result<()> {
        self.info.foreground = color;
        self.apply()?;

        Ok(())
    }

    fn bg(&mut self, color: color::Color) -> Result<()> {
        self.info.background = color;
        self.apply()?;

        Ok(())
    }

    fn attr(&mut self, attr: Attr) -> Result<()> {
        match attr {
            Attr::ForegroundColor(f) => {
                self.info.foreground = f;
                self.apply()?;
                Ok(())
            }
            Attr::BackgroundColor(b) => {
                self.info.background = b;
                self.apply()?;
                Ok(())
            }
            Attr::Reverse => {
                self.info.reverse = true;
                self.apply()?;
                Ok(())
            }
            Attr::Secure => {
                self.info.secure = true;
                self.apply()?;
                Ok(())
            }
            Attr::Standout(v) => {
                self.info.standout = v;
                self.apply()?;
                Ok(())
            }
            _ => Err(Error::NotSupported),
        }
    }

    fn supports_attr(&self, attr: Attr) -> bool {
        match attr {
            Attr::ForegroundColor(_)
            | Attr::BackgroundColor(_)
            | Attr::Standout(_)
            | Attr::Reverse
            | Attr::Secure => true,
            _ => false,
        }
    }

    fn reset(&mut self) -> Result<()> {
        self.info.foreground = self.info.def_foreground;
        self.info.background = self.info.def_background;
        self.info.reverse = false;
        self.info.secure = false;
        self.info.standout = false;
        self.apply()?;

        Ok(())
    }

    fn supports_reset(&self) -> bool {
        true
    }

    fn supports_color(&self) -> bool {
        true
    }

    fn cursor_up(&mut self) -> Result<()> {
        let _unused = self.buf.flush();
        let handle = conout()?;
        unsafe {
            let buffer_info = get_console_screen_buffer_info(*handle)?;
            let (x, y) = (
                buffer_info.dwCursorPosition.X,
                buffer_info.dwCursorPosition.Y,
            );
            if y == 0 {
                // Even though this might want to be a CursorPositionInvalid, on Unix there
                // is no checking to see if the cursor is already on the first line.
                // I'm not sure what the ideal behavior is, but I think it'd be silly to have
                // cursor_up fail in this case.
                Ok(())
            } else {
                let pos = COORD { X: x, Y: y - 1 };
                if SetConsoleCursorPosition(*handle, pos) != 0 {
                    Ok(())
                } else {
                    Err(io::Error::last_os_error().into())
                }
            }
        }
    }

    fn delete_line(&mut self) -> Result<()> {
        let _unused = self.buf.flush();
        let handle = conout()?;
        unsafe {
            let buffer_info = get_console_screen_buffer_info(*handle)?;
            let pos = buffer_info.dwCursorPosition;
            let size = buffer_info.dwSize;
            let num = (size.X - pos.X) as DWORD;
            let mut written = 0;
            // 0x0020u16 is ' ' (space) in UTF-16 (same as ascii)
            if FillConsoleOutputCharacterW(*handle, 0x0020, num, pos, &mut written) == 0 {
                return Err(io::Error::last_os_error().into());
            }
            if FillConsoleOutputAttribute(*handle, 0, num, pos, &mut written) == 0 {
                return Err(io::Error::last_os_error().into());
            }
            // Similar reasoning for not failing as in cursor_up -- it doesn't even make
            // sense to
            // me that these APIs could have written 0, unless the terminal is width zero.
            Ok(())
        }
    }

    fn carriage_return(&mut self) -> Result<()> {
        let _unused = self.buf.flush();
        let handle = conout()?;
        unsafe {
            let buffer_info = get_console_screen_buffer_info(*handle)?;
            let COORD { X: x, Y: y } = buffer_info.dwCursorPosition;
            if x == 0 {
                Err(Error::CursorDestinationInvalid)
            } else {
                let pos = COORD { X: 0, Y: y };
                if SetConsoleCursorPosition(*handle, pos) != 0 {
                    Ok(())
                } else {
                    Err(io::Error::last_os_error().into())
                }
            }
        }
    }

    fn get_ref<'a>(&'a self) -> &'a T {
        &self.buf
    }

    fn get_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.buf
    }

    fn into_inner(self) -> T
    where
        Self: Sized,
    {
        self.buf
    }
}
<commit_msg>Add test for get_console_screen_buffer_info()<commit_after>// Copyright 2013-2019 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Windows console handling

// FIXME (#13400): this is only a tiny fraction of the Windows console api

use crate::color;
use crate::Attr;
use crate::Error;
use crate::Result;
use crate::Terminal;
use std::io;
use std::io::prelude::*;
use std::ops::Deref;
use std::ptr;

use winapi::shared::minwindef::{DWORD, WORD};
use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode};
use winapi::um::fileapi::{CreateFileA, OPEN_EXISTING};
use winapi::um::handleapi::{CloseHandle, INVALID_HANDLE_VALUE};
use winapi::um::wincon::FillConsoleOutputAttribute;
use winapi::um::wincon::{
    FillConsoleOutputCharacterW, GetConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO, COORD,
};
use winapi::um::wincon::{SetConsoleCursorPosition, SetConsoleTextAttribute};
use winapi::um::wincon::{BACKGROUND_INTENSITY, ENABLE_VIRTUAL_TERMINAL_PROCESSING};
use winapi::um::winnt::{FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE};

/// Console info which can be used by a Terminal implementation
/// which uses the Win32 Console API.
pub struct WinConsoleInfo {
    def_foreground: color::Color,
    def_background: color::Color,
    foreground: color::Color,
    background: color::Color,
    reverse: bool,
    secure: bool,
    standout: bool,
}

/// A Terminal implementation which uses the Win32 Console API.
pub struct WinConsole<T> {
    buf: T,
    info: WinConsoleInfo,
}

fn color_to_bits(color: color::Color) -> u16 {
    // magic numbers from mingw-w64's wincon.h

    let bits = match color % 8 {
        color::BLACK => 0,
        color::BLUE => 0x1,
        color::GREEN => 0x2,
        color::RED => 0x4,
        color::YELLOW => 0x2 | 0x4,
        color::MAGENTA => 0x1 | 0x4,
        color::CYAN => 0x1 | 0x2,
        color::WHITE => 0x1 | 0x2 | 0x4,
        _ => unreachable!(),
    };

    if color >= 8 {
        bits | 0x8
    } else {
        bits
    }
}

fn bits_to_color(bits: u16) -> color::Color {
    let color = match bits & 0x7 {
        0 => color::BLACK,
        0x1 => color::BLUE,
        0x2 => color::GREEN,
        0x4 => color::RED,
        0x6 => color::YELLOW,
        0x5 => color::MAGENTA,
        0x3 => color::CYAN,
        0x7 => color::WHITE,
        _ => unreachable!(),
    };

    color | (bits as u32 & 0x8) // copy the hi-intensity bit
}

struct HandleWrapper {
    inner: HANDLE,
}

impl HandleWrapper {
    fn new(h: HANDLE) -> HandleWrapper {
        HandleWrapper { inner: h }
    }
}

impl Drop for HandleWrapper {
    fn drop(&mut self) {
        if self.inner != INVALID_HANDLE_VALUE {
            unsafe {
                CloseHandle(self.inner);
            }
        }
    }
}

impl Deref for HandleWrapper {
    type Target = HANDLE;
    fn deref(&self) -> &HANDLE {
        &self.inner
    }
}

/// Just get a handle to the current console buffer whatever it is
fn conout() -> io::Result<HandleWrapper> {
    let name = b"CONOUT$\0";
    let handle = unsafe {
        CreateFileA(
            name.as_ptr() as *const i8,
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_WRITE,
            ptr::null_mut(),
            OPEN_EXISTING,
            0,
            ptr::null_mut(),
        )
    };
    if handle == INVALID_HANDLE_VALUE {
        Err(io::Error::last_os_error())
    } else {
        Ok(HandleWrapper::new(handle))
    }
}

unsafe fn set_flag(handle: HANDLE, flag: DWORD) -> io::Result<()> {
    let mut curr_mode: DWORD = 0;
    if GetConsoleMode(handle, &mut curr_mode) == 0 {
        return Err(io::Error::last_os_error());
    }

    if SetConsoleMode(handle, curr_mode | flag) == 0 {
        return Err(io::Error::last_os_error());
    }
    return Ok(());
}

/// Check if console supports ansi codes (should succeed on Windows 10)
pub fn supports_ansi() -> bool {
    conout()
        .and_then(|handle| unsafe { set_flag(*handle, ENABLE_VIRTUAL_TERMINAL_PROCESSING) })
        .is_ok()
}

// This test will only pass if it is running in an actual console, probably
#[test]
fn test_conout() {
    assert!(conout().is_ok())
}

#[rustversion::before(1.36)]
unsafe fn get_console_screen_buffer_info(handle: HANDLE) -> io::Result<CONSOLE_SCREEN_BUFFER_INFO> {
    let mut buffer_info = ::std::mem::uninitialized();
    if GetConsoleScreenBufferInfo(handle, &mut buffer_info) == 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(buffer_info)
    }
}
#[rustversion::since(1.36)]
unsafe fn get_console_screen_buffer_info(handle: HANDLE) -> io::Result<CONSOLE_SCREEN_BUFFER_INFO> {
    let mut buffer_info = ::std::mem::MaybeUninit::uninit();
    if GetConsoleScreenBufferInfo(handle, buffer_info.as_mut_ptr()) == 0 {
        Err(io::Error::last_os_error())
    } else {
        Ok(buffer_info.assume_init())
    }
}

// This test will only pass if it is running in an actual console, probably
#[test]
fn test_get_console_screen_buffer_info() {
    let handle = conout().unwrap();
    unsafe {
        let buffer_info = get_console_screen_buffer_info(*handle);
        assert!(buffer_info.is_ok());
    }
}

impl WinConsoleInfo {
    /// Returns `Err` whenever console info cannot be retrieved for some
    /// reason.
    pub fn from_env() -> io::Result<WinConsoleInfo> {
        let fg;
        let bg;
        let handle = conout()?;
        unsafe {
            let buffer_info = get_console_screen_buffer_info(*handle)?;
            fg = bits_to_color(buffer_info.wAttributes);
            bg = bits_to_color(buffer_info.wAttributes >> 4);
        }
        Ok(WinConsoleInfo {
            def_foreground: fg,
            def_background: bg,
            foreground: fg,
            background: bg,
            reverse: false,
            secure: false,
            standout: false,
        })
    }
}

impl<T: Write + Send> WinConsole<T> {
    fn apply(&mut self) -> io::Result<()> {
        let out = conout()?;
        let _unused = self.buf.flush();

        let (mut fg, bg) = if self.info.reverse {
            (self.info.background, self.info.foreground)
        } else {
            (self.info.foreground, self.info.background)
        };

        if self.info.secure {
            fg = bg;
        }

        let mut accum: WORD = 0;

        accum |= color_to_bits(fg);
        accum |= color_to_bits(bg) << 4;

        if self.info.standout {
            accum |= BACKGROUND_INTENSITY;
        } else {
            accum &= BACKGROUND_INTENSITY ^ 0xFF;
        }

        unsafe {
            SetConsoleTextAttribute(*out, accum);
        }
        Ok(())
    }

    /// Create a new WinConsole with the given WinConsoleInfo and out
    pub fn new_with_consoleinfo(out: T, info: WinConsoleInfo) -> WinConsole<T> {
        WinConsole { buf: out, info }
    }

    /// Returns `Err` whenever the terminal cannot be created for some
    /// reason.
    pub fn new(out: T) -> io::Result<WinConsole<T>> {
        let info = WinConsoleInfo::from_env()?;
        Ok(Self::new_with_consoleinfo(out, info))
    }
}

impl<T: Write> Write for WinConsole<T> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.buf.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buf.flush()
    }
}

impl<T: Write + Send> Terminal for WinConsole<T> {
    type Output = T;

    fn fg(&mut self, color: color::Color) -> Result<()> {
        self.info.foreground = color;
        self.apply()?;

        Ok(())
    }

    fn bg(&mut self, color: color::Color) -> Result<()> {
        self.info.background = color;
        self.apply()?;

        Ok(())
    }

    fn attr(&mut self, attr: Attr) -> Result<()> {
        match attr {
            Attr::ForegroundColor(f) => {
                self.info.foreground = f;
                self.apply()?;
                Ok(())
            }
            Attr::BackgroundColor(b) => {
                self.info.background = b;
                self.apply()?;
                Ok(())
            }
            Attr::Reverse => {
                self.info.reverse = true;
                self.apply()?;
                Ok(())
            }
            Attr::Secure => {
                self.info.secure = true;
                self.apply()?;
                Ok(())
            }
            Attr::Standout(v) => {
                self.info.standout = v;
                self.apply()?;
                Ok(())
            }
            _ => Err(Error::NotSupported),
        }
    }

    fn supports_attr(&self, attr: Attr) -> bool {
        match attr {
            Attr::ForegroundColor(_)
            | Attr::BackgroundColor(_)
            | Attr::Standout(_)
            | Attr::Reverse
            | Attr::Secure => true,
            _ => false,
        }
    }

    fn reset(&mut self) -> Result<()> {
        self.info.foreground = self.info.def_foreground;
        self.info.background = self.info.def_background;
        self.info.reverse = false;
        self.info.secure = false;
        self.info.standout = false;
        self.apply()?;

        Ok(())
    }

    fn supports_reset(&self) -> bool {
        true
    }

    fn supports_color(&self) -> bool {
        true
    }

    fn cursor_up(&mut self) -> Result<()> {
        let _unused = self.buf.flush();
        let handle = conout()?;
        unsafe {
            let buffer_info = get_console_screen_buffer_info(*handle)?;
            let (x, y) = (
                buffer_info.dwCursorPosition.X,
                buffer_info.dwCursorPosition.Y,
            );
            if y == 0 {
                // Even though this might want to be a CursorPositionInvalid, on Unix there
                // is no checking to see if the cursor is already on the first line.
                // I'm not sure what the ideal behavior is, but I think it'd be silly to have
                // cursor_up fail in this case.
                Ok(())
            } else {
                let pos = COORD { X: x, Y: y - 1 };
                if SetConsoleCursorPosition(*handle, pos) != 0 {
                    Ok(())
                } else {
                    Err(io::Error::last_os_error().into())
                }
            }
        }
    }

    fn delete_line(&mut self) -> Result<()> {
        let _unused = self.buf.flush();
        let handle = conout()?;
        unsafe {
            let buffer_info = get_console_screen_buffer_info(*handle)?;
            let pos = buffer_info.dwCursorPosition;
            let size = buffer_info.dwSize;
            let num = (size.X - pos.X) as DWORD;
            let mut written = 0;
            // 0x0020u16 is ' ' (space) in UTF-16 (same as ascii)
            if FillConsoleOutputCharacterW(*handle, 0x0020, num, pos, &mut written) == 0 {
                return Err(io::Error::last_os_error().into());
            }
            if FillConsoleOutputAttribute(*handle, 0, num, pos, &mut written) == 0 {
                return Err(io::Error::last_os_error().into());
            }
            // Similar reasoning for not failing as in cursor_up -- it doesn't even make
            // sense to
            // me that these APIs could have written 0, unless the terminal is width zero.
            Ok(())
        }
    }

    fn carriage_return(&mut self) -> Result<()> {
        let _unused = self.buf.flush();
        let handle = conout()?;
        unsafe {
            let buffer_info = get_console_screen_buffer_info(*handle)?;
            let COORD { X: x, Y: y } = buffer_info.dwCursorPosition;
            if x == 0 {
                Err(Error::CursorDestinationInvalid)
            } else {
                let pos = COORD { X: 0, Y: y };
                if SetConsoleCursorPosition(*handle, pos) != 0 {
                    Ok(())
                } else {
                    Err(io::Error::last_os_error().into())
                }
            }
        }
    }

    fn get_ref<'a>(&'a self) -> &'a T {
        &self.buf
    }

    fn get_mut<'a>(&'a mut self) -> &'a mut T {
        &mut self.buf
    }

    fn into_inner(self) -> T
    where
        Self: Sized,
    {
        self.buf
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::mem;
use core_types::{Size2, ZInt};
use visualizer_types::{Color3, ZFloat, ScreenPos, AttrId};
use cgmath::{Matrix, Matrix4, Matrix3, ToMatrix4, Vector3, rad, Deg, ToRad};
use libc::c_void;
use gl;
use gl::Gl;
use gl::types::{GLuint, GLsizeiptr};
use std::ffi;

/*
pub const GREY_3: Color3 = Color3{r: 0.3, g: 0.3, b: 0.3};
pub const BLACK_3: Color3 = Color3{r: 0.0, g: 0.0, b: 0.0};
pub const WHITE: Color4 = Color4{r: 1.0, g: 1.0, b: 1.0, a: 1.0};
pub const BLUE: Color4 = Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0};
pub const BLACK: Color4 = Color4{r: 0.0, g: 0.0, b: 0.0, a: 1.0};
*/

pub enum MeshRenderMode {
    Triangles,
    // Lines,
}

impl MeshRenderMode {
    pub fn to_gl_type(&self) -> GLuint {
        match *self {
            MeshRenderMode::Triangles => gl::TRIANGLES,
            // MeshRenderMode::Lines => gl::LINES,
        }
    }
}

pub struct Zgl {
    pub gl: Gl,
}

impl Zgl {
    pub fn new<F>(get_proc_address: F) -> Zgl
        where F: Fn(&str) -> *const c_void
    {
        let gl = Gl::load_with(|s| get_proc_address(s));
         Zgl{gl: gl}
    }

    pub fn print_gl_info(&self) {
        println!("GL_VERSION: {}", self.get_info(gl::VERSION));
        println!("GL_SHADING_LANGUAGE_VERSION: {}", self.get_info(gl::SHADING_LANGUAGE_VERSION));
        println!("GL_VENDOR: {}", self.get_info(gl::VENDOR));
        println!("GL_RENDERER: {}", self.get_info(gl::RENDERER));
        // println!("GL_EXTENSIONS: {}", self.get_info(gl::EXTENSIONS));
    }

    pub fn set_clear_color(&mut self, color: Color3) {
        unsafe {
            self.gl.ClearColor(color.r, color.g, color.b, 1.0);
        }
        self.check();
    }

    pub fn clear_screen(&self) {
        unsafe {
            self.gl.Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
        self.check();
    }

    pub fn get_info(&self, name: GLuint) -> String {
        unsafe {
            let version = self.gl.GetString(name) as *const i8;
            String::from_utf8_lossy(ffi::c_str_to_bytes(&version)).into_owned()
        }
    }

    pub fn set_viewport(&mut self, size: &Size2<ZInt>) {
        unsafe {
            self.gl.Viewport(0, 0, size.w, size.h);
        }
        self.check();
    }

    // TODO: replace with something from cgmath-rs
    // from cgmath-rs`s docs:
    // "Transformations are not usually done directly on matrices, but go
    // through transformation objects that can be converted to matrices.
    // Rotations go through the Basis types, which are guaranteed to be
    // orthogonal matrices."
    pub fn tr(&self, m: Matrix4<ZFloat>, v: Vector3<ZFloat>) -> Matrix4<ZFloat> {
        let mut t = Matrix4::<ZFloat>::identity();
        t[3][0] = v.x;
        t[3][1] = v.y;
        t[3][2] = v.z;
        m.mul_m(&t)
    }

    /*
    pub fn scale(&self, m: Matrix4<ZFloat>, scale: ZFloat) -> Matrix4<ZFloat> {
        let mut t = Matrix4::<ZFloat>::identity();
        t[0][0] = scale;
        t[1][1] = scale;
        t[2][2] = scale;
        m.mul_m(&t)
    }
    */

    pub fn rot_x(&self, m: Matrix4<ZFloat>, angle: Deg<ZFloat>) -> Matrix4<ZFloat> {
        let rad = angle.to_rad();
        let r = Matrix3::from_angle_x(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn rot_z(&self, m: Matrix4<ZFloat>, angle: Deg<ZFloat>) -> Matrix4<ZFloat> {
        let rad = angle.to_rad();
        let r = Matrix3::from_angle_z(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn check(&self) {
        let error_code = unsafe { self.gl.GetError() };
        if error_code != 0 {
            let description = match error_code {
                gl::INVALID_ENUM => "GL_INVALID_ENUM",
                gl::INVALID_FRAMEBUFFER_OPERATION => "GL_INVALID_FRAMEBUFFER_OPERATION",
                gl::INVALID_OPERATION => "GL_INVALID_OPERATION",
                gl::INVALID_VALUE => "GL_INVALID_VALUE",
                gl::NO_ERROR => "GL_NO_ERROR",
                gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY",
                _ => panic!("Bad gl error code: {}", error_code),
            };
            panic!("gl error: {}({})", description, error_code);
        }
    }

    pub fn read_pixel_bytes(
        &self,
        win_size: &Size2<ZInt>,
        mouse_pos: &ScreenPos,
    ) -> (ZInt, ZInt, ZInt, ZInt) {
        let height = win_size.h;
        let reverted_h = height - mouse_pos.v.y;
        let data: [u8; 4] = [0, 0, 0, 0];
        unsafe {
            let data_ptr = mem::transmute(&data[0]);
            self.gl.ReadPixels(
                mouse_pos.v.x, reverted_h, 1, 1,
                gl::RGBA,
                gl::UNSIGNED_BYTE,
                data_ptr
            );
        }
        self.check();
        (data[0] as ZInt, data[1] as ZInt, data[2] as ZInt, data[3] as ZInt)
    }

    pub fn draw_arrays(&self, mode: &MeshRenderMode, length: ZInt) {
        let starting_index = 0;
        unsafe {
            self.gl.DrawArrays(mode.to_gl_type(), starting_index, length);
        }
        self.check();
    }

    pub fn enable_vertex_attrib_array(&self, attr_id: &AttrId) {
        unsafe {
            self.gl.EnableVertexAttribArray(attr_id.id);
        }
        self.check();
    }
}

/*
pub fn init_opengl() {
    verify!(gl::Enable(gl::DEPTH_TEST));
    verify!(gl::Enable(gl::BLEND));
    verify!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
}
*/

pub struct Vbo {
    id: GLuint,
}

impl Vbo {
    pub fn from_data<T>(zgl: &Zgl, data: &[T]) -> Vbo {
        let vbo = Vbo{id: Vbo::get_new_vbo_id(zgl)};
        vbo.bind(zgl);
        let size = mem::size_of::<T>();
        let buf_size = (data.len() * size) as GLsizeiptr;
        if data.len() != 0 {
            unsafe {
                let data_ptr = mem::transmute(&data[0]);
                zgl.gl.BufferData(
                    gl::ARRAY_BUFFER,
                    buf_size,
                    data_ptr,
                    gl::STATIC_DRAW,
                );
                zgl.check();
            }
        }
        vbo
    }

    fn get_new_vbo_id(zgl: &Zgl) -> GLuint {
        let mut id = 0;
        unsafe {
            zgl.gl.GenBuffers(1, &mut id);
            zgl.check();
        }
        id
    }

    pub fn bind(&self, zgl: &Zgl) {
        unsafe {
            zgl.gl.BindBuffer(gl::ARRAY_BUFFER, self.id);
        }
        zgl.check();
    }
}

/*
// TODO: how to pass Zgl to d-tor?
impl Drop for Vbo {
    fn drop(&mut self) {
        unsafe {
            verify!(gl::DeleteBuffers(1, &self.id));
        }
    }
}
*/

/*
pub fn get_2d_screen_matrix(&self, win_size: &Size2<ZInt>) -> Matrix4<ZFloat> {
    let left = 0.0;
    let right = win_size.w as ZFloat;
    let bottom = 0.0;
    let top = win_size.h as ZFloat;
    let near = -1.0;
    let far = 1.0;
    ortho(left, right, bottom, top, near, far)
}
*/

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>src/zgl.rs: Formatting<commit_after>// See LICENSE file for copyright and license details.

use std::mem;
use core_types::{Size2, ZInt};
use visualizer_types::{Color3, ZFloat, ScreenPos, AttrId};
use cgmath::{Matrix, Matrix4, Matrix3, ToMatrix4, Vector3, rad, Deg, ToRad};
use libc::c_void;
use gl;
use gl::Gl;
use gl::types::{GLuint, GLsizeiptr};
use std::ffi;

/*
pub const GREY_3: Color3 = Color3{r: 0.3, g: 0.3, b: 0.3};
pub const BLACK_3: Color3 = Color3{r: 0.0, g: 0.0, b: 0.0};
pub const WHITE: Color4 = Color4{r: 1.0, g: 1.0, b: 1.0, a: 1.0};
pub const BLUE: Color4 = Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0};
pub const BLACK: Color4 = Color4{r: 0.0, g: 0.0, b: 0.0, a: 1.0};
*/

pub enum MeshRenderMode {
    Triangles,
    // Lines,
}

impl MeshRenderMode {
    pub fn to_gl_type(&self) -> GLuint {
        match *self {
            MeshRenderMode::Triangles => gl::TRIANGLES,
            // MeshRenderMode::Lines => gl::LINES,
        }
    }
}

pub struct Zgl {
    pub gl: Gl, // TODO: make private
}

impl Zgl {
    pub fn new<F>(get_proc_address: F) -> Zgl
        where F: Fn(&str) -> *const c_void
    {
        let gl = Gl::load_with(|s| get_proc_address(s));
        Zgl{gl: gl}
    }

    pub fn print_gl_info(&self) {
        println!("GL_VERSION: {}", self.get_info(gl::VERSION));
        println!("GL_SHADING_LANGUAGE_VERSION: {}", self.get_info(gl::SHADING_LANGUAGE_VERSION));
        println!("GL_VENDOR: {}", self.get_info(gl::VENDOR));
        println!("GL_RENDERER: {}", self.get_info(gl::RENDERER));
        // println!("GL_EXTENSIONS: {}", self.get_info(gl::EXTENSIONS));
    }

    pub fn set_clear_color(&mut self, color: Color3) {
        unsafe {
            self.gl.ClearColor(color.r, color.g, color.b, 1.0);
        }
        self.check();
    }

    pub fn clear_screen(&self) {
        unsafe {
            self.gl.Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
        self.check();
    }

    pub fn get_info(&self, name: GLuint) -> String {
        unsafe {
            let version = self.gl.GetString(name) as *const i8;
            String::from_utf8_lossy(ffi::c_str_to_bytes(&version)).into_owned()
        }
    }

    pub fn set_viewport(&mut self, size: &Size2<ZInt>) {
        unsafe {
            self.gl.Viewport(0, 0, size.w, size.h);
        }
        self.check();
    }

    // TODO: replace with something from cgmath-rs
    // from cgmath-rs`s docs:
    // "Transformations are not usually done directly on matrices, but go
    // through transformation objects that can be converted to matrices.
    // Rotations go through the Basis types, which are guaranteed to be
    // orthogonal matrices."
    pub fn tr(&self, m: Matrix4<ZFloat>, v: Vector3<ZFloat>) -> Matrix4<ZFloat> {
        let mut t = Matrix4::<ZFloat>::identity();
        t[3][0] = v.x;
        t[3][1] = v.y;
        t[3][2] = v.z;
        m.mul_m(&t)
    }

    /*
    pub fn scale(&self, m: Matrix4<ZFloat>, scale: ZFloat) -> Matrix4<ZFloat> {
        let mut t = Matrix4::<ZFloat>::identity();
        t[0][0] = scale;
        t[1][1] = scale;
        t[2][2] = scale;
        m.mul_m(&t)
    }
    */

    pub fn rot_x(&self, m: Matrix4<ZFloat>, angle: Deg<ZFloat>) -> Matrix4<ZFloat> {
        let rad = angle.to_rad();
        let r = Matrix3::from_angle_x(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn rot_z(&self, m: Matrix4<ZFloat>, angle: Deg<ZFloat>) -> Matrix4<ZFloat> {
        let rad = angle.to_rad();
        let r = Matrix3::from_angle_z(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn check(&self) {
        let error_code = unsafe { self.gl.GetError() };
        if error_code != 0 {
            let description = match error_code {
                gl::INVALID_ENUM => "GL_INVALID_ENUM",
                gl::INVALID_FRAMEBUFFER_OPERATION => "GL_INVALID_FRAMEBUFFER_OPERATION",
                gl::INVALID_OPERATION => "GL_INVALID_OPERATION",
                gl::INVALID_VALUE => "GL_INVALID_VALUE",
                gl::NO_ERROR => "GL_NO_ERROR",
                gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY",
                _ => panic!("Bad gl error code: {}", error_code),
            };
            panic!("gl error: {}({})", description, error_code);
        }
    }

    pub fn read_pixel_bytes(
        &self,
        win_size: &Size2<ZInt>,
        mouse_pos: &ScreenPos,
    ) -> (ZInt, ZInt, ZInt, ZInt) {
        let height = win_size.h;
        let reverted_h = height - mouse_pos.v.y;
        let data: [u8; 4] = [0, 0, 0, 0];
        unsafe {
            let data_ptr = mem::transmute(&data[0]);
            self.gl.ReadPixels(
                mouse_pos.v.x, reverted_h, 1, 1,
                gl::RGBA,
                gl::UNSIGNED_BYTE,
                data_ptr,
            );
        }
        self.check();
        (data[0] as ZInt, data[1] as ZInt, data[2] as ZInt, data[3] as ZInt)
    }

    pub fn draw_arrays(&self, mode: &MeshRenderMode, length: ZInt) {
        let starting_index = 0;
        unsafe {
            self.gl.DrawArrays(mode.to_gl_type(), starting_index, length);
        }
        self.check();
    }

    pub fn enable_vertex_attrib_array(&self, attr_id: &AttrId) {
        unsafe {
            self.gl.EnableVertexAttribArray(attr_id.id);
        }
        self.check();
    }
}

/*
pub fn init_opengl() {
    verify!(gl::Enable(gl::DEPTH_TEST));
    verify!(gl::Enable(gl::BLEND));
    verify!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
}
*/

pub struct Vbo {
    id: GLuint,
}

impl Vbo {
    pub fn from_data<T>(zgl: &Zgl, data: &[T]) -> Vbo {
        let vbo = Vbo{id: Vbo::get_new_vbo_id(zgl)};
        vbo.bind(zgl);
        let size = mem::size_of::<T>();
        let buf_size = (data.len() * size) as GLsizeiptr;
        if data.len() != 0 {
            unsafe {
                let data_ptr = mem::transmute(&data[0]);
                zgl.gl.BufferData(
                    gl::ARRAY_BUFFER,
                    buf_size,
                    data_ptr,
                    gl::STATIC_DRAW,
                );
                zgl.check();
            }
        }
        vbo
    }

    fn get_new_vbo_id(zgl: &Zgl) -> GLuint {
        let mut id = 0;
        unsafe {
            zgl.gl.GenBuffers(1, &mut id);
            zgl.check();
        }
        id
    }

    pub fn bind(&self, zgl: &Zgl) {
        unsafe {
            zgl.gl.BindBuffer(gl::ARRAY_BUFFER, self.id);
        }
        zgl.check();
    }
}

/*
// TODO: how to pass Zgl to d-tor?
impl Drop for Vbo {
    fn drop(&mut self) {
        unsafe {
            verify!(gl::DeleteBuffers(1, &self.id));
        }
    }
}
*/

/*
pub fn get_2d_screen_matrix(&self, win_size: &Size2<ZInt>) -> Matrix4<ZFloat> {
    let left = 0.0;
    let right = win_size.w as ZFloat;
    let bottom = 0.0;
    let top = win_size.h as ZFloat;
    let near = -1.0;
    let far = 1.0;
    ortho(left, right, bottom, top, near, far)
}
*/

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>