<commit_before>mod key;
mod rangeset;

use key::Key;
use rangeset::{Range, RangeSet};
use std::collections::HashMap;

pub type VKey = Key;
pub type EKey = Key;
pub type FKey = Key;
pub type FaceLen = u32;

pub struct Mesh {
    verts: HashMap<VKey, Vert>,
    edges: HashMap<EKey, Edge>,
    faces: HashMap<FKey, Face>,

    vert_range_set: RangeSet,
    edge_range_set: RangeSet,
    face_range_set: RangeSet
}

impl Mesh {
    pub fn new() -> Mesh {
        Mesh {
            verts: HashMap::new(),
            edges: HashMap::new(),
            faces: HashMap::new(),

            // TODO
            vert_range_set: RangeSet::new(Range::new(0, 0xffffffff - 1)),
            edge_range_set: RangeSet::new(Range::new(0, 0xffffffff - 1)),
            face_range_set: RangeSet::new(Range::new(0, 0xffffffff - 1))
        }
    }

    /// Return the edge between two verts, or None if no such edge
    /// exists.
    pub fn find_edge(&self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        for ek in self.verts[&vk0].edges.iter() {
            if self.edges[ek].is_vert_adjacent(vk1) {
                return Some(*ek)
            }
        }
        None
    }

    /// Add a new isolated vertex and return its key. Fail and return
    /// None if there are no more vertex keys available.
    pub fn add_vert(&mut self) -> Option<VKey> {
        if let Some(val) = self.vert_range_set.take_any_one() {
            let vkey = VKey::new(val);
            self.verts.insert(vkey, Vert::new());
            Some(vkey)
        } else {
            None
        }
    }

    pub fn add_edge(&mut self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        // TODO(nicholasbishop): check that the verts are in the mesh,
        if vk0 == vk1 {
            None
        } else if let Some(ek) = self.find_edge(vk0, vk1) {
            Some(ek)
        } else {
            if let Some(val) = self.edge_range_set.take_any_one() {
                let ekey = EKey::new(val);
                self.verts.get_mut(&vk0).unwrap().push_edge(ekey);
                self.verts.get_mut(&vk1).unwrap().push_edge(ekey);
                self.edges.insert(ekey, Edge::new(vk0, vk1));
                Some(ekey)
            } else {
                None
            }
        }
    }

    pub fn add_face(&mut self, vk: &[VKey]) -> Option<FKey> {
        let mut loops = Vec::with_capacity(vk.len());
        for i in 0..vk.len() {
            let vk0 = vk[i];
            let vk1 = vk[if i < (vk.len() - 1) { i + 1 } else { 0 }];
            // TODO(nicholasbishop): do more checking up front so that
            // edges don't get created on failure, or delete them after.
            if let Some(ek) = self.add_edge(vk0, vk1) {
                loops.push(Loop { vert: vk0, edge: ek });
            } else {
                // Error: failed to create edge
                return None;
            }
        }
        if let Some(val) = self.face_range_set.take_any_one() {
            let fk = FKey::new(val);
            for lp in loops.iter() {
                self.edges.get_mut(&lp.edge).unwrap().push_face(fk);
            }
            self.faces.insert(fk, Face::new(loops));
            Some(fk)
        } else {
            None
        }
    }
}

pub struct Vert {
    edges: Vec<EKey>
}

impl Vert {
    fn new() -> Vert {
        Vert { edges: Vec::new() }
    }

    /// Check if the edge is in the set of edges adjacent to this vert.
    pub fn is_edge_adjacent(&self, ek: EKey) -> bool {
        self.edges.contains(&ek)
    }

    /// Add edge to set of edges adjacent to the vert. Does nothing if
    /// the edge is already in the set.
    fn push_edge(&mut self, ek: EKey) {
        if !self.is_edge_adjacent(ek) {
            self.edges.push(ek);
        }
    }
}

pub struct Edge {
    verts: [VKey; 2],
    faces: Vec<FKey>
}

impl Edge {
    fn new(vk0: VKey, vk1: VKey) -> Edge {
        Edge { verts: [vk0, vk1], faces: Vec::new() }
    }

    /// Check if the vert is one of the two verts adjacent to this edge.
    fn is_vert_adjacent(&self, vk: VKey) -> bool {
        self.verts.contains(&vk)
    }

    /// Check if the face is in the set of edges adjacent to this edge.
    pub fn is_face_adjacent(&self, fk: FKey) -> bool {
        self.faces.contains(&fk)
    }

    /// Add face to set of faces adjacent to the edge. Does nothing if
    /// the face is already in the set.
    fn push_face(&mut self, fk: FKey) {
        if !self.is_face_adjacent(fk) {
            self.faces.push(fk);
        }
    }
}

pub struct Loop {
    vert: VKey,
    edge: EKey,
}

pub struct Face {
    loops: Vec<Loop>
}

impl Face {
    fn new(loops: Vec<Loop>) -> Face {
        Face { loops: loops }
    }
}

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

    #[test]
    fn test_add_vert() {
        let mut mesh = Mesh::new();
        assert!(mesh.add_vert().is_some());
        assert!(!mesh.verts.is_empty());
    }

    #[test]
    fn test_add_edge() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert().unwrap();
        let b = mesh.add_vert().unwrap();

        // Add a valid edge
        let e = mesh.add_edge(a, b).unwrap();
        assert!(mesh.verts[&a].edges.contains(&e));
        assert!(mesh.verts[&b].edges.contains(&e));

        // Edge from a vertex to the same vertex is not allowed
        assert!(mesh.add_edge(a, a).is_none());

        // Duplicate edge should return the existing edge
        assert_eq!(mesh.add_edge(a, b).unwrap(), e);
        assert_eq!(mesh.add_edge(b, a).unwrap(), e);
    }

    #[test]
    fn test_add_face() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert().unwrap();
        let b = mesh.add_vert().unwrap();
        let c = mesh.add_vert().unwrap();

        // Add a valid triangle
        mesh.add_face(&[a, b, c]).unwrap();
        assert_eq!(mesh.edges.len(), 3);
        // TODO(nicholasbishop): check adj

        // Add an invalid triangle with invalid edge
        assert!(mesh.add_face(&[a, b, b]).is_none());
    }
}
<commit_msg>Minor de-dup<commit_after>mod key;
mod rangeset;

use key::Key;
use rangeset::{Range, RangeSet};
use std::collections::HashMap;

pub type VKey = Key;
pub type EKey = Key;
pub type FKey = Key;
pub type FaceLen = u32;

pub struct Mesh {
    verts: HashMap<VKey, Vert>,
    edges: HashMap<EKey, Edge>,
    faces: HashMap<FKey, Face>,

    vert_range_set: RangeSet,
    edge_range_set: RangeSet,
    face_range_set: RangeSet
}

// TODO
fn new_key_range_set() -> RangeSet {
    RangeSet::new(Range::new(0, 0xffffffff - 1))
}

impl Mesh {
    pub fn new() -> Mesh {
        Mesh {
            verts: HashMap::new(),
            edges: HashMap::new(),
            faces: HashMap::new(),

            vert_range_set: new_key_range_set(),
            edge_range_set: new_key_range_set(),
            face_range_set: new_key_range_set()
        }
    }

    /// Return the edge between two verts, or None if no such edge
    /// exists.
    pub fn find_edge(&self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        for ek in self.verts[&vk0].edges.iter() {
            if self.edges[ek].is_vert_adjacent(vk1) {
                return Some(*ek)
            }
        }
        None
    }

    /// Add a new isolated vertex and return its key. Fail and return
    /// None if there are no more vertex keys available.
    pub fn add_vert(&mut self) -> Option<VKey> {
        if let Some(val) = self.vert_range_set.take_any_one() {
            let vkey = VKey::new(val);
            self.verts.insert(vkey, Vert::new());
            Some(vkey)
        } else {
            None
        }
    }

    pub fn add_edge(&mut self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        // TODO(nicholasbishop): check that the verts are in the mesh,
        if vk0 == vk1 {
            None
        } else if let Some(ek) = self.find_edge(vk0, vk1) {
            Some(ek)
        } else {
            if let Some(val) = self.edge_range_set.take_any_one() {
                let ekey = EKey::new(val);
                self.verts.get_mut(&vk0).unwrap().push_edge(ekey);
                self.verts.get_mut(&vk1).unwrap().push_edge(ekey);
                self.edges.insert(ekey, Edge::new(vk0, vk1));
                Some(ekey)
            } else {
                None
            }
        }
    }

    pub fn add_face(&mut self, vk: &[VKey]) -> Option<FKey> {
        let mut loops = Vec::with_capacity(vk.len());
        for i in 0..vk.len() {
            let vk0 = vk[i];
            let vk1 = vk[if i < (vk.len() - 1) { i + 1 } else { 0 }];
            // TODO(nicholasbishop): do more checking up front so that
            // edges don't get created on failure, or delete them after.
            if let Some(ek) = self.add_edge(vk0, vk1) {
                loops.push(Loop { vert: vk0, edge: ek });
            } else {
                // Error: failed to create edge
                return None;
            }
        }
        if let Some(val) = self.face_range_set.take_any_one() {
            let fk = FKey::new(val);
            for lp in loops.iter() {
                self.edges.get_mut(&lp.edge).unwrap().push_face(fk);
            }
            self.faces.insert(fk, Face::new(loops));
            Some(fk)
        } else {
            None
        }
    }
}

pub struct Vert {
    edges: Vec<EKey>
}

impl Vert {
    fn new() -> Vert {
        Vert { edges: Vec::new() }
    }

    /// Check if the edge is in the set of edges adjacent to this vert.
    pub fn is_edge_adjacent(&self, ek: EKey) -> bool {
        self.edges.contains(&ek)
    }

    /// Add edge to set of edges adjacent to the vert. Does nothing if
    /// the edge is already in the set.
    fn push_edge(&mut self, ek: EKey) {
        if !self.is_edge_adjacent(ek) {
            self.edges.push(ek);
        }
    }
}

pub struct Edge {
    verts: [VKey; 2],
    faces: Vec<FKey>
}

impl Edge {
    fn new(vk0: VKey, vk1: VKey) -> Edge {
        Edge { verts: [vk0, vk1], faces: Vec::new() }
    }

    /// Check if the vert is one of the two verts adjacent to this edge.
    fn is_vert_adjacent(&self, vk: VKey) -> bool {
        self.verts.contains(&vk)
    }

    /// Check if the face is in the set of edges adjacent to this edge.
    pub fn is_face_adjacent(&self, fk: FKey) -> bool {
        self.faces.contains(&fk)
    }

    /// Add face to set of faces adjacent to the edge. Does nothing if
    /// the face is already in the set.
    fn push_face(&mut self, fk: FKey) {
        if !self.is_face_adjacent(fk) {
            self.faces.push(fk);
        }
    }
}

pub struct Loop {
    vert: VKey,
    edge: EKey,
}

pub struct Face {
    loops: Vec<Loop>
}

impl Face {
    fn new(loops: Vec<Loop>) -> Face {
        Face { loops: loops }
    }
}

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

    #[test]
    fn test_add_vert() {
        let mut mesh = Mesh::new();
        assert!(mesh.add_vert().is_some());
        assert!(!mesh.verts.is_empty());
    }

    #[test]
    fn test_add_edge() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert().unwrap();
        let b = mesh.add_vert().unwrap();

        // Add a valid edge
        let e = mesh.add_edge(a, b).unwrap();
        assert!(mesh.verts[&a].edges.contains(&e));
        assert!(mesh.verts[&b].edges.contains(&e));

        // Edge from a vertex to the same vertex is not allowed
        assert!(mesh.add_edge(a, a).is_none());

        // Duplicate edge should return the existing edge
        assert_eq!(mesh.add_edge(a, b).unwrap(), e);
        assert_eq!(mesh.add_edge(b, a).unwrap(), e);
    }

    #[test]
    fn test_add_face() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert().unwrap();
        let b = mesh.add_vert().unwrap();
        let c = mesh.add_vert().unwrap();

        // Add a valid triangle
        mesh.add_face(&[a, b, c]).unwrap();
        assert_eq!(mesh.edges.len(), 3);
        // TODO(nicholasbishop): check adj

        // Add an invalid triangle with invalid edge
        assert!(mesh.add_face(&[a, b, b]).is_none());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 by Stacy Prowell.  All rights reserved.
//
// Licensed under the BSD 2-Clause license.  See the file LICENSE
// that is part of this distribution.  This file may not be copied,
// modified, or distributed except according to those terms.extern

//! The Elision term rewriting library.
//!
//! Elision is a custom term rewriter intended for use in analyzing
//! and computing the behavior of compiled software.  Elision is
//! Turing complete.

#![feature(path,old_io,old_path,old_fs)]

// Tell the documentation system about some icons and require
// documentation.  Enable core.
#![doc(html_logo_url = "https://raw.githubusercontent.com/relision/things/master/graphics/relision.png",
		html_favicon_url = "https://raw.githubusercontent.com/relision/things/master/graphics/favicon.ico",
		html_root_url = "https://github.com/relision")]
#![warn(missing_docs)]

/* Load platform specific definitions. */

mod win32;
mod linux;
mod macos;
mod terms;

#[cfg(target_os = "linux")]
pub use linux::os_spec;
#[cfg(target_os = "win32")]
pub use win32::os_spec;
#[cfg(target_os = "macos")]
pub use macos::os_spec;
#[cfg(not(any(target_os = "macos",
              target_os = "win32",
              target_os = "linux")))]
pub use linux::os_spec;

use std::old_path::posix::Path;

/// Get the configuration folder.  This creates it if it does not exist.
pub fn get_config_dir() -> String {
	let location = os_spec::get_config_dir();
	let path = Path::new(&location);
	match std::old_io::fs::mkdir_recursive(&path, std::old_io::USER_RWX) {
		Ok(_) => {},
		Err(error) => {
			panic!("Failed to create configuration folder: {}", error);
		}
	};
	return location;
}

<commit_msg>Added collections feature to the crate.<commit_after>// Copyright (c) 2015 by Stacy Prowell.  All rights reserved.
//
// Licensed under the BSD 2-Clause license.  See the file LICENSE
// that is part of this distribution.  This file may not be copied,
// modified, or distributed except according to those terms.extern

//! The Elision term rewriting library.
//!
//! Elision is a custom term rewriter intended for use in analyzing
//! and computing the behavior of compiled software.  Elision is
//! Turing complete.

#![feature(path,old_io,old_path,old_fs,collections)]

// Tell the documentation system about some icons and require
// documentation.  Enable core.
#![doc(html_logo_url = "https://raw.githubusercontent.com/relision/things/master/graphics/relision.png",
		html_favicon_url = "https://raw.githubusercontent.com/relision/things/master/graphics/favicon.ico",
		html_root_url = "https://github.com/relision")]
#![warn(missing_docs)]

/* Load platform specific definitions. */

mod win32;
mod linux;
mod macos;
mod terms;

#[cfg(target_os = "linux")]
pub use linux::os_spec;
#[cfg(target_os = "win32")]
pub use win32::os_spec;
#[cfg(target_os = "macos")]
pub use macos::os_spec;
#[cfg(not(any(target_os = "macos",
              target_os = "win32",
              target_os = "linux")))]
pub use linux::os_spec;

use std::old_path::posix::Path;

/// Get the configuration folder.  This creates it if it does not exist.
pub fn get_config_dir() -> String {
	let location = os_spec::get_config_dir();
	let path = Path::new(&location);
	match std::old_io::fs::mkdir_recursive(&path, std::old_io::USER_RWX) {
		Ok(_) => {},
		Err(error) => {
			panic!("Failed to create configuration folder: {}", error);
		}
	};
	return location;
}

<|endoftext|>


<commit_before>//! Promises in Rust.

#![warn(incomplete_docs)]

use std::thread;
use std::sync::mpsc::channel;
use std::time::Duration;
use std::thread::JoinHandle;
use std::sync::mpsc::{Sender, Receiver};

/// A promise is a way of doing work in the background
pub struct Promise<T, E> {
    //sender: Sender<PromiseMessage<T, E>>, // Send messages to the promise
    receiver: Receiver<Result<T, E>> // Get the result of the promise for chaining (pass into then)
}

enum PromiseJoinType {
    Race,
    All
}

impl<T, E> Promise<T, E> {

    pub fn then<T2, E2>(self, callback: fn(f: T) -> Result<T2, E2>,
                              errback:  fn(e: E) -> Result<T2, E2>)
                        -> Promise<T2, E2> {
        let recv = self.receiver;
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            if let Some(message) = recv.recv() { // Blocking receive until message
                match message {
                    Ok(val) => {
                        tx.send(callback(val));
                    }
                    Err(err) => {
                        tx.send(errback(err));
                    }
                }
            }
            else { // Receive failed, origin was dropped
            }
        });
        return Promise { receiver: rx };
    }

    pub fn new(func: fn(fulfill: T, err: E)) -> Promise<T, E> {
    }
}

// Make sure to give notification to the vat.
impl<T, E> Drop for Promise<T, E> {
    fn drop(self: &mut Self) {
        self.signaler.send(PromiseMessage::OriginDropped);
    }
}

pub fn race<T, E>(promises: Vec<Promise<T, E>>) -> Promise<T, E> {
}

pub fn all<T, E>(promises: Vec<Promise<T, E>>) -> Promise<T, E> {
}

pub fn resolve<T, E>(val: E) -> Promise<T, E> {
}

pub fn reject<T, E>(val: E) -> Promise<T, E> {
}

// Dispatcher methods

fn spawn_vat<T, E>(func: fn(reciever: Receiver<PromiseMessage>) -> Result<T, E>) -> (Receiver<Result<T, E>>, JoinHandle<()>) {
    let (tx, rx) = channel();

}

fn vat_simple(rx: Receiver<PromiseMessage>) {

}

fn vat_join() {

}

#[test]
fn test_channels() {
    println!("Begin test...");
    let mut guard: Option<JoinHandle<_>> = None;
    let mut rec: Option<Receiver<_>> = None;

    {
        println!("\tBegin inner scope...");
        let (tx, rx) = channel();
        guard = Some(thread::spawn(move || {
            println!("\t\tThread created!");
            tx.send("Hello!").unwrap();
            println!("\t\tThread finished!");
        }));
        rec = Some(rx);
        println!("\t(tx, rx) out of scope");
    }

    println!("Sleeping...");
    thread::sleep(Duration::from_secs(2));
    println!("Receiving result...");
    let result = rec.unwrap().recv();
    assert_eq!(result, Ok("Hello!"));
}
<commit_msg>Add unwraps on sends<commit_after>//! Promises in Rust.

#![warn(incomplete_docs)]

use std::thread;
use std::sync::mpsc::channel;
use std::time::Duration;
use std::thread::JoinHandle;
use std::sync::mpsc::{Sender, Receiver};

/// A promise is a way of doing work in the background
pub struct Promise<T, E> {
    //sender: Sender<PromiseMessage<T, E>>, // Send messages to the promise
    receiver: Receiver<Result<T, E>> // Get the result of the promise for chaining (pass into then)
}

enum PromiseJoinType {
    Race,
    All
}

impl<T, E> Promise<T, E> {

    /// Chains a function to be called after this promise resolves.
    pub fn then<T2, E2>(self, callback: fn(f: T) -> Result<T2, E2>,
                              errback:  fn(e: E) -> Result<T2, E2>)
                        -> Promise<T2, E2> {
        let recv = self.receiver;
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            if let Some(message) = recv.recv() { // Blocking receive until message
                match message {
                    Ok(val) => {
                        let _ = tx.send(callback(val)).unwrap_or(());
                    }
                    Err(err) => {
                        let _ = tx.send(errback(err)).unwrap_or(());
                    }
                }
            }
            else { // Receive failed, origin was dropped
            }
        });
        return Promise { receiver: rx };
    }

    /// Chains a function to be called after this promise resolves.
    pub fn then_result<T2, E2>(self,
                               callback: fn(input: Result<T, E>) -> Result<T2, E2>),
                               -> Promise<T2, E2> {
        let recv = self.receiver;
        let recv2 = self.receiver;
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            if let Some(result) = recv.recv() { // Blocking receive until message
                let _ = tx.send(callback(result)).unwrap_or(());
            }
            else { // Receive failed, origin was dropped
            }
        });
        return Promise { receiver: rx };
    }

    pub fn new(func: fn() -> Result<T, E>) -> Promise<T, E> {
        let (tx, rx) = channel();

        let thread = thread::spawn(move || {
            let result = func();
            let _ = tx.send(func).unwrap_or(());
        });

        return Promise { receiver: rx };
    }
}

pub fn race<T, E>(promises: Vec<Promise<T, E>>) -> Promise<T, E> {
}

pub fn all<T, E>(promises: Vec<Promise<T, E>>) -> Promise<T, E> {
}

pub fn resolve<T, E>(val: E) -> Promise<T, E> {
}

pub fn reject<T, E>(val: E) -> Promise<T, E> {
}

// Dispatcher methods

fn spawn_vat<T, E>(func: fn(reciever: Receiver<PromiseMessage>) -> Result<T, E>) -> (Receiver<Result<T, E>>, JoinHandle<()>) {
    let (tx, rx) = channel();

}

fn vat_join() {

}

#[test]
fn test_channels() {
    println!("Begin test...");
    let mut guard: Option<JoinHandle<_>> = None;
    let mut rec: Option<Receiver<_>> = None;

    {
        println!("\tBegin inner scope...");
        let (tx, rx) = channel();
        guard = Some(thread::spawn(move || {
            println!("\t\tThread created!");
            tx.send("Hello!").unwrap();
            println!("\t\tThread finished!");
        }));
        rec = Some(rx);
        println!("\t(tx, rx) out of scope");
    }

    println!("Sleeping...");
    thread::sleep(Duration::from_secs(2));
    println!("Receiving result...");
    let result = rec.unwrap().recv();
    assert_eq!(result, Ok("Hello!"));
}
<|endoftext|>


<commit_before>//#[link(name = "my_build_dependency", kind = "static")]
extern crate libc;
//use libc::size_t;

use std::default::Default;

pub const WATCH_ENABLE:libc::c_int   = 0x000001;   /* enable streaming */
pub const WATCH_DISABLE:libc::c_int  = 0x000002;   /* disable watching */
pub const WATCH_JSON:libc::c_int     = 0x000010;   /* JSON output */
pub const WATCH_NMEA:libc::c_int     = 0x000020;   /* output in NMEA */
pub const WATCH_RARE:libc::c_int     = 0x000040;   /* output of packets in hex */
pub const WATCH_RAW:libc::c_int      = 0x000080;   /* output of raw packets */
pub const WATCH_SCALED:libc::c_int   = 0x000100;   /* scale output to floats */
pub const WATCH_TIMING:libc::c_int   = 0x000200;   /* timing information */
pub const WATCH_DEVICE:libc::c_int   = 0x000800;   /* watch specific device */
pub const WATCH_SPLIT24:libc::c_int  = 0x001000;   /* split AIS Type 24s */
pub const WATCH_PPS:libc::c_int      = 0x002000;   /* enable PPS JSON */
pub const WATCH_NEWSTYLE:libc::c_int = 0x010000;   /* force JSON streaming */

//GPS_PATH_MAX:uint8 = 128;

// MAXCHANNELS = 72 /* must be > 12 GPS + 12 GLONASS + 2 WAAS */
// MAXUSERDEVS 4   /* max devices per user */

pub type GPSMaskT = libc::uint64_t;
pub type TimestampT = libc::c_double;

pub type GPSPath = [libc::c_char; 128];

#[repr(C)]
#[derive(Default)]
pub struct DopT {
    /* Dilution of precision factors */
    xdop: libc::c_double,
    ydop: libc::c_double,
    pdop: libc::c_double,
    hdop: libc::c_double,
    vdop: libc::c_double,
    tdop: libc::c_double,
    gdop: libc::c_double,
}

#[repr(C)]
pub struct DevconfigT {
    path: [libc::c_char; 128],
    flags: libc::c_int,
//    #define SEEN_GPS    0x01
//    #define SEEN_RTCM2  0x02
//    #define SEEN_RTCM3  0x04
//    #define SEEN_AIS    0x08
    driver: [libc::c_char; 64],
    subtype: [libc::c_char; 64],
    activated: libc::c_double,

    /* RS232 link parameters */
    baudrate: libc::c_uint,
    stopbits: libc::c_uint,

    /* 'N', 'O', or 'E' */
    parity: libc::c_char,

    /* refresh cycle time in seconds */
    cycle: libc::c_double,
    mincycle: libc::c_double,

    /* is driver in native mode or not? */
    driver_mode: libc::c_int,
}

impl Default for DevconfigT {
    fn default() -> DevconfigT {
        DevconfigT {
            path: [0; 128],
            flags: Default::default(),
            driver: [0; 64],
            subtype: [0; 64],
            activated: Default::default(),
            baudrate: Default::default(),
            stopbits: Default::default(),
            parity: Default::default(),
            cycle: Default::default(),
            mincycle: Default::default(),
            driver_mode: Default::default(),
        }
    }
}

#[repr(C)]
#[derive(Default)]
pub struct GPSFixT {
    time: TimestampT,   /* Time of update */

    /* Mode of fix */
    mode: libc::c_int,
//    #define MODE_NOT_SEEN   0   /* mode update not seen yet */
//    #define MODE_NO_FIX 1   /* none */
//    #define MODE_2D     2   /* good for latitude/longitude */
//    #define MODE_3D     3   /* good for altitude/climb too */

    /* Expected time uncertainty */
    ept: libc::c_double,

    /* Latitude in degrees (valid if mode >= 2) */
    latitude: libc::c_double,

    /* Latitude position uncertainty, meters */
    epy: libc::c_double,

    /* Longitude in degrees (valid if mode >= 2) */
    longitude: libc::c_double,

    /* Longitude position uncertainty, meters */
    epx: libc::c_double,

    /* Altitude in meters (valid if mode == 3) */
    altitude: libc::c_double,

    /* Vertical position uncertainty, meters */
    epv: libc::c_double,

    /* Course made good (relative to true north) */
    track: libc::c_double,

    /* Track uncertainty, degrees */
    epd: libc::c_double,

    /* Speed over ground, meters/sec */
    speed: libc::c_double,

    /* Speed uncertainty, meters/sec */
    eps: libc::c_double,

    /* Vertical speed, meters/sec */
    climb: libc::c_double,

    /* Vertical speed uncertainty */
    epc: libc::c_double,
}
#[repr(C)]
pub struct PolicyT {
    watcher: bool, /* is watcher mode on? */
    json:    bool, /* requesting JSON? */
    nmea:    bool, /* requesting dumping as NMEA? */
    raw:     i16, /* requesting raw data? */
    scaled:  bool, /* requesting report scaling? */
    timing:  bool, /* requesting timing info */
    split24: bool, /* requesting split AIS Type 24s */
    pps:     bool, /* requesting PPS in NMEA/raw modes */
    loglevel: u8,  /* requested log level of messages */
    devpath: [libc::c_char; 128], /* specific device to watch */
    remote:  [libc::c_char; 128], /* ...if this was passthrough */
}

impl Default for PolicyT {
    fn default() -> PolicyT {
        PolicyT {
            watcher: Default::default(),
            json:    Default::default(),
            nmea:    Default::default(),
            raw:     Default::default(),
            scaled:  Default::default(),
            timing:  Default::default(),
            split24: Default::default(),
            pps:     Default::default(),
            loglevel: Default::default(),
            devpath: [0; 128],
            remote:  [0; 128],
        }
    }
}

#[repr(C)]
pub struct GPSDataT {

    /* has field been set since this was last cleared? */
    set: GPSMaskT,

   /* NZ if GPS is on line, 0 if not.
    *
    * Note: gpsd clears this time when sentences
    * fail to show up within the GPS's normal
    * send cycle time. If the host-to-GPS
    * link is lossy enough to drop entire
    * sentences, this field will be
    * prone to false zero values.
    */
    online: TimestampT,

//    #ifndef USE_QT
//      gps_fd: socket_t/* socket or file descriptor to GPS */
//    #else
//      gps_fd: *void,
//    #endif

    /* accumulated PVT data */
    fix: GPSFixT,

    /* this should move to the per-driver structure */
    separation: libc::c_double,/* Geoidal separation, MSL - WGS84 (Meters) */

    /* GPS status -- always valid */
    status: libc::c_int ,/* Do we have a fix? */

    /* precision of fix -- valid if satellites_used > 0 */
    satellites_used: libc::c_int ,/* Number of satellites used in solution */
    lused: [libc::c_int; 72],/* PRNs of satellites used in solution */
    dop: DopT,

    /* redundant with the estimate elements in the fix structure */
    epe: libc::c_double,  /* spherical position error, 95% confidence (meters)  */

    /* satellite status -- valid when satellites_visible > 0 */
    skyview_time: TimestampT,/* skyview timestamp */

    /* # of satellites in view */
    satellites_visible: libc::c_int,

    /* PRNs of satellite */
    prn: [libc::c_int; 72],

    /* elevation of satellite */
    elevation: [libc::c_int; 72],

    /* azimuth */
    azimuth: [libc::c_int; 72],

    /* signal-to-noise ratio (dB) */
    ss: [libc::c_double; 72],

    dev: DevconfigT,/* device that shipped last update */

    policy: PolicyT,/* our listening policy */

    /* should be moved to privdata someday */
    tag: [libc::c_char; 73],/* tag of last sentence processed */

    /* pack things never reported together to reduce structure size */
   // #define UNION_SET(RTCM2_SET|RTCM3_SET|SUBFRAME_SET|AIS_SET|ATTITUDE_SET|GST_SET|VERSION_SET|DEVICELIST_SET|LOGMESSAGE_SET|ERROR_SET)
//    union NeverReported {
//      /* unusual forms of sensor data that might come up the pipe */
//      rtcm2: rtcm2_trtcm2,
//      rtcm3: rtcm3_trtcm3,
//      subframe: subframe_t,
//      ais:ais_t,
//      attitude: attitude_t,
//      raw: rawdata_t,
//      gst: gst_t,
//      /* "artificial" structures for various protocol responses */
//      version: version_t,
//      error: [char; 256],
//    }

    /* Private data - client code must not set this */
    //void *privdata,
}

impl Default for GPSDataT {
    fn default() -> GPSDataT {
        GPSDataT {
            set: Default::default(),
            online: Default::default(),
            fix: Default::default(),
            separation: Default::default(),
            status: Default::default(),
            satellites_used: Default::default(),
            lused: [0;72],
            dop: Default::default(),
            epe: Default::default(),
            skyview_time: Default::default(),
            satellites_visible: Default::default(),
            prn: [0;72],
            elevation: [0;72],
            azimuth: [0;72],
            ss:[0.0;72],
            dev: Default::default(),
            policy: Default::default(),
            tag: [Default::default(); 73]
        }
    }
}

#[repr(C)]
#[derive(Default)]
pub struct Devices {
    time: TimestampT,
    ndevices: libc::c_int,
    list: [DevconfigT; 4],
}

#[link(name = "gps")]
extern "C" {

    pub fn gps_sock_open(host: *const libc::c_char, port: *const libc::c_char, gpsDataT: *mut GPSDataT) -> libc::c_int;
    pub fn gps_sock_close(gpsdata: *mut GPSDataT) -> libc::c_int;
    pub fn gps_sock_send(gpsdata: *mut GPSDataT, buf: *const libc::c_char) -> libc::c_int;
    pub fn gps_sock_read(gpsdata: *mut GPSDataT) -> libc::c_int;
    pub fn gps_sock_waiting(gpsdata: *const GPSDataT, timeout: i64) -> bool;
    pub fn gps_sock_stream(gpsdata: *mut GPSDataT, flags: libc::c_int, d: *mut libc::c_void)  -> libc::c_int;
    pub fn gps_sock_data(gpsdata: *const GPSDataT) -> libc::c_char;
    //
//    extern int gps_sock_mainloop(struct gps_data_t *, int,
//                        void (*)(struct gps_data_t *));
    fn gps_sock_mainloop(GPSDataT: *mut GPSDataT,
                         timeout: libc::c_int,
                         hook: extern "C" fn (*mut GPSDataT)) -> libc::c_int;
    pub fn gps_shm_open(gpsdata: *mut GPSDataT) -> libc::c_int;
    pub fn gps_shm_close(gpsdata: *mut GPSDataT);
    pub fn gps_shm_waiting(gpsdata: *const GPSDataT, timeout: libc::c_long)  -> bool;
    pub fn gps_shm_read(gpsdata: *mut GPSDataT) -> libc::c_int;
    //fn gps_shm_mainloop(*mut GPSDataT, timeout: libc::c_long, void (*)(struct GPSDataT *)) -> libc::c_int;

    pub fn gps_dbus_open(gpsdata: *mut GPSDataT)  -> libc::c_int;
    //fn gps_dbus_mainloop(gpsdata: *mut GPSDataT, lib::c_long, void (*)(struct GPSDataT *)) -> libc::c_int;
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        unsafe {
            use GPSDataT;
            use gps_sock_open;
            use gps_sock_mainloop;
            use gps_sock_stream;
            use gps_sock_close;
            use WATCH_JSON;
            use WATCH_ENABLE;
            use std::ffi::CString;
            use std::ptr;

            let mut gps_data: GPSDataT = Default::default();
            let ip = CString::new("127.0.0.1").expect("Invalid IP");
            let port = CString::new("2947").expect("Invalid Port");

            extern "C" fn print_gps(gps_data: *mut GPSDataT) {
                unsafe {
                    println!("Satellites visible {}, online {}", (*gps_data).satellites_visible, (*gps_data).online)
                }
            }

            println!("Running now");
            let openres = gps_sock_open(ip.as_ptr(), port.as_ptr(), &mut gps_data);
            println!("Open Result {}", openres);

            let sockres = gps_sock_stream(&mut gps_data, WATCH_ENABLE | WATCH_JSON, ptr::null_mut());
            println!("Socket Result {}", sockres);

            let mainres = gps_sock_mainloop(&mut gps_data, 20000, print_gps);
            println!("Main Result {}", mainres);

            let closeres = gps_sock_close(&mut gps_data);
            println!("Close Result {}", closeres);
        }
    }
}
<commit_msg>Align types to libgps 3.16<commit_after>//#[link(name = "my_build_dependency", kind = "static")]
extern crate libc;

use std::default::Default;
use std::ptr;
use std::fmt;

pub const WATCH_ENABLE:libc::c_int   = 0x000001;   /* enable streaming */
pub const WATCH_DISABLE:libc::c_int  = 0x000002;   /* disable watching */
pub const WATCH_JSON:libc::c_int     = 0x000010;   /* JSON output */
pub const WATCH_NMEA:libc::c_int     = 0x000020;   /* output in NMEA */
pub const WATCH_RARE:libc::c_int     = 0x000040;   /* output of packets in hex */
pub const WATCH_RAW:libc::c_int      = 0x000080;   /* output of raw packets */
pub const WATCH_SCALED:libc::c_int   = 0x000100;   /* scale output to floats */
pub const WATCH_TIMING:libc::c_int   = 0x000200;   /* timing information */
pub const WATCH_DEVICE:libc::c_int   = 0x000800;   /* watch specific device */
pub const WATCH_SPLIT24:libc::c_int  = 0x001000;   /* split AIS Type 24s */
pub const WATCH_PPS:libc::c_int      = 0x002000;   /* enable PPS JSON */
pub const WATCH_NEWSTYLE:libc::c_int = 0x010000;   /* force JSON streaming */

//GPS_PATH_MAX:uint8 = 128;

// MAXCHANNELS = 72 /* must be > 12 GPS + 12 GLONASS + 2 WAAS */
// MAXUSERDEVS 4   /* max devices per user */

pub type GPSMaskT = libc::uint64_t;
pub type TimestampT = libc::c_double;

pub type GPSPath = [libc::c_char; 128];
pub type SocketT = libc::c_int;

#[repr(C)]
#[derive(Default)]
pub struct DopT {
    /* Dilution of precision factors */
    xdop: libc::c_double,
    ydop: libc::c_double,
    pdop: libc::c_double,
    hdop: libc::c_double,
    vdop: libc::c_double,
    tdop: libc::c_double,
    gdop: libc::c_double,
}

#[repr(C)]
pub struct DevconfigT {
    path: [libc::c_char; 128],
    flags: libc::c_int,
//    #define SEEN_GPS    0x01
//    #define SEEN_RTCM2  0x02
//    #define SEEN_RTCM3  0x04
//    #define SEEN_AIS    0x08
    driver: [libc::c_char; 64],
    subtype: [libc::c_char; 64],
    activated: libc::c_double,

    /* RS232 link parameters */
    baudrate: libc::c_uint,
    stopbits: libc::c_uint,

    /* 'N', 'O', or 'E' */
    parity: libc::c_char,

    /* refresh cycle time in seconds */
    cycle: libc::c_double,
    mincycle: libc::c_double,

    /* is driver in native mode or not? */
    driver_mode: libc::c_int,
}

impl Default for DevconfigT {
    fn default() -> DevconfigT {
        DevconfigT {
            path: [0; 128],
            flags: Default::default(),
            driver: [0; 64],
            subtype: [0; 64],
            activated: Default::default(),
            baudrate: Default::default(),
            stopbits: Default::default(),
            parity: Default::default(),
            cycle: Default::default(),
            mincycle: Default::default(),
            driver_mode: Default::default(),
        }
    }
}

#[repr(C)]
#[derive(Default)]
pub struct GPSFixT {
    time: TimestampT,   /* Time of update */

    /* Mode of fix */
    mode: libc::c_int,
//    #define MODE_NOT_SEEN   0   /* mode update not seen yet */
//    #define MODE_NO_FIX 1   /* none */
//    #define MODE_2D     2   /* good for latitude/longitude */
//    #define MODE_3D     3   /* good for altitude/climb too */

    /* Expected time uncertainty */
    ept: libc::c_double,

    /* Latitude in degrees (valid if mode >= 2) */
    latitude: libc::c_double,

    /* Latitude position uncertainty, meters */
    epy: libc::c_double,

    /* Longitude in degrees (valid if mode >= 2) */
    longitude: libc::c_double,

    /* Longitude position uncertainty, meters */
    epx: libc::c_double,

    /* Altitude in meters (valid if mode == 3) */
    altitude: libc::c_double,

    /* Vertical position uncertainty, meters */
    epv: libc::c_double,

    /* Course made good (relative to true north) */
    track: libc::c_double,

    /* Track uncertainty, degrees */
    epd: libc::c_double,

    /* Speed over ground, meters/sec */
    speed: libc::c_double,

    /* Speed uncertainty, meters/sec */
    eps: libc::c_double,

    /* Vertical speed, meters/sec */
    climb: libc::c_double,

    /* Vertical speed uncertainty */
    epc: libc::c_double,
}

impl fmt::Display for GPSFixT {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "\nGPSFIX \n \
                Time {}\n \
                Mode {}\n \
                Ept {}\n \
                Lat {}\n \
                Epy {}\n \
                Lon {}\n \
                Epx {}\n \
                Altitude {}\n \
                Epv {}\n \
                Track {}\n \
                Epd {}\n \
                Speed {}"
               ,
               self.time,
               self.mode,
               self.ept,
               self.latitude,
               self.epy,
               self.longitude,
               self.epx,
               self.altitude,
               self.epv,
               self.track,
               self.epd,
               self.speed
         )
    }
}

#[repr(C)]
pub struct PolicyT {
    watcher: bool, /* is watcher mode on? */
    json:    bool, /* requesting JSON? */
    nmea:    bool, /* requesting dumping as NMEA? */
    raw:     libc::c_int, /* requesting raw data? */
    scaled:  bool, /* requesting report scaling? */
    timing:  bool, /* requesting timing info */
    split24: bool, /* requesting split AIS Type 24s */
    pps:     bool, /* requesting PPS in NMEA/raw modes */
    loglevel: u8,  /* requested log level of messages */
    devpath: [libc::c_char; 128], /* specific device to watch */
    remote:  [libc::c_char; 128], /* ...if this was passthrough */
}

impl Default for PolicyT {
    fn default() -> PolicyT {
        PolicyT {
            watcher: Default::default(),
            json:    Default::default(),
            nmea:    Default::default(),
            raw:     Default::default(),
            scaled:  Default::default(),
            timing:  Default::default(),
            split24: Default::default(),
            pps:     Default::default(),
            loglevel: Default::default(),
            devpath: [0; 128],
            remote:  [0; 128],
        }
    }
}

#[derive(Clone, Copy)]
#[repr(C)]
pub struct SatelliteT {
    /* signal-to-noise ratio (dB) */
    ss: libc::c_double,
    /* PRNs of satellites used in solution */
    used: bool,
    /* PRNs of satellite */
    prn: libc::c_short,
    /* elevation of satellite */
    elevation: libc::c_short,
    /* azimuth */
    azimuth: libc::c_short,
}

impl Default for SatelliteT {
    fn default() -> SatelliteT {
        SatelliteT {
            ss: Default::default(),
            used: Default::default(),
            prn: Default::default(),
            elevation: Default::default(),
            azimuth: Default::default(),
       }
    }
}

#[repr(C)]
pub struct GPSDataT {

    /* has field been set since this was last cleared? */
    set: GPSMaskT,

   /* NZ if GPS is on line, 0 if not.
    *
    * Note: gpsd clears this time when sentences
    * fail to show up within the GPS's normal
    * send cycle time. If the host-to-GPS
    * link is lossy enough to drop entire
    * sentences, this field will be
    * prone to false zero values.
    */
    online: TimestampT,

//    #ifndef USE_QT
    gps_fd: SocketT, /* socket or file descriptor to GPS */
//    #else
//    gps_fd: *mut libc::c_void,
//    #endif

    /* accumulated PVT data */
    fix: GPSFixT,

    /* this should move to the per-driver structure */
    separation: libc::c_double,/* Geoidal separation, MSL - WGS84 (Meters) */

    /* GPS status -- always valid */
    status: libc::c_int ,/* Do we have a fix? */

    /* precision of fix -- valid if satellites_used > 0 */
    satellites_used: libc::c_int ,/* Number of satellites used in solution */

    dop: DopT,

    /* redundant with the estimate elements in the fix structure */
    epe: libc::c_double,  /* spherical position error, 95% confidence (meters)  */

    /* satellite status -- valid when satellites_visible > 0 */
    skyview_time: TimestampT,/* skyview timestamp */

    /* # of satellites in view */
    satellites_visible: libc::c_int,

    skyview: [SatelliteT; 72],

    dev: DevconfigT,/* device that shipped last update */

    policy: PolicyT,/* our listening policy */

    devices: Devices,

    union_never_reported: [libc::c_int; 1418], // rtcm3_t largest in union -> sizeof 5672 = 4*1418
    /* pack things never reported together to reduce structure size */
   // #define UNION_SET(RTCM2_SET|RTCM3_SET|SUBFRAME_SET|AIS_SET|ATTITUDE_SET|GST_SET|VERSION_SET|DEVICELIST_SET|LOGMESSAGE_SET|ERROR_SET)
//    union NeverReported {
//      /* unusual forms of sensor data that might come up the pipe */
//      rtcm2: rtcm2_trtcm2,
//      rtcm3: rtcm3_trtcm3,
//      subframe: subframe_t,
//      ais:ais_t,
//      attitude: attitude_t,
//      raw: rawdata_t,
//      gst: gst_t,
//      /* "artificial" structures for various protocol responses */
//      version: version_t,
//      error: [char; 256],
//    }

    /* Private data - client code must not set this */
    privdata: *mut libc::c_void,
    //void *privdata,
}

impl Default for GPSDataT {
    fn default() -> GPSDataT {
        GPSDataT {
            set: Default::default(),
            online: Default::default(),
            gps_fd:  Default::default(),
//            gps_fd: ptr::null_mut(),
            fix: Default::default(),
            separation: Default::default(),
            status: Default::default(),
            satellites_used: Default::default(),
            dop: Default::default(),
            epe: Default::default(),
            skyview_time: Default::default(),
            satellites_visible: Default::default(),
            skyview: [Default::default(); 72],
            dev: Default::default(),
            policy: Default::default(),
            devices: Default::default(),
            union_never_reported: [Default::default(); 1418],
            privdata: ptr::null_mut(),
        }
    }
}

impl fmt::Display for GPSDataT {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
                "\nGPSDATAT \n \
                 Set {}\n \
                 Online {}\n \n\
                 Fix {}\n \n \
                 Separation {}\n \
                 Status {}\n \
                 SatellitesUsed {}\n \
                 Epe {}\n \
                 SkyviewTime {}\n \
                 SatellitesVisible {}\n",
               self.set,
               self.online,
               self.fix,
               self.separation,
               self.status,
               self.satellites_used,
               self.epe,
               self.skyview_time,
               self.satellites_visible,
        )
    }
}

#[repr(C)]
#[derive(Default)]
pub struct Devices {
    time: TimestampT,
    ndevices: libc::c_int,
    list: [DevconfigT; 4],
}

#[link(name = "gps")]
extern "C" {

    pub fn gps_sock_open(host: *const libc::c_char, port: *const libc::c_char, gpsDataT: *mut GPSDataT) -> libc::c_int;
    pub fn gps_sock_close(gpsdata: *mut GPSDataT) -> libc::c_int;
    pub fn gps_sock_send(gpsdata: *mut GPSDataT, buf: *const libc::c_char) -> libc::c_int;
    pub fn gps_sock_read(gpsdata: *mut GPSDataT) -> libc::c_int;
    pub fn gps_sock_waiting(gpsdata: *const GPSDataT, timeout: i64) -> bool;
    pub fn gps_sock_stream(gpsdata: *mut GPSDataT, flags: libc::c_int, d: *mut libc::c_void)  -> libc::c_int;
    pub fn gps_sock_data(gpsdata: *const GPSDataT) -> libc::c_char;
    //
//    extern int gps_sock_mainloop(struct gps_data_t *, int,
//                        void (*)(struct gps_data_t *));
    fn gps_sock_mainloop(GPSDataT: *mut GPSDataT,
                         timeout: libc::c_int,
                         hook: extern "C" fn (*mut GPSDataT)) -> libc::c_int;
    pub fn gps_shm_open(gpsdata: *mut GPSDataT) -> libc::c_int;
    pub fn gps_shm_close(gpsdata: *mut GPSDataT);
    pub fn gps_shm_waiting(gpsdata: *const GPSDataT, timeout: libc::c_long)  -> bool;
    pub fn gps_shm_read(gpsdata: *mut GPSDataT) -> libc::c_int;
    //fn gps_shm_mainloop(*mut GPSDataT, timeout: libc::c_long, void (*)(struct GPSDataT *)) -> libc::c_int;

    pub fn gps_dbus_open(gpsdata: *mut GPSDataT)  -> libc::c_int;
    //fn gps_dbus_mainloop(gpsdata: *mut GPSDataT, lib::c_long, void (*)(struct GPSDataT *)) -> libc::c_int;
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        unsafe {
            use GPSDataT;
            use GPSFixT;
            use DopT;
            use DevconfigT;
            use PolicyT;
            use GPSMaskT;
            use TimestampT;
            use SocketT;
            use Devices;
            use gps_sock_open;
            use gps_sock_mainloop;
            use gps_sock_stream;
            use gps_sock_close;
            use WATCH_JSON;
            use WATCH_ENABLE;
            use std::ffi::CString;
            use std::ptr;
            use std::mem;

            let mut gps_data: GPSDataT = Default::default();
            let ip = CString::new("127.0.0.1").expect("Invalid IP");
            let port = CString::new("2947").expect("Invalid Port");

            println!("GPSDataT Size {}", mem::size_of::<GPSDataT>());
            println!("GpsFixT Size {}", mem::size_of::<GPSFixT>());
            println!("DopT Size {}", mem::size_of::<DopT>());
            println!("DevconfigT Size {}", mem::size_of::<DevconfigT>());
            println!("PolicyT Size {}", mem::size_of::<PolicyT>());
            println!("GPSMaskT Size {}", mem::size_of::<GPSMaskT>());
            println!("TimestampT Size {}", mem::size_of::<TimestampT>());
            println!("SocketT Size {}", mem::size_of::<SocketT>());
            println!("Devices Size {}", mem::size_of::<Devices>());

            extern "C" fn print_gps(gps_data: *mut GPSDataT) {
                unsafe {
                    println!("{}", (*gps_data));
                    println!("{}", (*gps_data).fix);
                }
            }

            println!("Running now");
            let openres = gps_sock_open(ip.as_ptr(), port.as_ptr(), &mut gps_data);
            println!("Open Result {}", openres);

            let sockres = gps_sock_stream(&mut gps_data, WATCH_ENABLE | WATCH_JSON, ptr::null_mut());
            println!("Socket Result {}", sockres);

            let mainres = gps_sock_mainloop(&mut gps_data, 20000, print_gps);
            println!("Main Result {}", mainres);

            let closeres = gps_sock_close(&mut gps_data);
            println!("Close Result {}", closeres);
        }
    }
}
<|endoftext|>


<commit_before>extern crate openssl;
extern crate rust_base58;
extern crate rustc_serialize;

use self::HashType::*;

use openssl::crypto::hash as openssl_hash;
use rust_base58::{FromBase58, ToBase58};

#[derive(Copy, Clone)]
pub enum HashType {
    SHA1 = 0x11,
    SHA2_256 = 0x12,
    SHA2_512 = 0x13,
    SHA3 = 0x14,
    BLAKE2B = 0x40,
    BLAKE2S = 0x41,
}

impl HashType {
    pub fn from_code(code: u8) -> Option<HashType> {
        match code {
            0x11 => Some(SHA1),
            0x12 => Some(SHA2_256),
            0x13 => Some(SHA2_512),
            0x14 => Some(SHA3),
            0x40 => Some(BLAKE2B),
            0x41 => Some(BLAKE2S),
            _ => None,
        }
    }

    fn digest_len(&self) -> u8 {
        match *self {
            SHA1     => 20,
            SHA2_256 => 32,
            SHA2_512 => 64,
            SHA3     => 64,
            BLAKE2B  => 64,
            BLAKE2S  => 32,
        }
    }

    fn code(&self) -> u8 {
        *self as u8
    }

    fn to_str(&self) -> &'static str {
        match *self {
            SHA1     => "sha1",
            SHA2_256 => "sha2-256",
            SHA2_512 => "sha2-512",
            SHA3     => "sha3",
            BLAKE2B  => "blake2b",
            BLAKE2S  => "blake2s",
        }
    }
}

/// Hashes the `data` with the function described by `hash_type` and returns the result
/// as a Multihash.
pub fn multihash<'a>(data: &'a[u8], hash_type: HashType) -> Multihash {
    let openssl_type: openssl_hash::Type = match hash_type {
        SHA1     => openssl_hash::Type::SHA1,
        SHA2_256 => openssl_hash::Type::SHA256,
        SHA2_512 => openssl_hash::Type::SHA512,
        _ => panic!("That hash function is not yet implemented. Sorry"),
    };

    let hashed = openssl_hash::hash(openssl_type, data);

    Multihash::encode(&hashed[..], hash_type.code()).unwrap()
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Multihash {
    bytes: Vec<u8>
}

impl Multihash {
    /// Construct a multihash from a base58 string by parsing it into bytes. Verifies
    /// that the bytes are valid according to the Multihash format.
    pub fn from_base58_str(s: &str) -> Result<Multihash, String> {
        let bytes = try!(s.from_base58()
                          .map_err(|e| format!("Error parsing base58 string: {}", e)));

        let hash_code = bytes[0];

        if !is_valid_code(hash_code) {
            return Err(format!("Invalid hash function code: {}", hash_code));
        }

        if !is_app_code(hash_code) {
            let hash_type = HashType::from_code(hash_code).unwrap();
            let expected_digest_len = hash_type.digest_len();
            if expected_digest_len != bytes[1] {
                return Err(format!("For hash function {}, expected digest length {}, but \
                                    found digest length {}", hash_type.to_str(),
                                    expected_digest_len, bytes[1]));
            }
        }

        if (bytes.len() - 2) as u8 != bytes[1] {
            return Err(format!("Hash digest is {} bytes, which does not match the stated \
                                digest length {}", bytes.len() - 2, bytes[1]));
        }

        Ok(Multihash::from_vec(bytes))
    }

    /// Create a Multihash directly from a vector of bytes. Does not verify that the
    /// bytes are a valid Multihash.
    pub fn from_vec(vec: Vec<u8>) -> Multihash {
        Multihash { bytes: vec }
    }

    pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] }

    pub fn into_bytes(self) -> Vec<u8> { self.bytes }

    /// Construct a Multihash out of the hash digest and hash function code
    pub fn encode<'a>(digest: &'a [u8], hash_code: u8) -> Result<Multihash, String> {
        let size = digest.len();
        if size > 127 {
            return Err("Digest length > 127 is currently not supported.".to_string())
        }

        if !is_valid_code(hash_code) {
            return Err(format!("Invalid hash function code: {}", hash_code));
        }

        let mut v = Vec::with_capacity(size + 2);
        v.push(hash_code);
        v.push(size as u8);
        v.extend(digest);
        Ok(Multihash::from_vec(v))
    }

    // TODO: evaluate whether this function makes sense
    /*
    pub fn decode<'a>(&'a self) -> Result<DecodedMultiHash<'a>, DecodeError> {
        let mhlen = self.bytes.len();
        if mhlen < 3 {
            return Err(DecodeError::TooShort);
        } else if mhlen > 129 {
            return Err(DecodeError::TooLong);
        } else {
            let digest_len = (mhlen - 2) as u8;
            if digest_len != self.bytes[1] {
                return Err(DecodeError::InvalidDigestLength(self.bytes[1], digest_len));
            }
        }

        let fn_code = match HashType::from_code(self.bytes[0]) {
            None => return Err(DecodeError::UnknownCode(self.bytes[0])),
            Some(code) => code,
        };

        let decoded = DecodedMultiHash {
            code: fn_code,
            name: fn_code.to_str(),
            length: self.bytes[1],
            digest: &self.bytes[2..],
        };
        Ok(decoded)

    }
    */

    pub fn to_base58_string(&self) -> String {
        self.bytes.to_base58()
    }
}

impl rustc_serialize::Encodable for Multihash {
    fn encode<S>(&self, s: &mut S) -> Result<(), S::Error> where
        S: rustc_serialize::Encoder
    {
        self.to_base58_string().encode(s)
    }
}

impl rustc_serialize::Decodable for Multihash {
    fn decode<D>(d: &mut D) -> Result<Multihash, D::Error> where
        D: rustc_serialize::Decoder
    {
        let s = try!(d.read_str());
        Multihash::from_base58_str(&s).map_err(|e| d.error(&e))
    }
}

impl rustc_serialize::hex::ToHex for Multihash {
    fn to_hex(&self) -> String {
        self.bytes.to_hex()
    }
}

fn is_valid_code(code: u8) -> bool {
    is_app_code(code) || HashType::from_code(code).is_some()
}

fn is_app_code(code: u8) -> bool {
    code <= 0x0f
}

/*
pub struct DecodedMultiHash<'a> {
    code: HashType,
    name: &'static str,
    length: u8,
    digest: &'a [u8],
}

#[derive(Debug)]
pub enum DecodeError {
    UnknownCode(u8),
    TooShort,
    TooLong,
    InvalidDigestLength(u8, u8), // (stated, actual)
}
*/

#[cfg(test)]
mod tests {
    use super::{multihash, Multihash, HashType};
    use rustc_serialize::hex::FromHex;
    use rust_base58::ToBase58;

    struct TestCase {
        hexstr: &'static str,
        hash_type: HashType,
    }

    impl TestCase {
        fn new(s: &'static str, ty: HashType) -> TestCase {
            TestCase { hexstr: s, hash_type: ty }
        }
    }

    static SHA1_STR: &'static str = "a228821137dacdbcd3ba5fa264f918fd
                                     a6223f7b";

    static SHA256_STR: &'static str = "95071c8e1ad3c7a016b30fd25853c1d9\
                                       e346ee7ee4afc977f554b139f71f4f30";

    static SHA512_STR: &'static str = "3912d4c1777934091ed95a15278b351e\
                                       00efa51f524af9af3320f0f6a227d551\
                                       76b1399684d15a05f03d1e519a9a9aa5\
                                       2a812a6d9bc63e5b485d6fd7ebf72114";

    #[test]
    fn test_multihash() {
        let abc = b"ABC";
        let sha1_hex = "3c01bdbb26f358bab27f267924aa2c9a03fcfdb8";
        let sha256_hex = "b5d4045c3f466fa91fe2cc6abe79232a1a57cdf104f7a26e716e0a1e2789df78";
        let sha512_hex = "397118fdac8d83ad98813c50759c85b8c47565d8268bf10da483153b747a7474\
                          3a58a90e85aa9f705ce6984ffc128db567489817e4092d050d8a1cc596ddc119";

        let sha1 = multihash(abc, HashType::SHA1);
        let mut sha1_bytes = hexstr_to_vec(sha1_hex);
        let mut expected_bytes = vec![0x11, 20];
        expected_bytes.append(&mut sha1_bytes);
        assert_eq!(sha1.as_bytes(), &expected_bytes[..]);

        let sha256 = multihash(abc, HashType::SHA2_256);
        let mut sha256_bytes = hexstr_to_vec(sha256_hex);
        let mut expected_bytes = vec![0x12, 32];
        expected_bytes.append(&mut sha256_bytes);
        assert_eq!(sha256.as_bytes(), &expected_bytes[..]);

        let sha512 = multihash(abc, HashType::SHA2_512);
        let mut sha512_bytes = hexstr_to_vec(sha512_hex);
        let mut expected_bytes = vec![0x13, 64];
        expected_bytes.append(&mut sha512_bytes);
        assert_eq!(sha512.as_bytes(), &expected_bytes[..]);
    }

    fn hexstr_to_vec(hexstr: &'static str) -> Vec<u8> {
        match hexstr.from_hex() {
            Err(e) => panic!("from_hex() failed with error: {:?}", e),
            Ok(vec) => vec,
        }
    }

    #[test]
    fn test_encode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);

            let mut expected = Vec::new();
            expected.push(case.hash_type.code());
            expected.push(v.len() as u8);
            expected.extend(&v[..]);

            let mh = Multihash::encode(&v[..], case.hash_type.code()).unwrap();
            assert_eq!(&expected[..], mh.as_bytes());
        }
    }

    /*
    #[test]
    fn test_decode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);
            let digest_length = v.len() as u8;
            let mh = Multihash::encode(&v[..], case.hash_type).unwrap();
            let hash_name = case.hash_type.to_str();

            match mh.decode() {
                Err(e) => panic!("Error decoding: {:?}", e),
                Ok(decoded) => {
                    assert_eq!(decoded.code, case.hash_type);
                    assert_eq!(decoded.name, hash_name);
                    assert_eq!(decoded.length, digest_length);
                    assert_eq!(decoded.digest, &v[..]);
                },
            }
        }
    }
    */

    #[test]
    fn test_from_base58_str() {
        assert!(Multihash::from_base58_str("Invalid base58!!!").is_err());

        // digest length of SHA1 is 20, not 5
        let x = &[0x11, 5, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        // mismatch between stated digest length and actual digest length
        let x = &[0x11, 20, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        let x = &[0x11, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_ok());

        let x = "QmR6XorNYAywK4q1dRiRN1gmvfLcx3ccBv68iGtAqon9tt";
        assert!(Multihash::from_base58_str(x).is_ok());
    }
}
<commit_msg>impl Display for Multihash<commit_after>extern crate openssl;
extern crate rust_base58;
extern crate rustc_serialize;

use self::HashType::*;

use openssl::crypto::hash as openssl_hash;
use rust_base58::{FromBase58, ToBase58};
use std::fmt;

#[derive(Copy, Clone)]
pub enum HashType {
    SHA1 = 0x11,
    SHA2_256 = 0x12,
    SHA2_512 = 0x13,
    SHA3 = 0x14,
    BLAKE2B = 0x40,
    BLAKE2S = 0x41,
}

impl HashType {
    pub fn from_code(code: u8) -> Option<HashType> {
        match code {
            0x11 => Some(SHA1),
            0x12 => Some(SHA2_256),
            0x13 => Some(SHA2_512),
            0x14 => Some(SHA3),
            0x40 => Some(BLAKE2B),
            0x41 => Some(BLAKE2S),
            _ => None,
        }
    }

    fn digest_len(&self) -> u8 {
        match *self {
            SHA1     => 20,
            SHA2_256 => 32,
            SHA2_512 => 64,
            SHA3     => 64,
            BLAKE2B  => 64,
            BLAKE2S  => 32,
        }
    }

    fn code(&self) -> u8 {
        *self as u8
    }

    fn to_str(&self) -> &'static str {
        match *self {
            SHA1     => "sha1",
            SHA2_256 => "sha2-256",
            SHA2_512 => "sha2-512",
            SHA3     => "sha3",
            BLAKE2B  => "blake2b",
            BLAKE2S  => "blake2s",
        }
    }
}

/// Hashes the `data` with the function described by `hash_type` and returns the result
/// as a Multihash.
pub fn multihash<'a>(data: &'a[u8], hash_type: HashType) -> Multihash {
    let openssl_type: openssl_hash::Type = match hash_type {
        SHA1     => openssl_hash::Type::SHA1,
        SHA2_256 => openssl_hash::Type::SHA256,
        SHA2_512 => openssl_hash::Type::SHA512,
        _ => panic!("That hash function is not yet implemented. Sorry"),
    };

    let hashed = openssl_hash::hash(openssl_type, data);

    Multihash::encode(&hashed[..], hash_type.code()).unwrap()
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Multihash {
    bytes: Vec<u8>
}

impl Multihash {
    /// Construct a multihash from a base58 string by parsing it into bytes. Verifies
    /// that the bytes are valid according to the Multihash format.
    pub fn from_base58_str(s: &str) -> Result<Multihash, String> {
        let bytes = try!(s.from_base58()
                          .map_err(|e| format!("Error parsing base58 string: {}", e)));

        let hash_code = bytes[0];

        if !is_valid_code(hash_code) {
            return Err(format!("Invalid hash function code: {}", hash_code));
        }

        if !is_app_code(hash_code) {
            let hash_type = HashType::from_code(hash_code).unwrap();
            let expected_digest_len = hash_type.digest_len();
            if expected_digest_len != bytes[1] {
                return Err(format!("For hash function {}, expected digest length {}, but \
                                    found digest length {}", hash_type.to_str(),
                                    expected_digest_len, bytes[1]));
            }
        }

        if (bytes.len() - 2) as u8 != bytes[1] {
            return Err(format!("Hash digest is {} bytes, which does not match the stated \
                                digest length {}", bytes.len() - 2, bytes[1]));
        }

        Ok(Multihash::from_vec(bytes))
    }

    /// Create a Multihash directly from a vector of bytes. Does not verify that the
    /// bytes are a valid Multihash.
    pub fn from_vec(vec: Vec<u8>) -> Multihash {
        Multihash { bytes: vec }
    }

    pub fn as_bytes(&self) -> &[u8] { &self.bytes[..] }

    pub fn into_bytes(self) -> Vec<u8> { self.bytes }

    /// Construct a Multihash out of the hash digest and hash function code
    pub fn encode<'a>(digest: &'a [u8], hash_code: u8) -> Result<Multihash, String> {
        let size = digest.len();
        if size > 127 {
            return Err("Digest length > 127 is currently not supported.".to_string())
        }

        if !is_valid_code(hash_code) {
            return Err(format!("Invalid hash function code: {}", hash_code));
        }

        let mut v = Vec::with_capacity(size + 2);
        v.push(hash_code);
        v.push(size as u8);
        v.extend(digest);
        Ok(Multihash::from_vec(v))
    }

    // TODO: evaluate whether this function makes sense
    /*
    pub fn decode<'a>(&'a self) -> Result<DecodedMultiHash<'a>, DecodeError> {
        let mhlen = self.bytes.len();
        if mhlen < 3 {
            return Err(DecodeError::TooShort);
        } else if mhlen > 129 {
            return Err(DecodeError::TooLong);
        } else {
            let digest_len = (mhlen - 2) as u8;
            if digest_len != self.bytes[1] {
                return Err(DecodeError::InvalidDigestLength(self.bytes[1], digest_len));
            }
        }

        let fn_code = match HashType::from_code(self.bytes[0]) {
            None => return Err(DecodeError::UnknownCode(self.bytes[0])),
            Some(code) => code,
        };

        let decoded = DecodedMultiHash {
            code: fn_code,
            name: fn_code.to_str(),
            length: self.bytes[1],
            digest: &self.bytes[2..],
        };
        Ok(decoded)

    }
    */

    pub fn to_base58_string(&self) -> String {
        self.bytes.to_base58()
    }
}

impl rustc_serialize::Encodable for Multihash {
    fn encode<S>(&self, s: &mut S) -> Result<(), S::Error> where
        S: rustc_serialize::Encoder
    {
        self.to_base58_string().encode(s)
    }
}

impl rustc_serialize::Decodable for Multihash {
    fn decode<D>(d: &mut D) -> Result<Multihash, D::Error> where
        D: rustc_serialize::Decoder
    {
        let s = try!(d.read_str());
        Multihash::from_base58_str(&s).map_err(|e| d.error(&e))
    }
}

impl rustc_serialize::hex::ToHex for Multihash {
    fn to_hex(&self) -> String {
        self.bytes.to_hex()
    }
}

impl fmt::Display for Multihash {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        f.write_str(&self.to_base58_string())
    }
}

fn is_valid_code(code: u8) -> bool {
    is_app_code(code) || HashType::from_code(code).is_some()
}

fn is_app_code(code: u8) -> bool {
    code <= 0x0f
}

/*
pub struct DecodedMultiHash<'a> {
    code: HashType,
    name: &'static str,
    length: u8,
    digest: &'a [u8],
}

#[derive(Debug)]
pub enum DecodeError {
    UnknownCode(u8),
    TooShort,
    TooLong,
    InvalidDigestLength(u8, u8), // (stated, actual)
}
*/

#[cfg(test)]
mod tests {
    use super::{multihash, Multihash, HashType};
    use rustc_serialize::hex::FromHex;
    use rust_base58::ToBase58;

    struct TestCase {
        hexstr: &'static str,
        hash_type: HashType,
    }

    impl TestCase {
        fn new(s: &'static str, ty: HashType) -> TestCase {
            TestCase { hexstr: s, hash_type: ty }
        }
    }

    static SHA1_STR: &'static str = "a228821137dacdbcd3ba5fa264f918fd
                                     a6223f7b";

    static SHA256_STR: &'static str = "95071c8e1ad3c7a016b30fd25853c1d9\
                                       e346ee7ee4afc977f554b139f71f4f30";

    static SHA512_STR: &'static str = "3912d4c1777934091ed95a15278b351e\
                                       00efa51f524af9af3320f0f6a227d551\
                                       76b1399684d15a05f03d1e519a9a9aa5\
                                       2a812a6d9bc63e5b485d6fd7ebf72114";

    #[test]
    fn test_multihash() {
        let abc = b"ABC";
        let sha1_hex = "3c01bdbb26f358bab27f267924aa2c9a03fcfdb8";
        let sha256_hex = "b5d4045c3f466fa91fe2cc6abe79232a1a57cdf104f7a26e716e0a1e2789df78";
        let sha512_hex = "397118fdac8d83ad98813c50759c85b8c47565d8268bf10da483153b747a7474\
                          3a58a90e85aa9f705ce6984ffc128db567489817e4092d050d8a1cc596ddc119";

        let sha1 = multihash(abc, HashType::SHA1);
        let mut sha1_bytes = hexstr_to_vec(sha1_hex);
        let mut expected_bytes = vec![0x11, 20];
        expected_bytes.append(&mut sha1_bytes);
        assert_eq!(sha1.as_bytes(), &expected_bytes[..]);

        let sha256 = multihash(abc, HashType::SHA2_256);
        let mut sha256_bytes = hexstr_to_vec(sha256_hex);
        let mut expected_bytes = vec![0x12, 32];
        expected_bytes.append(&mut sha256_bytes);
        assert_eq!(sha256.as_bytes(), &expected_bytes[..]);

        let sha512 = multihash(abc, HashType::SHA2_512);
        let mut sha512_bytes = hexstr_to_vec(sha512_hex);
        let mut expected_bytes = vec![0x13, 64];
        expected_bytes.append(&mut sha512_bytes);
        assert_eq!(sha512.as_bytes(), &expected_bytes[..]);
    }

    fn hexstr_to_vec(hexstr: &'static str) -> Vec<u8> {
        match hexstr.from_hex() {
            Err(e) => panic!("from_hex() failed with error: {:?}", e),
            Ok(vec) => vec,
        }
    }

    #[test]
    fn test_encode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);

            let mut expected = Vec::new();
            expected.push(case.hash_type.code());
            expected.push(v.len() as u8);
            expected.extend(&v[..]);

            let mh = Multihash::encode(&v[..], case.hash_type.code()).unwrap();
            assert_eq!(&expected[..], mh.as_bytes());
        }
    }

    /*
    #[test]
    fn test_decode() {
        let mut cases = Vec::new();

        cases.push(TestCase::new(SHA1_STR, HashType::SHA1));
        cases.push(TestCase::new(SHA256_STR, HashType::SHA2_256));
        cases.push(TestCase::new(SHA512_STR, HashType::SHA2_512));

        for case in cases {
            let v = hexstr_to_vec(case.hexstr);
            let digest_length = v.len() as u8;
            let mh = Multihash::encode(&v[..], case.hash_type).unwrap();
            let hash_name = case.hash_type.to_str();

            match mh.decode() {
                Err(e) => panic!("Error decoding: {:?}", e),
                Ok(decoded) => {
                    assert_eq!(decoded.code, case.hash_type);
                    assert_eq!(decoded.name, hash_name);
                    assert_eq!(decoded.length, digest_length);
                    assert_eq!(decoded.digest, &v[..]);
                },
            }
        }
    }
    */

    #[test]
    fn test_from_base58_str() {
        assert!(Multihash::from_base58_str("Invalid base58!!!").is_err());

        // digest length of SHA1 is 20, not 5
        let x = &[0x11, 5, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        // mismatch between stated digest length and actual digest length
        let x = &[0x11, 20, 1, 2, 3, 4, 5];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_err());

        let x = &[0x11, 20, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
                  0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
        assert!(Multihash::from_base58_str(&x.to_base58()).is_ok());

        let x = "QmR6XorNYAywK4q1dRiRN1gmvfLcx3ccBv68iGtAqon9tt";
        assert!(Multihash::from_base58_str(x).is_ok());
    }
}
<|endoftext|>


<commit_before>extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_optional_text(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_optional_text(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name.to_string(), None, vec![]);
    elem.text(chars.to_string());
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss".to_string(), None, vec![("version".to_string(), None, "2.0".to_string())]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        if let Err(..) = reader.read_to_string(&mut rss_string) {
            return Err("Error reading string from reader");
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Some(Ok(element)) = builder.handle_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    pub ttl: Option<String>,  // TODO: change this to Option<i32>?
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel".to_string(), None, vec![]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_optional_text("language", &self.language);
        channel.tag_with_optional_text("copyright", &self.copyright);
        channel.tag_with_optional_text("managingEditor", &self.managing_editor);
        channel.tag_with_optional_text("webMaster", &self.web_master);
        channel.tag_with_optional_text("pubDate", &self.pub_date);
        channel.tag_with_optional_text("lastBuildDate", &self.last_build_date);
        channel.tag_with_optional_text("generator", &self.generator);
        channel.tag_with_optional_text("docs", &self.docs);
        channel.tag_with_optional_text("ttl", &self.ttl);
        channel.tag_with_optional_text("image", &self.image);
        channel.tag_with_optional_text("rating", &self.rating);
        channel.tag_with_optional_text("skipHours", &self.skip_hours);
        channel.tag_with_optional_text("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            categories: categories,
            ..Default::default()  // TODO
        })
    }
}

/// Item
///
/// [RSS 2.0 Specification § Item]
/// (http://cyber.law.harvard.edu/rss/rss.html#hrelementsOfLtitemgt)
#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    pub author: Option<String>,
    pub categories: Vec<Category>,
    pub comments: Option<String>,
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item".to_string(), None, vec![]);

        item.tag_with_optional_text("title", &self.title);
        item.tag_with_optional_text("link", &self.link);
        item.tag_with_optional_text("description", &self.description);
        item.tag_with_optional_text("author", &self.author);
        item.tag_with_optional_text("comments", &self.comments);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(Element::content_str);
        let link = element.get_child("link", None).map(Element::content_str);
        let description = element.get_child("description", None).map(Element::content_str);
        let author = element.get_child("author", None).map(Element::content_str);
        let comments = element.get_child("comments", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
            author: author,
            comments: comments,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category".to_string(), None, vec![("domain".to_string(), None, d.clone())]),
            None => Element::new("category".to_string(), None, vec![]),
        };
        category.text(self.value.clone());
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<commit_msg>Read Channel properties from xml<commit_after>extern crate xml;

use std::ascii::AsciiExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_optional_text(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_optional_text(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name.to_string(), None, vec![]);
    elem.text(chars.to_string());
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss".to_string(), None, vec![("version".to_string(), None, "2.0".to_string())]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        if let Err(..) = reader.read_to_string(&mut rss_string) {
            return Err("Error reading string from reader");
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Some(Ok(element)) = builder.handle_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    pub ttl: Option<String>,  // TODO: change this to Option<i32>?
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel".to_string(), None, vec![]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_optional_text("language", &self.language);
        channel.tag_with_optional_text("copyright", &self.copyright);
        channel.tag_with_optional_text("managingEditor", &self.managing_editor);
        channel.tag_with_optional_text("webMaster", &self.web_master);
        channel.tag_with_optional_text("pubDate", &self.pub_date);
        channel.tag_with_optional_text("lastBuildDate", &self.last_build_date);
        channel.tag_with_optional_text("generator", &self.generator);
        channel.tag_with_optional_text("docs", &self.docs);
        channel.tag_with_optional_text("ttl", &self.ttl);
        channel.tag_with_optional_text("image", &self.image);
        channel.tag_with_optional_text("rating", &self.rating);
        channel.tag_with_optional_text("skipHours", &self.skip_hours);
        channel.tag_with_optional_text("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let language = element.get_child("language", None).map(Element::content_str);
        let copyright = element.get_child("copyright", None).map(Element::content_str);
        let managing_editor = element.get_child("managing_editor", None).map(Element::content_str);
        let web_master = element.get_child("managing_editor", None).map(Element::content_str);
        let pub_date = element.get_child("pub_date", None).map(Element::content_str);
        let last_build_date = element.get_child("last_build_date", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let generator = element.get_child("generator", None).map(Element::content_str);
        let docs = element.get_child("docs", None).map(Element::content_str);
        let ttl = element.get_child("ttl", None).map(Element::content_str);
        let image = element.get_child("image", None).map(Element::content_str);
        let rating = element.get_child("rating", None).map(Element::content_str);
        let skip_hours = element.get_child("skip_hours", None).map(Element::content_str);
        let skip_days = element.get_child("skip_days", None).map(Element::content_str);

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            language: language,
            copyright: copyright,
            managing_editor: managing_editor,
            web_master: web_master,
            pub_date: pub_date,
            last_build_date: last_build_date,
            categories: categories,
            generator: generator,
            docs: docs,
            ttl: ttl,
            image: image,
            rating: rating,
            skip_hours: skip_hours,
            skip_days: skip_days,
        })
    }
}

/// Item
///
/// [RSS 2.0 Specification § Item]
/// (http://cyber.law.harvard.edu/rss/rss.html#hrelementsOfLtitemgt)
#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    pub author: Option<String>,
    pub categories: Vec<Category>,
    pub comments: Option<String>,
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item".to_string(), None, vec![]);

        item.tag_with_optional_text("title", &self.title);
        item.tag_with_optional_text("link", &self.link);
        item.tag_with_optional_text("description", &self.description);
        item.tag_with_optional_text("author", &self.author);
        item.tag_with_optional_text("comments", &self.comments);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(Element::content_str);
        let link = element.get_child("link", None).map(Element::content_str);
        let description = element.get_child("description", None).map(Element::content_str);
        let author = element.get_child("author", None).map(Element::content_str);
        let comments = element.get_child("comments", None).map(Element::content_str);

        let categories = element.get_children("category", None)
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
            author: author,
            comments: comments,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category".to_string(), None, vec![("domain".to_string(), None, d.clone())]),
            None => Element::new("category".to_string(), None, vec![]),
        };
        category.text(self.value.clone());
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<|endoftext|>